Omnimaga

Calculator Community => TI Calculators => ASM => Topic started by: ralphdspam on December 24, 2011, 12:27:13 am

Title: ASM Command of the Week
Post by: ralphdspam 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
Title: Re: ASM Command of the Week
Post by: calc84maniac 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
Title: Re: ASM Command of the Week
Post by: Hot_Dog 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.
Title: Re: ASM Command of the Week
Post by: ZippyDee 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
Title: Re: ASM Command of the Week
Post by: calc84maniac on December 24, 2011, 01:21:19 am
and MASK
jp pe,bitsAreTheSame

/me runs
Title: Re: ASM Command of the Week
Post by: ZippyDee 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...
Title: Re: ASM Command of the Week
Post by: DrDnar 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.
Title: Re: ASM Command of the Week
Post by: chickendude 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.
Title: Re: ASM Command of the Week
Post by: ralphdspam 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.
Title: Re: ASM Command of the Week
Post by: chickendude 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
Title: Re: ASM Command of the Week
Post by: TIfanx1999 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. =)
Title: Re: ASM Command of the Week
Post by: chickendude 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"?
Title: Re: ASM Command of the Week
Post by: Xeda112358 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 :)
Title: Re: ASM Command of the Week
Post by: ralphdspam 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?
Title: Re: ASM Command of the Week
Post by: Xeda112358 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.
Title: Re: ASM Command of the Week
Post by: chickendude on January 13, 2012, 08:13:10 pm
I haven't responded yet simply because, to be honest, i had no idea this command even existed :/ I could see it maybe being used for a fixed-width font text-wrapping routine or something, though that might not be quite so simple as you'd have to check for a space character and EOS character.
Title: Re: ASM Command of the Week
Post by: Xeda112358 on January 13, 2012, 08:14:38 pm
In that case, you can play with CPI >.>
Title: Re: ASM Command of the Week
Post by: Hot_Dog on January 18, 2012, 03:25:53 pm
Here's the next one:

CPL

Title: Re: ASM Command of the Week
Post by: Xeda112358 on January 18, 2012, 03:39:03 pm
CPL is a great command for logic. Pretty much, it inverts the A register. The most common thing I use it for, is with drawing sprites and pixels with erasing logic. For example, to display a sprite by erasing, take the sprite data and invert it with cpl, then use AND logic on the screen. Also, you can use it to invert the graph buffer:
Code: [Select]
     ld hl,9340h
     ld bc,3
       ld a,(hl)
       cpl
       ld (hl),a
       inc hl
       djnz $-4
       dec c
       jr nz,-7
     ret
Title: Re: ASM Command of the Week
Post by: calc84maniac on January 18, 2012, 03:46:54 pm
CPL can also be used to subtract from 255. This is useful to subtract A from any number N by doing this:

cpl
add a,N+1


Of course, if N=254, 255, or 0, replace the add with a dec a, nothing, or inc a respectively.
Title: Re: ASM Command of the Week
Post by: Xeda112358 on January 18, 2012, 03:55:32 pm
Building off of what calc said, NEG is like CPL \ INC A, except NEG will modify the c flag.
Title: Re: ASM Command of the Week
Post by: chickendude on January 18, 2012, 05:02:15 pm
Like others have said, I use cpl for a quicker/smaller xor $FF, for example in my tilemapper to get the mask  when  rotating the screen:
Code: [Select]
updateRotation:
    ld a,(xOff)         ;what is the xOffset?
    and 7               ;we're only interested in the lower three bits (essentially xOff % 8)
    ld hl,gbufMask
    ld e,a
    ld d,0
    add hl,de           ;pointer to the rotation mask
    ld a,(hl)
    ld hl,maskLeft
    ld (hl),a
    ld hl,maskRight
    cpl                 ;xor $FF
    ld (hl),a
;...
    ret
