Jump to content


Photo
- - - - -

The AND instruction


  • Please log in to reply
39 replies to this topic

#31 jetsetdanny

jetsetdanny

    Advanced Member

  • Contributor
  • 1,949 posts

Posted 03 March 2017 - 07:50 PM

The beauty of the code?  ;)



#32 IRF

IRF

    Advanced Member

  • Contributor
  • 3,932 posts

Posted 08 April 2017 - 12:29 AM

I have to say I'm quite impressed with John Elliott's cunning use of an XOR followed by an AND command, in the 'Move the Horizontal Guardians' code in JSW64, in order to determine when to reverse the guardians' direction of movement.

 

The traditional JSW code uses an AND gate - to pick the lowest five bits of Byte 2 of the guardian definition, and then compares it against the minimum or maximum x-coordinate (Byte 6 or Byte 7 respectively) using a CP command.

 

However, that isn't possible in JSW64, because the highest three bits of Byte 7 are used as flags for Fast and Slow horizontal guardians.  So an XOR command, and then an AND gate, is used as an alternative way to compare selected bits (0-4) for comparison - after that pair of operations, the zero flag is set if (and only if) the values stored in the lowest five bits of the pair of bytes under consideration, exactly match.

 

This isn't really related to AND, OR or XOR, but it's another impressive little trick of John Elliott's that I thought was worth mentioning somewhere:

 

In the code that moves Skylabs in the JSW64 game engine, there's a cunning use of the CCF command (Complement the Carry Flag), as part of a code-efficient way of handling Skylabs that move upwards.

 

******

 

And on the subject of variations on classic Manic Miner 'specials' in JSW64, I haven't seen it explicitly pointed out anywhere in the manual or anywhere else, but it is perfectly possible to have an Angry Eugene that moves upwards until it stops (rather than downwards as in the original MM).



#33 jetsetdanny

jetsetdanny

    Advanced Member

  • Contributor
  • 1,949 posts

Posted 08 April 2017 - 11:34 AM

I've never seen it mentioned before, Ian, thanks for mentioning it!  :)

 

It would be a nice feature for a future game.

 

Would the reversal of Angry Eugene's direction be easy to apply also in the original MM?



#34 IRF

IRF

    Advanced Member

  • Contributor
  • 3,932 posts

Posted 08 April 2017 - 12:06 PM

I guess you could modify the code in the MM game engine.

First thoughts: swap around the DEC A and INC A at #8E07 and #8E12 respectively, and then modify the y-coordinate at which Eugene comes to a halt (#8E14).

I have a further suggestion for a modification to Eugene - in fact suggestions for all four 'special' MM guardians, in the JSW64 game engine - but they will have to wait for a future post, when I have the time.

Edited by IRF, 08 April 2017 - 01:51 PM.


#35 IRF

IRF

    Advanced Member

  • Contributor
  • 3,932 posts

Posted 06 June 2017 - 01:11 PM

I have to say I'm quite impressed with John Elliott's cunning use of an XOR followed by an AND command, in the 'Move the Horizontal Guardians' code in JSW64, in order to determine when to reverse the guardians' direction of movement.

 

The traditional JSW code uses an AND gate - to pick the lowest five bits of Byte 2 of the guardian definition, and then compares it against the minimum or maximum x-coordinate (Byte 6 or Byte 7 respectively) using a CP command.

 

However, that isn't possible in JSW64, because the highest three bits of Byte 7 are used as flags for Fast and Slow horizontal guardians.  So an XOR command, and then an AND gate, is used as an alternative way to compare selected bits (0-4) for comparison - after that pair of operations, the zero flag is set if (and only if) the values stored in the lowest five bits of the pair of bytes under consideration, exactly match.

 

EDIT: To clarify, load Guardian Definition byte 2 into A, XOR with Guardian Definition Byte 7, then AND #1F.  The Z flag will be set iff the x-coordinates match.

 

Geoff Mode's 'Move the guardians' routine actually takes the above approach further, in order to update the animation frame of a guardian, and the x-coordinate of horizontal/diagonal guardians.

 

In these circumstances, part of a guardian definition byte needs to be updated without altering the rest of the byte.  That's easy for a single flag - just toggle the relevant bit (e.g. Bit 7 of Byte 0 which specifies the direction - use XOR 80).

 

