Author Topic: ASM Command of the Week  (Read 20132 times)

0 Members and 1 Guest are viewing this topic.

Offline ralphdspam

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 841
  • Rating: +38/-1
  • My name is actually Matt.
    • View Profile
ASM Command of the Week
« on: December 24, 2011, 12:27:13 am »
The ASM board hasn't been as active as it should be, so I'm starting a weekly discussion called "ASM Command of the Week."  Basically, we will discuss hacks, routines, optimizations, or alternatives to the command.  

It's basically going to be like these topics, except this one is going to be weekly.
DJNZ:
http://ourl.ca/13569
RLD and RRD:
http://ourl.ca/12758
IX and IY:
http://ourl.ca/12633

We'll start with a really easy one.  This week's command is:
XOR
« Last Edit: December 24, 2011, 12:27:33 am by ralphdspam »
ld a, 0
ld a, a

Offline calc84maniac

  • eZ80 Guru
  • Coder Of Tomorrow
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2912
  • Rating: +471/-17
    • View Profile
    • TI-Boy CE
Re: ASM Command of the Week
« Reply #1 on: December 24, 2011, 12:35:24 am »
Possibly one of the best uses of XOR is in combination with AND, to act as a bitwise multiplexer.

For example, this uses the bits of C to select bits from A and B: if the bit in C is 1, that bit is selected from A, and if the bit in C is 0, that bit is selected from B.
xor b
and c
xor b
"Most people ask, 'What does a thing do?' Hackers ask, 'What can I make it do?'" - Pablos Holman

Offline Hot_Dog

  • CoT Emeritus
  • LV12 Extreme Poster (Next: 5000)
  • *
  • Posts: 3006
  • Rating: +445/-10
    • View Profile
Re: ASM Command of the Week
« Reply #2 on: December 24, 2011, 12:45:30 am »
xor a is probably the most common use, faster than "ld a, 0"

xor is also commonly used to "flip" bits in register A.

Offline ZippyDee

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 729
  • Rating: +83/-8
  • Why not zoidberg?
    • View Profile
Re: ASM Command of the Week
« Reply #3 on: December 24, 2011, 01:13:39 am »
You can also use xor to test whether two bits within a byte are the same.

and MASK
jr z, bitsAreTheSame
xor MASK
jr z, bitsAreTheSame
;... otherwise, bits are different

where MASK is a mask of the two bits to compare


With this concept, you can use it to swap two bits within a byte:
ld a, (addr)
and MASK
jr z, doneSwapping
xor MASK
jr z, doneSwapping
ld a, (addr)
xor MASK
ld (addr), a
« Last Edit: December 24, 2011, 01:20:59 am by ZippyDee »
There's something about Tuesday...


Pushpins 'n' stuff...


Offline calc84maniac

  • eZ80 Guru
  • Coder Of Tomorrow
  • LV11 Super Veteran (Next: 3000)
  • ***********
  • Posts: 2912
  • Rating: +471/-17
    • View Profile
    • TI-Boy CE
Re: ASM Command of the Week
« Reply #4 on: December 24, 2011, 01:21:19 am »
and MASK
jp pe,bitsAreTheSame

* calc84maniac runs
"Most people ask, 'What does a thing do?' Hackers ask, 'What can I make it do?'" - Pablos Holman

Offline ZippyDee

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 729
  • Rating: +83/-8
  • Why not zoidberg?
    • View Profile
Re: ASM Command of the Week
« Reply #5 on: December 24, 2011, 01:22:00 am »
Explain how that works please...>.< I've never understood how to use parity.

Edit: After thinking about it that makes sense, but that only allows you to test two bits, whereas my method could be used to test any number (I think). Of course the swapping would only work for two bits at a time...
« Last Edit: December 24, 2011, 01:26:00 am by ZippyDee »
There's something about Tuesday...


Pushpins 'n' stuff...


Offline DrDnar

  • LV7 Elite (Next: 700)
  • *******
  • Posts: 546
  • Rating: +97/-1
    • View Profile
Re: ASM Command of the Week
« Reply #6 on: December 24, 2011, 01:28:37 am »
Code: [Select]
AND maskmasks out all bits except the two in question. If the remaining two bits are the same, either there will be 8 zeros and no ones, or 2 ones and 6 zeros. Thus, the parity will be even. However, if the remaining two bits are different, 1 will be zero, and 1 will be one. Thus, the parity will be odd.
"No tools will make a man a skilled workman, or master of defense, nor be of any use to him who has not learned how to handle them, and has never bestowed any attention upon them. . . . Yes, [] the tools which would teach men their own use would be beyond price."—Plato's The Republic, circa 380 BC

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: ASM Command of the Week
« Reply #7 on: December 26, 2011, 01:59:03 pm »
Possibly one of the best uses of XOR is in combination with AND, to act as a bitwise multiplexer.