gbufMask:
.db %11111111   ;0 display all of the first byte, none of the second
.db %11111110   ;1 after rotating left once, we only want the 7 leftern most bits of byte 1, and rightmost bit of byte 2
.db %11111100   ;2
.db %11111000   ;3
.db %11110000   ;4
.db %11100000   ;5
.db %11000000   ;6
.db %10000000   ;7
...which, btw, is based off an idea calc84maniac mentioned on IRC a few years ago of doing the rotation in the fastcopy routine, though i remember you saying that your main fastcopy loop was much faster than mine :)
Title: Re: ASM Command of the Week
Post by: Hot_Dog on February 08, 2012, 12:01:46 am
The next one is

SCF

Normally, this is used for math (do share ;D)

Sometimes I find the need to use the carry flag for conditions beyond what it is normally used for (detecting overflows or underflows).  For example, I could theoratically use C or NC to see if an object is collidable or not.  Whatever the situation, I would use SCF to set the carry flag if a condition is true. 
Title: Re: ASM Command of the Week
Post by: ralphdspam on February 08, 2012, 01:17:34 am
Was I not updating the topic weekly?  Whoops.  :P

Anyways, there is a very nice use of SCF in Axe's sound routine.  Instead of using it for math, it is used for conditional branching.
Code: [Select]
xor a
__FreqOutLoop1:
push bc
ld e,a
__FreqOutLoop2:
ld a,h
or l
jr z,__FreqOutDone
dec hl
dec bc
ld a,b
or c
jr nz,__FreqOutLoop2
ld a,e
xor %00000011
scf
__FreqOutDone:
pop bc
out ($00),a
ret nc
jr __FreqOutLoop1
Title: Re: ASM Command of the Week
Post by: Xeda112358 on February 08, 2012, 07:42:22 am
I often like to use it to return whether a function was successful or not. For example, the c flag here means the pixel was in bounds, so its location was computed normally:
Code: [Select]

GetPixelLoc:
;Input:
;     b is X
;     c is y
;Output:
;     HL points to byte
;     A is the mask
;     nc if not computed, c if computed
       ld a,c
       cp 64 \ ret nc
       ld a,b
       cp 96 \ ret nc
       ld l,c
       ld h,0
       ld b,h
       add hl,hl
       add hl,bc
       add hl,hl
       add hl,hl
       ld b,a
       rrca \ rrca \ rrca
       and 0Fh
       ld c,a
       ld a,b
       ld b,0
       add hl,bc
       ld bc,(BufPtr)
       add hl,bc
       and 7
       ld b,a
       inc b
       ld a,1
         rrca
         djnz $-1
       scf
       ret
Sometimes I need to correct an addition or subtraction by also adding or subtracting one:
Code: [Select]

OP1NameLength:
;Returns the name length in HL
        ld hl,8478h
NameLength:
        xor a \ ld b,a \ ld c,a
        cpir
        ld h,a \ ld l,a
        scf \ sbc hl,bc
        ret
 
(There is a better version of that)
Also, sometimes there are some very specific adjustments. In this case, you will see scf is used only when the end of the file is met, so an extra 1 must be subtracted to get the line length:
Code: [Select]

SearchLine:
;Inputs:
;     HL points to the start
;     BC is the number of bytes to search
;     DE is the line number
;     A is the line byte
;Outputs:
;     A is not changed
;     BC is the number of bytes left for the search
;     DE points to the line
;     HL is the length of the line
;===============================================================
     dec de \ inc d \ inc e
     or a
     ld (TempWord1),hl
SearchLoop:
     cpir                       ;21X-5
     jp po,EndSearchLoop+1
     dec e \ jr nz,SearchLoop-3
     dec d \ jr nz,SearchLoop-3
EndSearchLoop:
     scf
     ld de,(TempWord1)
     sbc hl,de
     ret
Title: Re: ASM Command of the Week
Post by: Hot_Dog on February 16, 2012, 11:30:06 am
OR

In bit manipulation, you can use this to set bits

Code: [Select]

ld a, %10000000
or %10000001   ;The first and last bits will be set no matter what.  All others will not be affected.


OR A is a wonderful substitue to "CP 0."  Also, OR A is a great way to reset the carry flag.  Whenever you want to subtract something from HL, you have to use the instruction SBC, and in a lot of cases, you want to make sure that the carry flag is reset, or your subtraction result could come out wrong.

