Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Tutorial: How to put inline assembly functions into ZX Basic
#16
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!
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#17
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
Reply
#18
Scuse the double post. Odd.
Reply
#19
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!
------------------------------------------------------------
http://lcd-one.da.ru redirector is dead
Visit my http://members.inode.at/838331/index.html home page!
Reply
#20
Is there any chance of getting an extra flag on the Print function that draws a character/sprite mirrored?
left/right and up/down
Reply
#21
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
Reply
#22
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
Reply
#23
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)
Reply
#24
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
Reply
#25
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
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)