For example, this uses the bits of C to select bits from A and B: if the bit in C is 1, that bit is selected from A, and if the bit in C is 0, that bit is selected from B.
xor b
and c
xor b

What could you/would you want to use this for?

I think this is an interesting topic and would like to see it continue :)

Like Hot_dog, i often use xor to flip bytes. I think i'm pretty unimaginative though when i code.

Offline ralphdspam

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 841
  • Rating: +38/-1
  • My name is actually Matt.
    • View Profile
Re: ASM Command of the Week
« Reply #8 on: December 29, 2011, 02:57:40 am »
Possibly one of the best uses of XOR is in combination with AND, to act as a bitwise multiplexer.

For example, this uses the bits of C to select bits from A and B: if the bit in C is 1, that bit is selected from A, and if the bit in C is 0, that bit is selected from B.
xor b
and c
xor b

What could you/would you want to use this for?
You can use it for a lot of graphics stuff.  ie: masking sprites, grayscale, etc.
I also use it for preserving certain flags in a register while changing others.
ld a, 0
ld a, a

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: ASM Command of the Week
« Reply #9 on: December 30, 2011, 01:09:06 pm »
Ok, i'm not really too interested in grayscale, but i'd like to see how masking sprites might work out.

Here's some basic code to draw a masked byte to the gbuf:
Code: [Select]
;ix=masked byte to draw
;ix+1=byte mask
;hl=location in gbuf to draw to
 ld a,(ix+1)  ;load mask into a
 and (hl)   ;and the mask onto the byte in gbuf
 or (ix)    ;draw the byte
 ld (hl),a  ;update gbuf
So that would become:
Code: [Select]
ld a,(ix)
 xor (hl)
 and (ix+1)
 xor (hl)
 ld (hl),a
Which is an extra byte larger. I've always drawn my masks like this:
sprite:
%00011000
%00111100
%01111110
%11111111

mask:
%11100111
%11000011
%10000001
%00000000
...a 1 being a byte to preserve in the gbuf (whereas i suppose with the xor method it'd be inverted).

If you want, i've got some code from a masked sprite routine i wrote a while back for an rpg i was working on that we could try to optimize :D I don't like how i went about it, first rotating/loading the mask onto the gbuf and updating the gbuf, then rotating/loading the sprite onto the gbuf (drawing twice to the gbuf).
Code: [Select]
drawPlayerLoop:
   push bc
drawPlayerRow
   ld d,(ix+32)     ;sprite mask
   ld e,(ix+33)
   ld a,$ff         ;a 1 means the gbuf bit will be preserved
   dec b \ inc b \ jr z,skipMaskClip    ;if b=0, no need to rotate
   scf \ rr d \ rr e \ rra \ djnz $-6   ;rotate mask b bits
skipMaskClip:
   and (hl)         ;a = mask to the furthest right
   ld (hl),a        ;store masked gbuf
   dec hl           ;next byte...
   ld a,(hl)
   and e
   ld (hl),a
   dec hl           ;last byte
   ld a,(hl)
   and d
   ld (hl),a
   pop bc           ;recall b=x offset, how many bits to rotate
   inc hl           ;return hl to starting gbuf position
   inc hl
   push bc          ;store bc again
   ld d,(ix)        ;sprite
   ld e,(ix+1)
   xor a            ;empty a to receive flowover from shifting
   cp b
   jp z,skipSpriteClip
   srl d \ rr e \ rra \ djnz $-5   ;rotate sprite
skipSpriteClip:
   or (hl)          ;load sprite into masked gbuf
   ld (hl),a        ;update gbuf
   dec hl           ;next byte, etc.
   ld a,(hl)
   or e
   ld (hl),a
   dec hl
   ld a,(hl)
   or d
   ld (hl),a
   inc ix           ;next sprite row
   inc ix
   ld de,14         ;jump to next row in gbuf, +2 (draw rightmost byte first)
   add hl,de
   pop bc
   dec c
   jp nz, drawPlayerLoop

Offline TIfanx1999

  • ಠ_ಠ ( ͡° ͜ʖ ͡°)
  • CoT Emeritus
  • LV13 Extreme Addict (Next: 9001)
  • *
  • Posts: 6173
  • Rating: +191/-9
    • View Profile
Re: ASM Command of the Week
« Reply #10 on: January 02, 2012, 10:22:25 am »
By the way, are you still working on that RPG any? I always thought it had a really nice look to it. =)
« Last Edit: January 02, 2012, 10:22:45 am by Art_of_camelot »

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: ASM Command of the Week
« Reply #11 on: January 03, 2012, 07:12:20 pm »
Well, my laptop busted (or rather, i busted my laptop) but i had made a fairely recent backup of it (the code on yaronet). Right now i'm a bit spread out but especially once i get Monopoly taken care of (a project that's been biting at my feet for maybe 8 years now) it's next on my hitlist. Actually, a lot of the work i've done with the Monopoly text/menu engine will probably be carried over into the RPG. One of the big things i need to do now is work on the story a bit. Thanks, btw :)

