Author Topic: [z80 asm] picture enlarge routine for axe  (Read 3815 times)

0 Members and 1 Guest are viewing this topic.

Offline MGOS

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 336
  • Rating: +95/-0
    • View Profile
[z80 asm] picture enlarge routine for axe
« on: August 11, 2012, 10:54:29 am »
Hey guys,
this is my first real try on Asm, I need it to embed in an axe program.
It takes a 156 byte file located where theta ($89EA) points to, should scale it with factor 2 and write it to AppBackUpScreen, starting at L3+24 ($988A). I use IX for read and IY to write. It converts each byte of the input to 2 bytes by shifting.
10011101 becomes 1100001111110011 etc.

Code: [Select]
ld   de,6  ; byte counter for lines, each 6 bytes next line
 ld   ix,($89EA)  ; get the location of file
 ld   iy,$988A    ; get location to write
 ld   b, 156      ; counter init
loop:
 ld   a,(ix+0)  ; get element of file
 ld   hl,0      ; reset hl
 ld   c,b       ; backup b for second loop
 ld   b,8       ; initialize second loop
double:
 rrca     ; get a bit of a in carry
 rr   l   ; shift that in l
 rr   h   ; shift also h
 sra  l   ; doublicate bit and shift once more
 rr   h
 djnz -9  ; repeat "double" for each bit

 ld   (iy+0),l   ; write first half
 ld   (iy+1),h   ; second half
 ld   (iy+12),l  ; next line
 ld   (iy+13),h
 dec  e   ; count one down (each 6 bytes there has to be a line skipped)
 jrnz 9   ; execute only if counter 0, otherwise jump to else
 ld   de,12
 add  iy,de   ; add 12 to skip next line
 ld   e,6     ; reset counter
else:
 ld   b,c   ; get backup of main counter
 djnz -43   ; jump back to loop to repeat if counter finished

First of all, it isn't working exactly correctly, but it doesn't crash immediately. Where is my logical mistake?
Secondly, it makes things weird on my calc (83+). I have to clear ram each time. Are there any things that you need to do when using these registers? Backup them? How?

I'm quite a noob in asm, so please excuse when I'm doing things really stupid. Asm was the only way I could think of solving this fast.
« Last Edit: August 11, 2012, 10:55:10 am by MGOS »

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: [z80 asm] picture enlarge routine for axe
« Reply #1 on: August 11, 2012, 11:13:12 am »
Don't use the IY register unless you have to. The OS expects it to point to flags (pointer to the system flags) at all time, including during interrupts. That's why you can do things like this without assigning IY beforehand:
Quote from: Z80 Assembly
    set textInverse,(IY+textFlags)
If you really need to use IY, you should always disable interrupts first, and when you're done enable interrupts and return IY to its usual place:
Quote from: Z80 Assembly
    di
    ; mess with IY all you want
    ld IY,flags
    ei
EDIT: I don't think you meant to do djnz -9. The assembler will try to send control to address $FFF7, and since djnz has only a 256-byte relative jump range, that can basically be anywhere in a 256-byte block surrounding the routine depending on where the routine is located.

I think you meant to do djnz double. Same thing with the jr nz stuff. The assembler calculates the appropriate offset for you.
« Last Edit: August 11, 2012, 11:24:49 am by Deep Thought »




Offline MGOS

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 336
  • Rating: +95/-0
    • View Profile
Re: [z80 asm] picture enlarge routine for axe
« Reply #2 on: August 11, 2012, 12:04:34 pm »
Thanks for the answer. I didn't knew the stuff with IY. IX is usable, right?
So I think I'm able to replace IY with something else.

I don't think you meant to do djnz -9. The assembler will try to send control to address $FFF7, and since djnz has only a 256-byte relative jump range, that can basically be anywhere in a 256-byte block surrounding the routine depending on where the routine is located.

I think you meant to do djnz double. Same thing with the jr nz stuff. The assembler calculates the appropriate offset for you.

I don't have an assembler, I do it by hand and Runer's IRC bot. So I just count the bytes to jump (-2 of the opcode of course).

Edit: to complete this topic, I add calc84maniac's correct and optimized version of it. I forgot to increment the pointers.
Code: [Select]
ld   hl,($89EA)   ; get the location of file
 ld   ix,$988A     ; get location to write
 ld   bc, 26*256+6 ; row counter in B (26), column counter in C (6)
outerloop:
 push bc
innerloop:
 ld   e,(hl)    ; get element of file
 ld   b,8       ; initialize second loop
double:
 rrc e    ; get a bit of e in carry
 rr   d   ; shift that in d
 rra      ; shift also a
 sra  d   ; duplicate bit and shift once more
 rra
 djnz double  ; repeat "double" for each bit
 ld   (ix+0),d   ; write first half
 ld   (ix+1),a   ; second half
 ld   (ix+12),d  ; next line
 ld   (ix+13),a
 inc hl          ; next file byte
 inc ix          ; next column
 inc ix          ; next column
 dec  c   ; count one down (each 6 bytes there has to be a line skipped)
 jr nz,innerloop
 ld   c,12    ;B is already 0, so BC=12
 add  ix,bc   ; add 12 to skip next line
 pop bc       ; restore row counter and column counter
 djnz outerloop

Now I just need to make it work the other way round.
« Last Edit: August 25, 2012, 09:20:02 am by MGOS »

Offline chickendude

  • LV8 Addict (Next: 1000)
  • ********
  • Posts: 817
  • Rating: +90/-1
  • Pro-Riot Squad
    • View Profile
