Forum
Tutorial: How to put inline assembly functions into ZX Basic - Printable Version

+- Forum (https://www.boriel.com/forum)
+-- Forum: Compilers and Computer Languages (https://www.boriel.com/forum/forumdisplay.php?fid=12)
+--- Forum: ZX Basic Compiler (https://www.boriel.com/forum/forumdisplay.php?fid=11)
+---- Forum: How-To & Tutorials (https://www.boriel.com/forum/forumdisplay.php?fid=13)
+---- Thread: Tutorial: How to put inline assembly functions into ZX Basic (/showthread.php?tid=428)

Pages: 1 2


Re: Tutorial: How to put inline assembly functions into ZX B - LCD - 02-20-2012

britlion Wrote:Ah - then you'd need one that just looks like this, I think:


Code:
function fastcall mirror (number as uByte) as uByte
asm
   ld b,8
   ld c,a
   XOR A
mirrorLoop:
      RR C
      RLA
DJNZ mirrorLoop
end asm
END FUNCTION

I haven't tested it, mind. Just typed it here. Feels right, though Smile
Works and is very very fast!!!
Simple but great!


Re: Tutorial: How to put inline assembly functions into ZX B - britlion - 02-22-2012

LCD Wrote:Works and is very very fast!!!
Simple but great!

It's a classic case of win by unrolled loop, though. As it stands, the main part of this function (not including the setup for being called, or the returning part at the end, which ZX Basic does for us) takes:

15 (intro) + (7*25) loop + 20 (last loop that doesn't jump back) = 210 T states.

An unrolled loop version would take

15 (intro) + 8*12 = 111 T states. Or 89% faster.... Those 13 T state DJNZ jumps are quite a big proportion.

If I was using this function, considering that I'm using a mirror function to replace storing the graphics in both left and right configuration, I'd want it to be fast, and I'd probably be willing to give up 12 bytes to do this - the loop version is 8 bytes. The unrolled loop is 20. [Edit - just realised that XOR A probably doesn't matter, since the rotates slide A off anyway. So 7 bytes versus 19 bytes, and 206 T states vs 107]

Code:
function fastcall mirror (number as uByte) as uByte
asm
  ; ld b,8  ; We don't need this either. We're not looping.
   ld c,a
   ; XOR A ; Edit - I bet it works without this. Saving 4 T states

   RR C
   RLA
  
   RR C
   RLA

   RR C
   RLA

   RR C
   RLA

   RR C
   RLA

   RR C
   RLA

   RR C
   RLA

   RR C
   RLA
end asm
END FUNCTION



Re: Tutorial: How to put inline assembly functions into ZX B - britlion - 02-22-2012

Scuse the double post. Odd.


Re: Tutorial: How to put inline assembly functions into ZX B - LCD - 02-22-2012

britlion Wrote:If I was using this function, considering that I'm using a mirror function to replace storing the graphics in both left and right configuration, I'd want it to be fast, and I'd probably be willing to give up 12 bytes to do this - the loop version is 8 bytes. The unrolled loop is 20. [Edit - just realised that XOR A probably doesn't matter, since the rotates slide A off anyway. So 7 bytes versus 19 bytes, and 206 T states vs 107]
Excellent, thats why I always like to have choice between functions which are fast and functions which are just small. Thanks!


Re: Tutorial: How to put inline assembly functions into ZX B - slenkar - 02-22-2012

Is there any chance of getting an extra flag on the Print function that draws a character/sprite mirrored?
left/right and up/down


Re: Tutorial: How to put inline assembly functions into ZX B - britlion - 02-23-2012

I'd think that a very unlikely extension - you're asking for mirroring functions to be built into the compiler, and then for an extension to the print routine.

Given you can write your own functions, you can build these extensions into the system anyway - for example, using my mirror function there would be the basis of a left/right mirror.

Are you wanting to mirror UDG or the original character set?

These would be ideal functions to write in BASIC, and then replace with inline assembly Smile


Re: Tutorial: How to put inline assembly functions into ZX B - slenkar - 02-23-2012

I would like to mirror UDG,
does the mirroring function alter the stored image or create a new one?

I think altering the stored image would be best for most uses


Re: Tutorial: How to put inline assembly functions into ZX B - britlion - 02-23-2012

slenkar Wrote:I would like to mirror UDG,
does the mirroring function alter the stored image or create a new one?

I think altering the stored image would be best for most uses

It doesn't do either - it's a function. I think you misunderstand what a function does - it takes a parameter and has a return value.

For example, in Sinclair Basic, CHR$ is a function. It takes a number, and returns a string character. So you do CHR$(65) - sending it 65, and it comes back with "A" as a string. This is why PRINT CHR$(65) prints out "A" on the screen.

The mirror function I listed above is the same thing - it takes one number, and returns another number, such that the bits in the first number are a mirror image of the bits in the second.

Let's use the same number as an example. In Binary, the number 65 is '0100 0001'. So mirrored, that would be '1000 0010' right?

If you do PRINT mirror(65), it prints 130 - which is the decimal equivalent of '1000 0010'

This doesn't change your UDG at all, but it can be the basis of /making/ a udg that's mirrored from another one.

For example, to mirror a udg in place:

Code:
for i=USR "A" to USR "A" +7
poke i, mirror(peek i)
next i

Would probably work. It reads the byte with peek, sends it to mirror, and what comes back from mirror is poked back into the byte again. (Note that with the default graphic of "A" in the UDG A slot, this won't be very obvious, since a left-right mirrored Capital A looks identical before and after). I'm quite certain an assembler version SUB for this could be much better.

In a similar way, vertical reflection means swapping the byte order, so you need somewhere to put them temporarily:

Code:
DIM buffer (7) as uByte
for i = 0 to 7
let buffer (7-i) =peek (USR "A" +i)
next i

for i = 0 to 7
poke (USR "A" +i), buffer(i)
next i

(The code is all off top of my head and untested. Again, an assembler subroutine would be much faster)


Re: Tutorial: How to put inline assembly functions into ZX B - slenkar - 02-23-2012

thanks i can use that to draw tanks that face left or right, saving a few bytes,
it would also help in one of those top down games where the sprite has to face in 8 or more directions


Re: Tutorial: How to put inline assembly functions into ZX B - britlion - 08-19-2013

Up on WOS, someone schooled me.

This code will apparently mirror a byte as well. Still trying to get my head round the logic! (and if it works)

Code:
;17 bytes and 66 clock cycles
Reverse:
    ld b,a         ;b=ABCDEFGH
    rrca         ;a=HABCDEFG
    rrca         ;a=GHABCDEF
    xor b \ and %10101010 \ xor b     ;a=GBADCFEH
    ld b,a         ;b=GBADCFEH
    rrca         ;a=HGBADCFE
    rrca         ;a=EHGBADCF
    rrca         ;a=FEHGBADC
    rrca         ;a=CFEHGBAD
    xor b \ and %01100110 \ xor b     ;a=GFEDCBAH
    rrca         ;a=HGFEDCBA


n=0
n A B
0 0 0 -> 0 = B
0 0 1 -> 1 = B
0 1 0 -> 0 = B
0 1 1 -> 1 = B

n=1
1 0 0 -> 0 = A
1 0 1 -> 0 = A
1 1 0 -> 1 = A
1 1 1 -> 1 = A

a XOR b and n xor b


aaaaaaaa xor bbbbbbbb and 10101010 xor bbbbbbbb = abababab