Does anyone have any suggestions for the next "Command of the Week"?

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: ASM Command of the Week
« Reply #12 on: January 08, 2012, 11:36:00 am »
Okay, time for a new command, ay? Well here goes:
CPIR
CPIR can be an extremely useful and powerful command, especially if you are doing a search.
What it does:
It performs cp (hl) then it decrements BC and increments HL. If the byte was a match, the loop stops and PE is the flag state of the parity/overflow flag and the other compare flags are affected normally. If BC reaches 0, the parity flag is PE.

As an example, if you want to find and jump to a certain line in an executing program, you can do something like this:
Code: [Select]
;Inputs:
;     DE is the line to jump to
;     (965Bh) points to the start of the program
;     (965Fh) points to the end of the program
;Notes:
;     The two addresses above are set accordingly while a BASIC program is running
     push de
     ld de,(965Bh)     ;This is the start of the currently running program
     ld hl,(965Fh)      ;This is the end of the currently running program
     or a
     sbc hl,de           ;HL is now the size of the program
     ex de,hl
     ld b,d
     ld c,e
     pop de
     dec hl
;HL points to the start of the program
;DE is the line to jump to
;BC are the size of the program
;A is the newline token
SearchLoop:
     dec de
     ld a,d \ or e
     jr z,StoLine
     ld a,3Fh
     cpir
     ret nz                  ;this means BC hit 0. In other words, the line does not exist.
;the byte is 3Fh, but we need to make sure that it is not part of a two-byte token
     dec hl \ dec hl
     ld a,(hl)
     inc hl \ inc hl
     cp 7Eh \ jr z,SearchLoop+5
     cp $AA \ jr z,SearchLoop+5
     cp $BB \ jr z,SearchLoop+5
     cp $EF \ jr z,SearchLoop+5
     cp 5Fh \  jr z,SearchLoop
     sub 5Ch \ jr c,SearchLoop
     sub 7 \ jr c,SearchLoop+5
     jr SearchLoop
StoLine:
     dec hl
     ld (965Dh),hl                  ;this loads the address to the BASIC program counter
     ret
It can probably be optimised a little, but I am sure you get the idea :)

Offline ralphdspam

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 841
  • Rating: +38/-1
  • My name is actually Matt.
    • View Profile
Re: ASM Command of the Week
« Reply #13 on: January 13, 2012, 07:55:38 pm »
Nice code, but I can't think of any other uses of the command.  Can you think of any hacky type usage?
ld a, 0
ld a, a

Offline Xeda112358

  • they/them
  • Moderator
  • LV12 Extreme Poster (Next: 5000)
  • ************
  • Posts: 4704
  • Rating: +719/-6
  • Calc-u-lator, do doo doo do do do.
    • View Profile
Re: ASM Command of the Week
« Reply #14 on: January 13, 2012, 08:10:26 pm »
You can use cpir to determine the length of a string or name. For example, if you want the length of a program name in OP1 with a maximum limit of 9:
Code: [Select]
     ld bc,9
     ld hl,OP1
     xor a
     cpir
     jr nz,$+3                ;This means the string ended at maximal length
       ccf
     ld a,9 \ sbc a,c
     ld c,a
In fact, you can turn that into a general code where you can find the length of a zero-terminated string pointed to by HL with a maximum size:
Code: [Select]
     push bc
     xor a
     cpir
     pop hl
     jr nz,$+3                ;This means the string ended at maximal length
       ccf
     sbc hl,bc           ;the c flag was reset by 'xor a', so hl is the length
     ret

There are other ways that I have used it, too, I just need a moment to think of some more uses XD I was actually hoping some other coders had neat hacks.

EDIT: Another use for this is when you want to display a string, but only up to x digits.