I found out about this site when I saw someone had linked to a project of mine. I come from the world of Texas Instruments Z80-based calculators (TI-83+/84+ in particular). I love optimizing code and I mostly make math routines and parsers, though I occasionally dabble in 2-D graphics.
I think that of all the routines I made last year, this is the one I am most proud of, an 8-bit PRNG that occasionally moonlights as a true RNG:
Code: Select all
;This code snippet is 9 bytes and 43cc
;Inputs:
; HL is the input seed and must be non-zero
;Outputs:
; A is the 8-bit pseudo-random number
; HL is the new seed value (will be non-zero)
;opcode cc
add hl,hl ; 29 11
sbc a,a ; 9F 4
and %00101101 ; E62D 7
xor l ; AD 4
ld l,a ; 6F 4
ld a,r ; ED5F 9
add a,h ; 84 4
;-------------------------------------------------------------------------------
;Technical details:
; The concept behind this routine is to combine an LFSR (poor RNG) with a
; counter. The counter improves the RNG quality, while also extending the period
; length.
; For this routine, I took advantage of the Z80's built-in counter, the `r`
; register. This means that we don't need to store the counter anywhere, and it
; is pretty fast to access!
; Some caveats:
; * r is a 7-bit counter
; * r will increment some number of times between runs of the RNG. In most
; cases, this will be constant, but if it increments an even number each
; time, then the bottom bit is always the same, weakening the effect of
; the counter. In the worst case, it increments a multiple of 128 times,
; effectively making your RNG just as good/bad as the LFSR. Ideally, you
; want `r` to increment an odd number of times between runs.
; * In the best case, the bottom 7 bits have 50/50 chance of being 0 or 1.
; The top bit is 1 with probability 1/2 + 1/(2^17-2) ~ .5000076295
; * In the event that your main loop waits for user input between calls,
; then congatulations, you might have a True RNG :)
;-------------------------------------------------------------------------------
If you are into truly obscene code, this square root routine will do it for you:
Code: Select all
; fast 16-bit isqrt by Zeda Thomas
;Feel free to use for whatever :)
sqrtHL:
;Input: HL
;Output: A is the integer square root of HL
;Destroys: HL,DE (D is actually 0)
;min: 343cc
;max: 380cc
;avg: 361.5cc
;88 bytes
ld de,05040h ; 10
ld a,h ; 4
sub e ; 4
jr nc,sq7 ;\
add a,e ; | branch 1: 12cc
ld d,16 ; | branch 2: 18cc
sq7: ;/
; ----------
cp d ; 4
jr c,sq6 ;\
sub d ; | branch 1: 12cc
set 5,d ; | branch 2: 19cc
sq6: ;/
; ----------
res 4,d ; 8
srl d ; 8
set 2,d ; 8
cp d ; 4
jr c,sq5 ;\
sub d ; | branch 1: 12cc
set 3,d ; | branch 2: 19cc
sq5: ;/
srl d ; 8
; ----------
inc a ; 4
sub d ; 4
jr nc,sq4 ;\
dec d ; | branch 1: 12cc
add a,d ; | branch 2: 19cc
dec d ; | <-- this resets the low bit of D, so `srl d` resets carry.
sq4: ;/
srl d ; 8
ld h,a ; 4
; ----------
ld a,e ; 4
sbc hl,de ; 15
jr nc,sq3 ;\
add hl,de ; | 12cc or 18cc
sq3: ;/
ccf ; 4
rra ; 4
srl d ; 8
rra ; 4
; ----------
ld e,a ; 4
sbc hl,de ; 15
jr c,sq2 ;\
or 20h ; | branch 1: 23cc
db 254 ; | <-- start of `cp *` which is 7cc to skip the next byte.
sq2: ; | branch 2: 21cc
add hl,de ;/
xor 18h ; 7
srl d ; 8
rra ; 4
; ----------
ld e,a ; 4
sbc hl,de ; 15
jr c,sq1 ;\
or 8 ; | branch 1: 23cc
db 254 ; | <-- start of `cp *` which is 7cc to skip the next byte.
sq1: ; | branch 2: 21cc
add hl,de ;/
xor 6 ; 7
srl d ; 8
rra ; 4
; ----------
ld e,a ; 4
sbc hl,de ; 15
;This code would restore the square root
; jr nc,sq0 ;\
; add hl,de ; | 12cc or 18cc
; sq0: ;/
sbc a,255 ; 7
srl d ; 8
rra ; 4
ret ; 10
Some of my projects on Github are:
Z80 Optimized Routines - These are optimized routines that I've either made or gathered (with permission). If you have some useful routines or optimizations that you'd like to contribute, please do!
z80float - This is a library of floating point routines for the Z80. There are 24-bit floats that are great for the Z80 (operands can be passed via registers), as well as two 32-bit float formats (7 digits), and an 80-bit format (19 digits). Each variant has addition, subtraction, multiplication, division, square roots, logarithms, exponentials (i.e. e^x, x^y, etc), cosine/sine/tangent, arccosine/arcsine/arctangent, hyperbolic cos/sin/tan, hyperbolic arccos/arcsin/arctan, and probably a few others that I missed. Please bug me about any issues!