Code: [Select]

ld hl, 10000
ld de, 5000
or a
sbc hl, de  ;Now it's guranteed that HL = 5000 instead of 4999.

Title: Re: ASM Command of the Week
Post by: calc84maniac on February 16, 2012, 01:44:27 pm
OR can be used to check if a multi-byte value is zero. For example, to check if BC is zero, use
ld a,b
or c
jr z,Value_Is_Zero


If you have a 32-bit value in DEHL, you can similarly use
ld a,d
or e
or h
or l
jr z,Value_Is_Zero
Title: Re: ASM Command of the Week
Post by: Hot_Dog on March 13, 2012, 11:20:24 pm
BIT

This will test a bit in a register to see if it's 1 or 0.  I find this instruction especially useful for (hl) and A  (If I don't want to lose the value that I have stored in register A with bit manipulation)
Title: Re: ASM Command of the Week
Post by: Xeda112358 on March 13, 2012, 11:55:16 pm
In a similar vein, you can do some soft-core SMC to speed up a routine such as pixel-testing or even turning the pixel on or off:
Code: [Select]
;===============================================================
PlotPixel:
;===============================================================
;Inputs:
;     B is the x-coordinate
;     C is the y-coordinate
;     D=Method
;        1=Test
;        2=Off
;        3=On
;     (BufPtr) points to the buffer to draw to
;Outputs:
;     BC is equal to (BufPtr)
;     DE not modified
;     HL points to the byte the pixel is drawn to
;     When using the pixel test method:
;       z means pixel off
;       nz means pixel on
;Destroys:
;     A
;===============================================================
     ld a,3Fh            ;7
     srl b \ rra         ;12    19
     srl b \ rra         ;12    31
     srl b \ rra         ;12    43
     cpl                 ;4     47
     or d                ;4     51
     rrca \ rrca         ;8     59
     ld (Method),a       ;13    72
     ld a,b              ;4     76
     ld b,0              ;7     83
     ld h,b \ ld l,c     ;4     87
     add hl,bc           ;11    98
     add hl,bc           ;11   109
     add hl,hl           ;11   120
     add hl,hl           ;11   131
     ld c,a              ;4    135
     add hl,bc           ;11   146
     ld bc,(BufPtr)      ;20   166    BufPtr points to the buffer
     add hl,bc           ;11   177
     .db $CB             ;15   192    First byte of BIT
Method:
     .db 46h             ;            second byte of the BIT instruction
     ret                 ;10   202  37 bytes
Title: Re: ASM Command of the Week
Post by: Quigibo on March 14, 2012, 04:36:21 am
Code: [Select]
bit 5,a
bit 3,a

These will set the hidden flag in the F register in the same way as, and in addition to, the z flag.  Obsucre? Yes.  Useful? >:D
Title: Re: ASM Command of the Week
Post by: calc84maniac on March 14, 2012, 04:43:20 am
The hidden flags only exist on the old models of the TI-83+, though (the ones with real Zilog chips)
Title: Re: ASM Command of the Week
Post by: ZippyDee on March 14, 2012, 06:08:07 am
But is there actually any use for the hidden flags? Are the values documented?
Title: Re: ASM Command of the Week
Post by: Hot_Dog on April 03, 2012, 10:59:53 am
EXX
Title: Re: ASM Command of the Week
Post by: Xeda112358 on April 03, 2012, 11:12:32 am
That is a pretty useful command, especially if you need more registers, or you need to preserve some and you don't use interrupts. I personally rarely use interrupts, so super complicated math functions get to use b'c'd'e'h'l' :D

So details:
4 cycles, 1 byte, hex code: D9
Swaps registers with shadow registers


So as a really poor example, say I need to copy some data to memory somewhere, but I need to preserve all registers for some reason. Also, assume you don't need interrupts :P

Code: [Select]
di
exx
ld bc,768
ld hl,BufData
ld de,plotSScreen
ldir
exx
And yay, your registers are preserved :D
Title: Re: ASM Command of the Week
Post by: calc84maniac on April 03, 2012, 11:13:46 am
I use shadow BC, DE, HL in all of my intense rendering methods: Project M parallax tilemapper, F-Zero mode7 engine, and TI-Boy tilemapping. (I rarely find a need to use shadow AF, which I would usually give to interrupts).