However, when a variable uses more than a single bit, it gets more complicated.  One example would be the two bits that determine a guardian's current frame of animation, which sits within the same definition byte (Byte 0) as the guardian type (lowest bits) as well as its direction flag.  Another example is a guardian's x-coordinate, which shares a definition byte (Byte 2) with the Base sprite.

 

The more familiar approach (to me at least) is to:

 

- load the byte that you're updating into the A register,

- do an AND for the bits you don't want to alter,

- save the output into another variable such as C,

- load the value you want for the bits you do want to update to A,

- do an OR C to merge the two elements,

- and then reload the output of that back into the definition byte.

 

Geoff used the sequence XOR - AND - XOR, which I think is more efficient(?), to update only the parts of a byte that need updating, and leave the rest of the byte unchanged.  The operand of both XOR commands being the guardian definition byte under consideration, whilst the operand of the AND command selects only the bits that you want to update.

 

e.g. to update a guardian's x-coordinate, he uses:

 

[A register holds the new value of the guardian's x-coordinate, in Bits 0-4; whilst Bits 5-7 are initially blank]

XOR (IX+$02)

AND #1F          for updating Bits 0-4

XOR (IX+$02)

[Then load A back into (IX+$02)]

 

The end result is that the x-coordinate of the guardian is updated, but its Base Sprite is unaltered.


Edited by IRF, 08 September 2017 - 04:32 PM.


#36 IRF

IRF

    Advanced Member

  • Contributor
  • 3,932 posts

Posted 21 June 2017 - 07:31 PM

I've just come to realise why a certain aspect of the MM/JSW code is the way it is.

 

The convention when copying data from one place to another is to use HL (or the indexed equivalents, IX or IY) to point at the data that you're copying, and DE as the addresses to which the values are copied.  (DE presumably signifying 'DEstination'?)

 

That's how LDIR loops operate, and also how the 'Print a message' and 'Print a single character' routines work.

 

But in the case of the 'Draw a sprite' routine at #9456, it is the other way round - DE points at the sprite graphic data, whilst the address to which to draw each byte, in turn, is defined via HL.

 

The reason for this is that the test for pixel collisions uses an AND (HL) instruction.  Furthermore, if no collision occurs, then the process of merging the sprite being drawn with the existing background graphic is done via an OR (HL) instruction.

 

There are no such equivalent Z80 commands involving the DE register-pair. i.e. there are no AND (DE) or OR (DE) commands in the Z80 instruction set.

 

So that is why the DE and HL register-pairs are used in the way that they are by the 'Draw a sprite' routine.


Edited by IRF, 08 September 2017 - 04:33 PM.


#37 jetsetdanny

jetsetdanny

    Advanced Member

  • Contributor
  • 1,949 posts

Posted 26 June 2017 - 08:11 AM

Thanks for the explanation, Ian!



#38 IRF

IRF

    Advanced Member

  • Contributor
  • 3,932 posts

Posted 02 August 2017 - 10:52 PM

John Elliott's cunning and efficient use of the Stack Pointer register, in his code which handles Triggers in JSW64, can only be described as audacious!  :o



#39 IRF

IRF

    Advanced Member

  • Contributor
  • 3,932 posts

Posted 08 September 2017 - 04:42 PM

I'm quite pleased with my successful implementation of the patch to 'Draw the Ropes', so that each rope's exact pixel-position can be specified on an individual basis.

 

Firstly, the use of the XOR command to separate out, in a byte-efficient manner, the two components of a rope's definition byte 2 (i.e. the starting column in Bits 0-4, and the pixel-position in Bits 5-7).

 

Secondly, the use of the SCF and RRA commands and a DJNZ loop, to convert Bits 5-7 in order to infill the appropriate pixel (set the correct single bit), in the graphic byte where the top segment of rope appears.

 

I'll type up a disassembly when I get a chance. :)



#40 IRF

IRF

    Advanced Member

  • Contributor
  • 3,932 posts

Posted 27 September 2017 - 12:03 PM

Looking at the 'Game Over' routine, I believe that the problem we once encountered in implementing certain INK colours for the Barrel (some choices for which were influenced by the chosen INK colour for the Foot/Willy) could be eliminated by simply replacing the value '#FA' at #8CB0 with '#F8'. i.e. the AND gate at #8CAF should only select the Barrel's PAPER/BRIGHT/FLASH bits (3-7), leaving the OR gate at #8CB1 to fully control the Barrel's INK bits (0-2).


Edited by IRF, 27 September 2017 - 12:05 PM.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users