Re: [z80 asm] picture enlarge routine for axe
« Reply #3 on: August 25, 2012, 07:19:44 am »
Btw, you don't need to subtract two extra bytes when you are jumping backwards, you just need to add the size of the instruction when jumping forward. At least not when assembling on a computer. I think if you were writing hex code, you'd be right (for relative jumps, at least), as a hex value of $00 would jump to the next instruction. However, the assembler starts at the start of the instruction (that is, at the first byte of the instruction), so jr $ would cause an infinite loop. Jr $-9 would jump to the instruction nine bytes before (in your case, the address held by the label double).

EDIT: DeepThought: For djnz/jr, would a value like -9 really trip it up? I think you might end up jumping to the wrong place because the calculator calculates relative jumps differently from the assembler. Wouldn't the assembler just load $F7 (even if it gets interpreted as $FFF7, the assembler might truncate it down to $F7) after the djnz/jr byte (i don't know what the hex codes are), essentially jumping to $-7 (2 bytes after double, aka the 2nd byte of the "rr l"?
« Last Edit: August 25, 2012, 07:28:11 am by chickendude »

Offline MGOS

  • LV6 Super Member (Next: 500)
  • ******
  • Posts: 336
  • Rating: +95/-0
    • View Profile
Re: [z80 asm] picture enlarge routine for axe
« Reply #4 on: August 25, 2012, 09:08:11 am »
Btw, you don't need to subtract two extra bytes when you are jumping backwards, you just need to add the size of the instruction when jumping forward. At least not when assembling on a computer. I think if you were writing hex code, you'd be right (for relative jumps, at least), as a hex value of $00 would jump to the next instruction. However, the assembler starts at the start of the instruction (that is, at the first byte of the instruction), so jr $ would cause an infinite loop. Jr $-9 would jump to the instruction nine bytes before (in your case, the address held by the label double).

EDIT: DeepThought: For djnz/jr, would a value like -9 really trip it up? I think you might end up jumping to the wrong place because the calculator calculates relative jumps differently from the assembler. Wouldn't the assembler just load $F7 (even if it gets interpreted as $FFF7, the assembler might truncate it down to $F7) after the djnz/jr byte (i don't know what the hex codes are), essentially jumping to $-7 (2 bytes after double, aka the 2nd byte of the "rr l"?
I'm now using a compiler, so I don't care that much anymore. Afaik you have to write the number of bytes you jump in the source, and in the hex 2 is automatically subtracted (doesn't matter if forward or backward) by the compiler. If you don't have a compiler, you have to subtract 2 by hand.

Example: jr $1 would skip one byte. jr $-5 would jump to byte 3 before "jr". jr $-2 would make it stuck in an endless loop.

Offline Deep Toaster

  • So much to do, so much time, so little motivation
  • Administrator
  • LV13 Extreme Addict (Next: 9001)
  • *************
  • Posts: 8217
  • Rating: +758/-15
    • View Profile
    • ClrHome
Re: [z80 asm] picture enlarge routine for axe
« Reply #5 on: August 25, 2012, 10:43:19 am »
EDIT: DeepThought: For djnz/jr, would a value like -9 really trip it up? I think you might end up jumping to the wrong place because the calculator calculates relative jumps differently from the assembler. Wouldn't the assembler just load $F7 (even if it gets interpreted as $FFF7, the assembler might truncate it down to $F7) after the djnz/jr byte (i don't know what the hex codes are), essentially jumping to $-7 (2 bytes after double, aka the 2nd byte of the "rr l"?
It'll try to subtract the $+2 from $F7 and make the jump to there, since it has to be relative to the byte following the jump instruction.

Basically, it'll jump to the nearest address that ends in $F7.
Example: jr $1 would skip one byte. jr $-5 would jump to byte 3 before "jr". jr $-2 would make it stuck in an endless loop.
jr $1 would jump to the nearest address ending in 01h; jr $-5 would jump to five bytes before the start of the jr instruction; and jr $-2 would jump to two bytes before the start of the jr instruction. jr $ would be an endless loop.

I don't think you understand what $ means in this context. Besides signifying that the following number is in hexadecimal, $ on its own also refers to the address of the current instruction.

So if you had a program that started with this:
Quote from: Z80 Assembly
.org        $9D95-2
.db         $BB,$6D
    ld  HL, $+2
The value of HL would be 9D97h—since $ at that instruction equals 9D95h and you're adding two to the value. If you had done this instead:
Quote from: Z80 Assembly
.org        $9D95-2
.db         $BB,$6D
    ld  HL, $2
The value of HL would simply be 0002h.

The point about this is that any assembler will try to convert an address following a relative jump instruction into the appropriate offset. That's why jp 12345 and jr 12345 do the same thing (assuming the jr is in range). With the first instruction, the assembler will give you C3 39 30 (a straightforward jump to 3039h), whereas with the second instruction, what the assembler assembles depends on the value of $ (where you are in memory). If the jr instruction is placed at address 12350, the next instruction starts at 12352 (since jr is a two-byte instruction), so it needs to create a relative jump seven bytes back. In this case, the instruction would be identical to jr $-5, since it's jumping to $ minus five. What you get is 18 F9 (0F9h being -7 as a signed byte).

So what happens when you try to jr -9? Let's say the instruction starts at 12350 again. The compiler reads -9 as absolute address 0FFF7h, but that's way out of range, since 12350 is only 303Eh. A decent assembler will throw you an error or warning on this, but some assemblers may just truncate and try to jump to there. In that case, it would move you to the only valid address ending in $F7, which in this case is 2FF7h. That's 71 bytes back from the start of the instruction, so the generated hexadecimal is 18 B7 (0B7h being -73 as a signed byte).

Hope that clears some stuff up for you :)
« Last Edit: August 25, 2012, 11:09:07 am by Deep Thought »