Also, shadow registers play a crucial role in TI-Boy's CPU emulator, as they hold the Game Boy's BC,DE,HL registers. This allows me to execute many GBZ80 opcodes almost directly, by doing something like exx \ add a,e \ exx in order to emulate add a,e, etc.
Title: Re: ASM Command of the Week
Post by: Xeda112358 on April 03, 2012, 11:14:29 am
Wow, nice, now I see why it is so fast o.o
Title: Re: ASM Command of the Week
Post by: TIfanx1999 on April 03, 2012, 06:40:52 pm
@calc84:That's pretty cool. =)
Title: Re: ASM Command of the Week
Post by: chickendude on September 03, 2012, 03:43:43 am
Can anyone think of a good use for otd/oti? I just saw JimE's Keyin (http://www.ticalc.org/archives/files/fileinfo/239/23966.html) routine which has a pretty interesting use of ini to store all DI keypresses into saferam that you can access using "bit key,(iy+keygroup)". It's a pretty interesting idea i might implement into some of my programs, especially since you don't have to worry about registers getting overwritten :)
Title: Re: ASM Command of the Week
Post by: Xeda112358 on September 03, 2012, 08:23:15 am
I have used these commands to read/write data to the LCD ports.

EDIT: For example, if I wanted to draw a simple sprite, assuming the LCD coordinates are already loaded:
Code: [Select]
     ld bc,0811h       ;b=8, size of the sprite, c=11h, the LCD Data port
     ld hl,SpriteData
DrawLoop:
     <<any code to provide a proper delay>>
     outi
     jr nz,DrawLoop
     ret
SpriteData:
     .db 3Ch,42h,81h,81h,81h,81h,42h,3Ch    ;ball
Title: Re: ASM Command of the Week
Post by: chickendude on September 03, 2012, 01:37:01 pm
That's what i figured they could be used for, though i was thinking more along the lines of a fastcopy routine. Thanks for the sample.
Title: Re: ASM Command of the Week
Post by: thepenguin77 on September 03, 2012, 05:58:41 pm
Let's not forget USB.

Code: [Select]
send8BytesBitsOverPipe0:
ld hl, bytesToSend
ld bc, 8*256+$A0
otir
ret

Code: [Select]
;#######################################
;take in all the bytes from a port
;input: c = port
;output: b = bytes received
importBytes:
ld b, 0
importLoop:
in a, ($96)
or a
ret z
ini ;this dec's b
inc b
inc b
jr importLoop


Every USB program includes some form of ini/inir and oti/otir. The reason you can do this is because the USB driver has internal buffers and does not need a delay when you write to it.
Title: Re: ASM Command of the Week
Post by: Xeda112358 on September 05, 2012, 12:33:48 pm
Hmm, so if I am reading your post properly, the first code sends 8 bytes to port $A0, and the second writes all the bytes being received, to HL, and then returns the number of bytes that were received? Is USB control that easy?
Title: Re: ASM Command of the Week
Post by: thepenguin77 on September 05, 2012, 01:51:46 pm
Hmm, so if I am reading your post properly, the first code sends 8 bytes to port $A0, and the second writes all the bytes being received, to HL, and then returns the number of bytes that were received? Is USB control that easy?

The one that reads all of the data is that easy. The driver basically says, "I got some data for you" and you read it all.

The output one is super simplified, but this small section of code does appear in most data transfer code.


USB is super hard.
Title: Re: ASM Command of the Week
Post by: Xeda112358 on September 07, 2012, 09:07:38 am
Okay, I will have to experiment a little with that, then. I don't care to use a standard USB protocol, anyways.
Title: Re: ASM Command of the Week
Post by: shmibs on September 07, 2012, 10:11:17 am
ooh, are you going to be using it for direct linking between calcs?
Title: Re: ASM Command of the Week
Post by: Xeda112358 on September 07, 2012, 04:14:24 pm
Yes, that is what I would try to do, if I can manage it.