├── .gitignore ├── examples └── chaosgame │ ├── chaos.8xp │ └── readme.md ├── math ├── multiplication │ ├── HL_Times_128.z80 │ ├── DE_Times_A.z80 │ ├── mul8.z80 │ ├── DE_Times_A_to_HL_sizeopt.z80 │ ├── mul8_faster_smaller.z80 │ ├── sqrA.z80 │ ├── DEBC_Times_A.z80 │ ├── sqr_L.z80 │ ├── HL_Times_12_special.z80 │ ├── mul24.z80 │ ├── mulfixed_88.z80 │ ├── C_Times_BDE.z80 │ ├── DE_Times_A_faster.z80 │ ├── mulfixed4_12.z80 │ ├── mulfixed1616.z80 │ └── mul32.z80 ├── rng │ ├── rand10.z80 │ ├── lfsr.z80 │ ├── lfsr64.z80 │ ├── rand16.z80 │ ├── rand24.z80 │ ├── rand32.z80 │ ├── xs32.z80 │ ├── xorshift16.z80 │ ├── xsp32.z80 │ ├── rand_TI_Float.z80 │ ├── lehmer16.z80 │ ├── rand16_LCG_xorshift.z80 │ ├── rng8_very_very_fast.z80 │ └── rand5.z80 ├── misc │ ├── D_compare_E_signed.z80 │ ├── A_mod_3.z80 │ ├── A_divisible_by_3.z80 │ ├── HL_divisible_by_3.z80 │ ├── lnfixed_88.z80 │ ├── pow2fixed_88.z80 │ ├── log2fixed_88.z80 │ ├── gcdHL_DE.z80 │ ├── ncr_HL_DE.z80 │ ├── natlog_fixed88.z80 │ └── log2fixed_88_table.z80 ├── subtraction │ ├── A_Minus_HL.z80 │ └── BC_Minus_A.z80 ├── division │ ├── div9.z80 │ ├── EHL_Div_D.z80 │ ├── C_Div_D.z80 │ ├── HL_Div_384.z80 │ ├── sdiv16.z80 │ ├── HL_Div_3_round.z80 │ ├── BC_Div_DE_sizeopt.z80 │ ├── HL_Div_5_round.z80 │ ├── DEHL_Div_C.z80 │ ├── HL_Div_5.z80 │ ├── DEHL_Div_10_fast.z80 │ ├── HL_Div_C_round.z80 │ ├── HL_Div_3_better.z80 │ ├── HL_Div_7_round.z80 │ ├── HL_Div_3.z80 │ ├── AL_Div_100.z80 │ ├── ALDE_div_100.z80 │ ├── BC_Div_DE_fast.z80 │ ├── bignum_div_100.z80 │ ├── ALDEIX_Div_100.z80 │ ├── HLDE_Div_C.z80 │ ├── sdiv24_16.z80 │ ├── BC_Div_DE.z80 │ ├── BC_Div_DE_faster.z80 │ ├── HL_Div_B_fast.z80 │ ├── HL_SDiv_BC.z80 │ ├── div32_16.z80 │ ├── DEHL_Div_10.z80 │ ├── div_32_32.z80 │ └── divfixed_88.z80 ├── squareroot │ ├── sqrtfixed_88.z80 │ ├── sqrtHL_faster.z80 │ ├── sqrtDE_slower.z80 │ ├── sqrtL.z80 │ ├── sqrtA_fastest.z80 │ ├── sqrt32.z80 │ └── sqrtfixed_88_fast.z80 ├── addition │ └── addBCD_16.z80 ├── trig │ ├── atan8.z80 │ └── atanE.z80 └── float │ ├── extendedprecision.md │ └── singleprecision.md ├── conversion ├── A_To_ASCII_Char.z80 ├── toUpper.z80 ├── reverseHL.z80 ├── reverseA.z80 ├── inflateA.z80 ├── signed16To8.z80 ├── L_To_BCD.z80 ├── atoui8.z80 ├── i16toa_destructive.z80 ├── atoui32.z80 ├── uint32tostr_baseC.z80 ├── string_to_uint16.z80 ├── uitoa_16.z80 ├── fixed1616_to_str.z80 ├── uitoa_8.z80 ├── u16toa_destructive.z80 ├── itoa_8.z80 ├── itoa_16.z80 ├── fixed88_to_str.z80 └── fixed_4_12_to_str.z80 ├── ti8x ├── gfx │ ├── pixelOn.z80 │ ├── pixelToggle.z80 │ ├── pixelOff.z80 │ ├── fillgbuf_faster.z80 │ ├── pixelTest.z80 │ ├── fillgbuf.z80 │ ├── plotpixel.z80 │ ├── shiftleft_v.z80 │ ├── shiftgbufright4.z80 │ ├── shiftgbufleft4.z80 │ ├── horizontal.z80 │ ├── shiftright_v.z80 │ ├── vertical.z80 │ ├── getpixelloc.z80 │ ├── fillgbuf_very_fast.z80 │ ├── getpixelloc_faster.z80 │ ├── getpixelloc_0x9340_nobounds.z80 │ ├── rectOR.z80 │ ├── rectXOR.z80 │ ├── getpixelloc_0x9340.z80 │ ├── getpixelloc_nobounds.z80 │ ├── rectErase.z80 │ ├── shiftgbufupA.z80 │ ├── shiftgbufdownA.z80 │ ├── vbufToLCD.z80 │ ├── UpdateLCD.z80 │ ├── bigsprite_OR.z80 │ ├── bigsprite_Erase.z80 │ ├── bigsprite_XOR.z80 │ ├── bigsprite_AND.z80 │ ├── putbigsprite.z80 │ ├── bigsprite_Overwrite.z80 │ ├── gray4v.z80 │ ├── getpixelloc_v.z80 │ ├── updatelcd_partial.z80 │ ├── drawtile_v.z80 │ ├── PutSprite16.z80 │ ├── verticalline.z80 │ ├── iPutSpriteMask.z80 │ ├── filledcircle.z80 │ ├── gbuf_to_lcd_6MHz.z80 │ ├── putspritemasked_fasterer.z80 │ ├── putsprite10.z80 │ ├── putspritemasked_fastest.z80 │ ├── putspritemasked_faster.z80 │ ├── sprite8.z80 │ └── gbuf_to_lcd_15MHz.z80 ├── utility │ ├── batterylevel_basic.z80 │ ├── checkkey.z80 │ ├── set15MHz.z80 │ ├── getKey.z80 │ ├── dispfixed1616.z80 │ ├── dispfixed88.z80 │ ├── typewritertext.z80 │ ├── dispi8.z80 │ ├── dispui8.z80 │ ├── dispi16.z80 │ ├── dispui16.z80 │ ├── CRC16.z80 │ ├── dispfixed412.z80 │ ├── getappnumpages.z80 │ ├── centertext.z80 │ ├── getKeyDebounce.z80 │ ├── text_len.z80 │ ├── setXXX_signed.z80 │ ├── getbatterylevel.z80 │ ├── setXX.z80 │ ├── fastLDIR.z80 │ ├── flashtoRAM.z80 │ ├── setXXX_faster.z80 │ ├── setXXX.z80 │ ├── ConvOP_noerr.z80 │ └── ConvOP.z80 └── VAT │ ├── ChkFindSym.z80 │ └── findsym.z80 ├── utility ├── strcopy.z80 ├── stringlength_8bit.z80 ├── swapbytes.z80 ├── stringlength.z80 ├── stringlength_smaller.z80 ├── im2setup.z80 ├── pushpop.z80 ├── diRestore.z80 ├── fastLDIR.z80 └── im2setup_smaller.z80 ├── misc ├── mask_least_bit.z80 ├── hotspot2.z80 └── hotspot.z80 ├── search ├── cpstr.z80 ├── cpstr_nocase_faster.z80 └── cpstr_nocase.z80 ├── todo.txt ├── LICENSE.md ├── gfx ├── filledcircle.z80 ├── line.z80 └── circle.z80 └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /test 2 | compile 3 | .atom-build.json 4 | -------------------------------------------------------------------------------- /examples/chaosgame/chaos.8xp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Zeda/Z80-Optimized-Routines/HEAD/examples/chaosgame/chaos.8xp -------------------------------------------------------------------------------- /math/multiplication/HL_Times_128.z80: -------------------------------------------------------------------------------- 1 | HL_Times_128: 2 | xor a 3 | rr h 4 | rr l 5 | rra 6 | ld h,l 7 | ld l,a 8 | ret 9 | -------------------------------------------------------------------------------- /math/rng/rand10.z80: -------------------------------------------------------------------------------- 1 | rand10: 2 | ;Returns A as a random integer on [0,9] 3 | ;Destroys: All 4 | call rand5 5 | sla h 6 | rla 7 | ret 8 | -------------------------------------------------------------------------------- /conversion/A_To_ASCII_Char.z80: -------------------------------------------------------------------------------- 1 | ;converts the low nibble of A to an ASCII char. 2 | and $0F 3 | add a,$90 4 | daa 5 | adc a,$40 6 | daa 7 | -------------------------------------------------------------------------------- /ti8x/gfx/pixelOn.z80: -------------------------------------------------------------------------------- 1 | pixelOn: 2 | ;(B,C) is (x,y) 3 | 4 | call getpixelloc 5 | ret nc ;Exit if the coordinates are out-of-bounds 6 | or (hl) 7 | ld (hl),a 8 | ret 9 | -------------------------------------------------------------------------------- /ti8x/gfx/pixelToggle.z80: -------------------------------------------------------------------------------- 1 | pixelToggle: 2 | ;(B,C) is (x,y) 3 | 4 | call getpixelloc 5 | ret nc ;Exit if the coordinates are out-of-bounds 6 | xor (hl) 7 | ld (hl),a 8 | ret 9 | -------------------------------------------------------------------------------- /utility/strcopy.z80: -------------------------------------------------------------------------------- 1 | ;author: calcmaniac84, I think 2 | ;Copy zero terminated string at HL to DE. 3 | strcopy: 4 | xor a 5 | docopystr: 6 | cp (hl) 7 | ldi 8 | jr nz,docopystr 9 | ret 10 | -------------------------------------------------------------------------------- /math/misc/D_compare_E_signed.z80: -------------------------------------------------------------------------------- 1 | ;Signed Compare D to E! 2 | ;Returns carry and zero flag as expected 3 | ;Destroys A. 4 | ld a,d 5 | sub e 6 | sbc a,a 7 | xor e 8 | xor d 9 | rla 10 | -------------------------------------------------------------------------------- /misc/mask_least_bit.z80: -------------------------------------------------------------------------------- 1 | ;masks the lowest bit in C 2 | ;Ex. If c=%10110100, this would return a=%00000100 3 | ; (it also always returns nc, and z only when c=0). 4 | ; 5 | xor a 6 | sub c 7 | and c 8 | -------------------------------------------------------------------------------- /ti8x/gfx/pixelOff.z80: -------------------------------------------------------------------------------- 1 | pixelOff: 2 | ;(B,C) is (x,y) 3 | 4 | call getpixelloc 5 | ret nc ;Exit if the coordinates are out-of-bounds 6 | cpl 7 | and (hl) 8 | ld (hl),a 9 | ret 10 | -------------------------------------------------------------------------------- /math/subtraction/A_Minus_HL.z80: -------------------------------------------------------------------------------- 1 | ;via calc84maniac 2 | ;"Optimized routine for HL=A-HL (the negate HL optimization can be derived from this by setting A=0 first)" 3 | sub l 4 | ld l,a 5 | sbc a,a 6 | sub h 7 | ld h,a 8 | -------------------------------------------------------------------------------- /conversion/toUpper.z80: -------------------------------------------------------------------------------- 1 | toUpper: 2 | ;A is the char. 3 | ;If A is a lowercase letter, this sets it to the matching uppercase 4 | ;18cc or 30cc or 41cc 5 | ;avg: 26.75cc 6 | cp 'a' 7 | ret c 8 | cp 'z'+1 9 | ret nc 10 | sub 'a'-'A' 11 | ret 12 | -------------------------------------------------------------------------------- /ti8x/gfx/fillgbuf_faster.z80: -------------------------------------------------------------------------------- 1 | clrgbuf: 2 | ;Input: HL points to the gbuf 3 | xor a 4 | fillgbuf: 5 | ;Input: HL points to the gbuf, A is the byte to fill with. 6 | ld bc,767 7 | ld (hl),a 8 | ld d,h 9 | ld e,l 10 | inc de 11 | ldir 12 | ret 13 | -------------------------------------------------------------------------------- /ti8x/gfx/pixelTest.z80: -------------------------------------------------------------------------------- 1 | pixelTest: 2 | ;(B,C) is (x,y) 3 | ;Returns z if the pixel is off, nz if it is on. 4 | 5 | call getpixelloc 6 | jr nc,+_ 7 | and (hl) 8 | ret 9 | _: 10 | xor a ;or maybe you want to return nz for out-of-bounds? 11 | ret 12 | -------------------------------------------------------------------------------- /math/rng/lfsr.z80: -------------------------------------------------------------------------------- 1 | LFSR: 2 | ;13 bytes 3 | ;72cc (66cc if using SMC) 4 | ;period is 65535 5 | #ifdef SMC 6 | seed = $+1 7 | ld hl,9797 8 | #else 9 | ld hl,(seed) 10 | #endif 11 | add hl,hl 12 | sbc a,a 13 | and %00101101 14 | xor l 15 | ld l,a 16 | ld (seed),hl 17 | ret 18 | -------------------------------------------------------------------------------- /search/cpstr.z80: -------------------------------------------------------------------------------- 1 | cpstr: 2 | ;Compare two strings at HL and DE 3 | ;returns z if they are equal 4 | ;returns c if DE points to the smaller string 5 | ;returns nc if DE is the bigger (or equal) string. 6 | ld a,(de) 7 | cp (hl) 8 | inc de 9 | inc hl 10 | ret nz 11 | or a 12 | jr nz,cpstr 13 | ret 14 | -------------------------------------------------------------------------------- /ti8x/gfx/fillgbuf.z80: -------------------------------------------------------------------------------- 1 | clrgbuf: 2 | ;Input: HL points to the gbuf 3 | xor a 4 | fillgbuf: 5 | ;Input: HL points to the gbuf, A is the byte to fill with. 6 | ;preserves DE. 7 | ld bc,3 8 | fillgbuf_loop: 9 | ld (hl),a 10 | inc hl 11 | djnz fillgbuf_loop 12 | dec c 13 | jr nz,fillgbuf_loop 14 | ret 15 | -------------------------------------------------------------------------------- /utility/stringlength_8bit.z80: -------------------------------------------------------------------------------- 1 | stringlength_8bit: 2 | ; Input: HL points to the null-terminated string (less than 256 bytes long) 3 | ; Output: A is the length of the string 4 | xor a 5 | ld c,a 6 | cpir 7 | sub c 8 | ; dec a ; comment if the null byte is supposed to be included in the length 9 | ret 10 | -------------------------------------------------------------------------------- /ti8x/utility/batterylevel_basic.z80: -------------------------------------------------------------------------------- 1 | ;Name: BatteryStatus 2 | ;Description: Returns if the batteries are good, or low and need changing. 3 | ;Inputs: None 4 | ;Outputs: Non-Zero = Good Batteries 5 | ; Zero = Batteries Low 6 | ;Destroys: A 7 | 8 | GetBatteryStatus: 9 | in a, (2) 10 | and 01h 11 | ret 12 | -------------------------------------------------------------------------------- /math/division/div9.z80: -------------------------------------------------------------------------------- 1 | div9: 2 | ;HL/9 --> A, HL<256*9 3 | inc hl 4 | ld d,h 5 | ld e,l 6 | add hl,hl 7 | add hl,de 8 | add hl,hl 9 | add hl,de 10 | ld e,0 11 | ld d,l 12 | ld a,h 13 | add hl,hl 14 | add hl,hl 15 | add hl,de 16 | adc a,e 17 | add hl,hl 18 | rla 19 | add hl,hl 20 | rla 21 | ret 22 | -------------------------------------------------------------------------------- /math/division/EHL_Div_D.z80: -------------------------------------------------------------------------------- 1 | EHL_Div_D: 2 | ;1360+24({0,3+{0,3}}) 3 | ;min: 1360cc 4 | ;max: 1504cc 5 | ;avg: 1414cc 6 | ;17 bytes 7 | xor a 8 | ld b,24 9 | _: 10 | add hl,hl 11 | rl e 12 | rla 13 | jr c,$+5 ;if D is guaranteed <129, can omit this 14 | cp d 15 | jr c,$+4 16 | sub d 17 | inc l 18 | djnz -_ 19 | ret 20 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | Scavenge code from 2 | Z80 Bits http://map.grauw.nl/sources/external/z80bits.html 3 | Z80 Heaven http://z80-heaven.wikidot.com/forum/t-676164/column-major-graphics-buffer-format 4 | z80float https://github.com/Zeda/z80float 5 | Grammer https://github.com/Zeda/Grammer2 6 | Axe 7 | Doors CS7 https://github.com/KermMartian/Doors_CS_7 8 | -------------------------------------------------------------------------------- /conversion/reverseHL.z80: -------------------------------------------------------------------------------- 1 | ;Reverses the bits in HL 2 | ;author: calcmaniac84 3 | 4 | reverseHL: 5 | ;28 bytes and 112 cycles (with RET: 29 bytes, 122cc) 6 | ld a,l 7 | rla 8 | rr h 9 | rla 10 | rr h 11 | rla 12 | rr h 13 | rla 14 | rr h 15 | rla 16 | rr h 17 | rla 18 | rr h 19 | rla 20 | rr h 21 | rla 22 | rr h 23 | rla 24 | rrca 25 | ld l,a 26 | ret 27 | -------------------------------------------------------------------------------- /math/rng/lfsr64.z80: -------------------------------------------------------------------------------- 1 | lfsr64: 2 | ;;Output: A is an 8-bit pseudo-random number. 3 | ld hl,seed 4 | sla (hl) \ inc hl 5 | rl (hl) \ inc hl 6 | rl (hl) \ inc hl 7 | rl (hl) \ inc hl 8 | rl (hl) \ inc hl 9 | rl (hl) \ inc hl 10 | rl (hl) \ inc hl 11 | rl (hl) 12 | ret nc 13 | ld a,(seed) 14 | xor %000011011 15 | ld (seed),a 16 | ret 17 | 18 | -------------------------------------------------------------------------------- /conversion/reverseA.z80: -------------------------------------------------------------------------------- 1 | ;Reverses the bits in A 2 | ;author: calcmaniac84 3 | 4 | reversea: 5 | ;input: Byte in A 6 | ;output: Reversed byte in A 7 | ;destroys B 8 | ;Clock cycles: 66 9 | ;Bytes: 18 10 | ld b,a 11 | rrca 12 | rrca 13 | xor b 14 | and %10101010 15 | xor b 16 | ld b,a 17 | rrca 18 | rrca 19 | rrca 20 | rrca 21 | xor b 22 | and %01100110 23 | xor b 24 | rrca 25 | ret 26 | -------------------------------------------------------------------------------- /math/division/C_Div_D.z80: -------------------------------------------------------------------------------- 1 | C_Div_D: 2 | ;Inputs: 3 | ; C is the numerator 4 | ; D is the denominator 5 | ;Outputs: 6 | ; A is the remainder 7 | ; B is 0 8 | ; C is the result of C/D 9 | ; D,E,H,L are not changed 10 | ; 11 | ld b,8 12 | xor a 13 | C_Div_D_loop: 14 | sla c 15 | rla 16 | cp d 17 | jr c,+_ 18 | inc c 19 | sub d 20 | _: 21 | djnz C_Div_D_loop 22 | ret 23 | -------------------------------------------------------------------------------- /ti8x/gfx/plotpixel.z80: -------------------------------------------------------------------------------- 1 | plotpixel: 2 | ; (B,C) is (x,y) 3 | ; A is the method: 4 | ; 0 is white 5 | ; 1 is black 6 | ; 2 is inverted 7 | ; 3+ is a pixel test (returns z if off, nz if on) 8 | 9 | inc a 10 | push af 11 | call getpixelloc 12 | pop bc 13 | djnz $+3 \ or (hl) 14 | djnz $+3 \ xor (hl) 15 | djnz $+3 \ and (hl) 16 | djnz $+4 \ cpl \ and (hl) 17 | ld (hl),a 18 | ret 19 | -------------------------------------------------------------------------------- /utility/swapbytes.z80: -------------------------------------------------------------------------------- 1 | swapbytes: 2 | ;Swaps BC bytes pointed to by HL and DE 3 | ;Inputs: 4 | ; HL points to a spot in memory 5 | ; DE points to a spot in memory 6 | ; BC number of bytes to swap 7 | ;Outputs: 8 | ; A is 0 9 | ; BC is 0 10 | ; HL is incremented BC times 11 | ; DE is incremented BC times 12 | ; 13 | ld a,(de) 14 | ldi 15 | dec hl 16 | ld (hl),a 17 | inc hl 18 | jp pe,swapbytes 19 | ret 20 | -------------------------------------------------------------------------------- /math/division/HL_Div_384.z80: -------------------------------------------------------------------------------- 1 | HL_Div_384: 2 | ;223cc 3 | ;(HL+HL*5*17*2)/256 4 | push hl 5 | ld b,h 6 | ld c,l 7 | xor a 8 | add hl,hl \ rl a 9 | add hl,hl \ rl a 10 | add hl,bc \ adc a,0 11 | ld d,a 12 | ld b,h 13 | ld c,l 14 | add hl,hl \ rl a 15 | add hl,hl \ rl a 16 | add hl,hl \ rl a 17 | add hl,hl \ rl a 18 | add hl,bc \ adc a,d 19 | add hl,hl \ rla 20 | pop de 21 | add hl,hl \ rl a 22 | sla l 23 | adc a,0 24 | ret -------------------------------------------------------------------------------- /utility/stringlength.z80: -------------------------------------------------------------------------------- 1 | stringlength: 2 | ;Inputs: 3 | ; HL points to the null-terminated string 4 | ;Outputs: 5 | ; BC is the length of the string 6 | ; HL points to the byte after the null-byte 7 | ;Destroys: 8 | ; A 9 | ;speed: 41+21n 10 | ;12 bytes 11 | xor a 12 | ld c,a 13 | ld b,a 14 | cpir 15 | scf ;comment this if the NULL byte should be counted 16 | sbc a,c 17 | ld c,a 18 | sbc a,a 19 | sub b 20 | ld b,a 21 | ret 22 | -------------------------------------------------------------------------------- /conversion/inflateA.z80: -------------------------------------------------------------------------------- 1 | ;I have no idea what to call this. 2 | ;It was created by calc84maniac 3 | 4 | inflateA: 5 | ;in: a = ABCDEFGH 6 | ;out: hl= AABBCCDDEEFFGGHH 7 | rrca 8 | rra 9 | rra 10 | ld l,a 11 | rra 12 | sra l 13 | rla 14 | rr l 15 | sra l 16 | rra 17 | rr l 18 | sra l 19 | 20 | rrca 21 | rra 22 | rra 23 | ld h,a 24 | rra 25 | sra h 26 | rla 27 | rr h 28 | sra h 29 | rra 30 | rr h 31 | sra h 32 | ret 33 | -------------------------------------------------------------------------------- /ti8x/gfx/shiftleft_v.z80: -------------------------------------------------------------------------------- 1 | ;written by Zeda 2 | ;Shift a vertically aligned buffer left 3 | 4 | 5 | shiftleft: 6 | ld ix,buf0+768-65 7 | ld b,64 8 | shiftleftloop: 9 | sla (ix+64) \ rl (ix) \ rl (ix-64) \ rl (ix-128) \ dec ixh ;100 10 | rl (ix+64) \ rl (ix) \ rl (ix-64) \ rl (ix-128) \ dec ixh ;100 11 | rl (ix+64) \ rl (ix) \ rl (ix-64) \ rl (ix-128) ;92 12 | inc ixh \ inc ixh \ dec ix ; 26 13 | djnz shiftleftloop 14 | ret 15 | -------------------------------------------------------------------------------- /ti8x/gfx/shiftgbufright4.z80: -------------------------------------------------------------------------------- 1 | shiftgraphright4: 2 | ; Shifts the contents of plotSScreen right 4 pixels 3 | ;29846cc 4 | ld hl,plotSScreen 5 | 6 | shiftgbufright4: 7 | ; HL points to the horizontally aligned gbuf 8 | ; Shifts the contents right 4 pixels, shifting in zeros. 9 | ;29836cc 10 | ;14 bytes 11 | ld c,64 12 | shiftgbufright4_loop: 13 | xor a 14 | ld b,12 15 | 16 | rrd \ inc hl \ djnz $-3 17 | 18 | dec c 19 | jr nz,shiftgbufright4_loop 20 | ret 21 | -------------------------------------------------------------------------------- /math/misc/A_mod_3.z80: -------------------------------------------------------------------------------- 1 | A_mod_3: 2 | ;destroys HL, returns A mod 3 in A 3 | ;97+{0,2} + {0,8} + {0,1} 4 | ;min: 97 5 | ;max: 108 6 | ;avg: 102.5 7 | ld h,$C0 8 | ld l,a ;save a copy of a 9 | add a,a 10 | add a,a 11 | add a,a 12 | add a,a 13 | add a,l 14 | jr nc,$+4 15 | add a,16 16 | 17 | ld l,a 18 | add a,a 19 | add a,a 20 | and h 21 | add a,l 22 | 23 | jr nc,$+3 24 | sub h 25 | 26 | and h 27 | rlca 28 | rlca 29 | ret po 30 | xor a 31 | ret 32 | -------------------------------------------------------------------------------- /math/misc/A_divisible_by_3.z80: -------------------------------------------------------------------------------- 1 | A_divisible_by_3: 2 | ;Inputs: A 3 | ;Outputs: pe if A was divisible by 3, po if A was not divisible by 3 4 | ;Destroys: HL 5 | ;88+{0,2}+{0,1} 6 | ;min: 88 7 | ;max: 91 8 | ;avg: 89.5 9 | ld h,$C0 10 | ld l,a ;save a copy of a 11 | add a,a 12 | add a,a 13 | add a,a 14 | add a,a 15 | add a,l 16 | jr nc,$+4 17 | add a,16 18 | ld l,a 19 | add a,a 20 | add a,a 21 | and h 22 | add a,l 23 | jr nc,$+3 24 | sub h 25 | and h 26 | ret 27 | -------------------------------------------------------------------------------- /ti8x/gfx/shiftgbufleft4.z80: -------------------------------------------------------------------------------- 1 | shiftgraphright4: 2 | ; Shifts the contents of plotSScreen right 4 pixels 3 | ;29846cc 4 | ld hl,plotSScreen+767 5 | 6 | shiftgbufright4: 7 | ; HL points to the last byte of a horizontally aligned gbuf 8 | ; Shifts the contents left 4 pixels, shifting in zeros. 9 | ;29836cc 10 | ;14 bytes 11 | ld c,64 12 | shiftgbufright4_loop: 13 | xor a 14 | ld b,12 15 | 16 | rld \ dec hl \ djnz $-3 17 | 18 | dec c 19 | jr nz,shiftgbufright4_loop 20 | ret 21 | -------------------------------------------------------------------------------- /ti8x/gfx/horizontal.z80: -------------------------------------------------------------------------------- 1 | ;Fast Horizontal Line 2 | 3 | 4 | horizontal: 5 | ;Input: 6 | ; A is the row 7 | ;Output: 8 | ; Horizontal line at A 9 | ld bc,plotSScreen 10 | horizontal_buf: 11 | ;Input: 12 | ; A is the row 13 | ; BC is the buffer 14 | ;Output: 15 | ; Horizontal line at A 16 | ld l,a 17 | ld h,0 18 | add a,a 19 | add a,l 20 | ld l,a 21 | add hl,hl 22 | add hl,hl 23 | add hl,bc 24 | ld bc,$0CFF 25 | _: 26 | ld (hl),c 27 | inc hl 28 | djnz -_ 29 | ret 30 | -------------------------------------------------------------------------------- /ti8x/utility/checkkey.z80: -------------------------------------------------------------------------------- 1 | checkkey: 2 | ;Input: A is the key code 3 | ;Output: z flag is set if the key is pressed, reset otherwise. 4 | ;32 bytes 5 | sub 1 6 | ret c 7 | ld b,a 8 | and 7 9 | ld c,a 10 | xor b 11 | rra 12 | rra 13 | rra 14 | ld b,a 15 | inc b 16 | ld a,$7F 17 | rlca 18 | djnz $-1 19 | out (1),a ;set the group, now get the key 20 | ld b,c 21 | inc b 22 | ld a,$80 23 | rlca 24 | djnz $-1 25 | ld c,a 26 | in a,(1) 27 | and c 28 | ret 29 | -------------------------------------------------------------------------------- /utility/stringlength_smaller.z80: -------------------------------------------------------------------------------- 1 | ;This version returns the string length without the null byte 2 | stringlength: 3 | ; Input: HL points to the null-terminated string 4 | ; Output: HL is the length of the string 5 | ;speed: 40cc+21n (+4cc if `scf` is uncommented) 6 | ;10 bytes (+1 byte if `scf` is uncommented) 7 | xor a 8 | ld d,h 9 | ld e,l 10 | ld b,a 11 | ld c,a 12 | cpir 13 | ;scf ; comment if the null byte is supposed to be included in the length 14 | sbc hl,de 15 | ret 16 | -------------------------------------------------------------------------------- /math/division/sdiv16.z80: -------------------------------------------------------------------------------- 1 | ;Adapted from Axe 2 | 3 | p_SDiv: 4 | ld a,h 5 | xor d 6 | push af 7 | xor d 8 | jp p,__SDivSkip1 9 | xor a 10 | sub l 11 | ld l,a 12 | sbc a,a 13 | sub h 14 | ld h,a 15 | __SDivSkip1: 16 | bit 7,d 17 | jr z,__SDivSkip2 18 | xor a 19 | sub e 20 | ld e,a 21 | sbc a,a 22 | sub d 23 | ld d,a 24 | __SDivSkip2: 25 | call div16 ;normal routine division 26 | pop af 27 | ret p 28 | xor a 29 | sub l 30 | ld l,a 31 | sbc a,a 32 | sub h 33 | ld h,a 34 | ret 35 | -------------------------------------------------------------------------------- /math/division/HL_Div_3_round.z80: -------------------------------------------------------------------------------- 1 | HL_Div_3_round: 2 | ;205cc or 215cc 3 | xor a \ ld d,h \ ld e,l 4 | add hl,hl \ rla 5 | add hl,hl \ rla 6 | add hl,de 7 | ld d,h \ ld e,l \ ld b,a 8 | add hl,hl \ rla 9 | add hl,hl \ rla 10 | add hl,hl \ rla 11 | add hl,hl \ rla 12 | add hl,de \ adc a,bas 13 | ld d,h \ ld e,l \ ld b,a 14 | ld d,a \ ld e,h \ add hl,de 15 | adc a,0 16 | sla l 17 | ld l,h 18 | ld h,a 19 | ret nc 20 | inc hl 21 | ret 22 | 23 | -------------------------------------------------------------------------------- /utility/im2setup.z80: -------------------------------------------------------------------------------- 1 | ;This is a routine to set up an IM 2 interrupt 2 | ;This example sets the vector table at 0x9900 through 0x9A00 and a jump to the actual routine at 0x9A9A 3 | ;Created by calc84maniac 4 | setupim2: 5 | di 6 | ld a,$99 7 | ld bc,$0100 8 | ld h,a 9 | ld d,a 10 | ld l,c 11 | ld e,b 12 | ld i,a 13 | inc a 14 | ld (hl),a 15 | ldir 16 | ld l,a 17 | ld (hl),$c3 18 | inc l 19 | ld (hl),intvec & $ff 20 | inc l 21 | ld (hl),intvec >> 8 22 | im 2 23 | ei 24 | ret 25 | -------------------------------------------------------------------------------- /math/division/BC_Div_DE_sizeopt.z80: -------------------------------------------------------------------------------- 1 | BC_Div_DE: 2 | ;BC/DE ==> BC, remainder in HL 3 | ;min: 1166cc 4 | ;max: 1310cc 5 | ;avg: 1238cc 6 | ;22 bytes 7 | ld hl,0 8 | ld a,b 9 | ld b,16 10 | 11 | div_loop: 12 | ;shift the bits from BC into HL 13 | sla c \ rla 14 | adc hl,hl 15 | sbc hl,de 16 | jr nc,div_inc_acc 17 | add hl,de 18 | .db $FE ;this begins the instruction `cp *`, so it eats the next byte. 19 | div_inc_acc: 20 | inc c 21 | 22 | div_loop_done: 23 | djnz div_loop 24 | ld b,a 25 | ret 26 | -------------------------------------------------------------------------------- /ti8x/utility/set15MHz.z80: -------------------------------------------------------------------------------- 1 | set15MHz: 2 | ;This sets the clock speed to the highest possible for the calc it is running on. 3 | ;At this writing, the highest is 15MHz, but TI had planned on 20MHz and 25MHz, possibly. 4 | ;This routine selects speed 3, which would have been 25MHz. 5 | in a,(2) 6 | add a,a 7 | sbc a,a 8 | out (20h),a 9 | ret 10 | 11 | ; set15MHz: 12 | ; ;This sets the clock speed to 15MHz, but is +3cc, +1 byte. 13 | ; in a,(2) 14 | ; and %10000000 15 | ; rlca 16 | ; out (20h),a 17 | ; ret 18 | -------------------------------------------------------------------------------- /math/squareroot/sqrtfixed_88.z80: -------------------------------------------------------------------------------- 1 | ;Adapted from Axe 2 | 3 | sqrtfixed_88: 4 | ;Inputs: A.C 5 | ;Output: D.E contains the squareroot 6 | ;speed: 1482+12{0,17} 7 | ;min: 1482cc 8 | ;max: 1686cc 9 | ;avg: 1584cc 10 | ;35 bytes 11 | ld b,12 12 | ld de,0 13 | ld h,d 14 | ld l,e 15 | __Sqrt88Loop: 16 | sub $40 17 | sbc hl,de 18 | jr nc,__Sqrt88Skip 19 | add a,$40 20 | adc hl,de 21 | __Sqrt88Skip: 22 | ccf 23 | rl e 24 | rl d 25 | sla c 26 | rla 27 | adc hl,hl 28 | sla c 29 | rla 30 | adc hl,hl 31 | djnz __Sqrt88Loop 32 | ret 33 | -------------------------------------------------------------------------------- /ti8x/gfx/shiftright_v.z80: -------------------------------------------------------------------------------- 1 | ;written by Zeda 2 | ;Shift a vertically aligned buffer right 3 | 4 | shiftright: 5 | ;20446 cc's needed 6 | ld ix,gbuf+128 7 | ld b,64 8 | shiftrightloop: 9 | srl (ix-128) \ rr (ix-64) \ rr (ix) \ rr (ix+64) \ inc ixh ;100 incrementing the MSB of IX is the same as adding 256 10 | rr (ix-128) \ rr (ix-64) \ rr (ix) \ rr (ix+64) \ inc ixh ;100 11 | rr (ix-128) \ rr (ix-64) \ rr (ix) \ rr (ix+64) ;92 12 | dec ixh \ dec ixh \ inc ix ; 26 13 | djnz shiftrightloop 14 | ret 15 | -------------------------------------------------------------------------------- /math/multiplication/DE_Times_A.z80: -------------------------------------------------------------------------------- 1 | DE_Times_A: 2 | ;DE*A ==> AHL 3 | ld hl,0 4 | ld b,h 5 | add a,a \ jr nc,$+5 \ ld h,d \ ld l,e 6 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,b 7 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,b 8 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,b 9 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,b 10 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,b 11 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,b 12 | add hl,hl \ rla \ ret nc \ add hl,de \ adc a,b \ ret 13 | -------------------------------------------------------------------------------- /misc/hotspot2.z80: -------------------------------------------------------------------------------- 1 | ;This version works like the hotspot routine, but takes width and height args 2 | ;instead of a second coord 3 | ;----------Hot spot detection----------- 4 | ;inputs: b,c (upper-left x and y coordinates) 5 | ; d,e (width and height) 6 | ; h,l (current x,y) 7 | ;output: "c" flag [either true (set) or false (reset)] 8 | 9 | ; This routine checks if a point (H,L) is within a box defined by (B,C) and (D,E) 10 | hdetectrect: 11 | ld a,h 12 | sub b 13 | cp d 14 | ret nc 15 | ld a,l 16 | sub c 17 | cp e 18 | ret 19 | -------------------------------------------------------------------------------- /math/division/HL_Div_5_round.z80: -------------------------------------------------------------------------------- 1 | HL_Div_5_round: 2 | ;210cc or 220cc 3 | xor a 4 | ld d,h \ ld e,l \ ld b,a 5 | add hl,hl \ rla 6 | add hl,de \ adc a,b 7 | ld d,h \ ld e,l \ ld c,a 8 | add hl,hl \ rla 9 | add hl,hl \ rla 10 | add hl,hl \ rla 11 | add hl,hl \ rla 12 | add hl,de \ adc a,c 13 | ld d,a \ ld e,h 14 | add hl,de \ adc a,b 15 | ld d,a \ ld e,h 16 | add a,l 17 | ex de,hl 18 | rla \ rla \ and 3 \ rra 19 | adc a,b 20 | add a,l 21 | ld l,a 22 | ret nc 23 | inc h 24 | ret 25 | -------------------------------------------------------------------------------- /math/multiplication/mul8.z80: -------------------------------------------------------------------------------- 1 | H_Times_E: 2 | mul8: 3 | ;Inputs: H,E 4 | ;Outputs: HL is the product, D is 0 5 | ;190+6{0,6}+{0,15}+{0,1} 6 | ;min: 190cc 7 | ;max: 242 8 | ;avg: 216 9 | ;36 bytes 10 | ld d,0 11 | ld l,d 12 | sla h \ jr nc,$+3 \ ld l,e 13 | add hl,hl \ jr nc,$+3 \ add hl,de 14 | add hl,hl \ jr nc,$+3 \ add hl,de 15 | add hl,hl \ jr nc,$+3 \ add hl,de 16 | add hl,hl \ jr nc,$+3 \ add hl,de 17 | add hl,hl \ jr nc,$+3 \ add hl,de 18 | add hl,hl \ jr nc,$+3 \ add hl,de 19 | add hl,hl \ ret nc \ add hl,de \ ret 20 | -------------------------------------------------------------------------------- /math/squareroot/sqrtHL_faster.z80: -------------------------------------------------------------------------------- 1 | ;Adapted from Axe 2 | 3 | sqrtHL: 4 | ;Input: HL 5 | ;Output: D is the square root, cH is the remainder (c being the c flag), A is 0, B is 0, L is 0 6 | ;speed: 758+8{0,6} 7 | ;min: 758cc 8 | ;max: 806cc 9 | ;avg: 782cc 10 | ;26 bytes 11 | p_Sqrt: 12 | ld a,l 13 | ld l,h 14 | ld de,$0040 15 | ld h,d 16 | ld b,8 17 | or a 18 | __SqrtLoop: 19 | sbc hl,de 20 | jr nc,__SqrtSkip 21 | add hl,de 22 | __SqrtSkip: 23 | ccf 24 | rl d 25 | add a,a 26 | adc hl,hl 27 | add a,a 28 | adc hl,hl 29 | djnz __SqrtLoop 30 | ret 31 | -------------------------------------------------------------------------------- /misc/hotspot.z80: -------------------------------------------------------------------------------- 1 | ;License: https://www.cemetech.net/projects/uti/viewtopic.php?t=1279 2 | ;DarkerLine 3 | ;----------Hot spot detection----------- 4 | ;inputs: b,c (first x and y cor) 5 | ; d,e (last x and y cor) 6 | ; h,l (current x,y) 7 | ;output: "c" flag [either true (set) or false (reset)] 8 | ; 9 | ; This routine checks if a point (H,L) is within a box defined by (B,C) and (D,E) 10 | hdetect: 11 | ld a,h 12 | cp b 13 | ccf 14 | ret nc 15 | cp d 16 | ret nc 17 | ld a,l 18 | cp c 19 | ccf 20 | ret nc 21 | cp e 22 | ret 23 | -------------------------------------------------------------------------------- /ti8x/gfx/vertical.z80: -------------------------------------------------------------------------------- 1 | ;Fast Vertical Line 2 | ;Created by calc84maniac 3 | 4 | vertical: 5 | ;Input: 6 | ; A is the column number 7 | ;Output: 8 | ; Vertical line at column A 9 | ;Destroys: 10 | ; AF, BC, DE, HL 11 | ld hl,plotsscreen 12 | ld d,0 13 | ld e,a 14 | srl e 15 | srl e 16 | srl e 17 | add hl,de 18 | and $07 19 | ld b,a 20 | inc b 21 | ld a,1 22 | vertloop1: 23 | rrca 24 | djnz vertloop1 25 | ld c,a 26 | ld b,64 27 | ld e,12 28 | vertloop2: 29 | ld a,c 30 | or (hl) 31 | ld (hl),a 32 | add hl,de 33 | djnz vertloop2 34 | ret 35 | -------------------------------------------------------------------------------- /math/division/DEHL_Div_C.z80: -------------------------------------------------------------------------------- 1 | ;Created by calc84maniac 2 | ;NOTE from Zeda: C should <=128, the original forgot to mention this. 3 | 4 | DEHL_Div_C: 5 | ;Inputs: dehl=32-bit dividend, c<=128 is the divisor (Or is it the other way around?) 6 | ;Outputs: dehl=32-bit quotient, a=remainder, c=unchanged, b=0 7 | ;min: 1936cc 8 | ;max: 2032cc 9 | ;avg: 1984cc 10 | ;Size: 17 bytes 11 | div32bit: 12 | ld b,32 13 | xor a 14 | divloop: 15 | add hl,hl 16 | rl e 17 | rl d 18 | rla 19 | cp c 20 | jr c,divlbl 21 | inc l 22 | sub c 23 | divlbl: 24 | djnz divloop 25 | ret 26 | -------------------------------------------------------------------------------- /math/multiplication/DE_Times_A_to_HL_sizeopt.z80: -------------------------------------------------------------------------------- 1 | DE_Times_A: 2 | ;Inputs: 3 | ; DE and A are factors 4 | ;Outputs: 5 | ; A is not changed 6 | ; B is 0 7 | ; C is not changed 8 | ; DE is not changed 9 | ; HL is the product 10 | ;Time: 11 | ; 342+6x 12 | ;13 bytes 13 | ld b,8 ;7 7 14 | ld hl,0 ;10 10 15 | _: 16 | add hl,hl ;11*8 88 17 | rlca ;4*8 32 18 | jr nc,$+3 ;(12|18)*8 96+6x 19 | add hl,de ;-- -- 20 | djnz -_ ;13*7+8 99 21 | ret ;10 10 22 | -------------------------------------------------------------------------------- /conversion/signed16To8.z80: -------------------------------------------------------------------------------- 1 | ;This amazing routine is by Runer112 2 | ;"Here's a very optimized way to convert a 16-bit signed number into an 8-bit 3 | ;signed number in a with overflow handling (if hl<-128, a=-128; if hl>127, a=127). 4 | ;Two added bonus to being super small and super fast are that it destroys nothing 5 | ;and that you could easily modify it to make the input a 16-bit register other 6 | ;than hl." 7 | 8 | Signed16To8: 9 | ld a,l 10 | add a,a 11 | sbc a,a 12 | sub h 13 | ld a,l 14 | ret z 15 | ld a,h 16 | add a,a 17 | sbc a,a 18 | xor %01111111 19 | ret 20 | -------------------------------------------------------------------------------- /conversion/L_To_BCD.z80: -------------------------------------------------------------------------------- 1 | L_To_BCD: 2 | ;Unrolled 3 | ;Converts the 8-bit register L to binary coded decimal 4 | ;Digits stored in LA (A has the lower 2 digits, L the upper). 5 | ;Inputs: L is the 8-bit unsigned int to convert 6 | ;Output: A has the lower 2 digits (in BCD form), L has the upper 7 | ;Destroys: H,F 8 | ;141cc 9 | ;27 bytes 10 | ld h,0 11 | add hl,hl 12 | add hl,hl 13 | add hl,hl 14 | add hl,hl 15 | ld a,h \ daa \ rl l 16 | adc a,a \ daa \ rl l 17 | adc a,a \ daa \ rl l 18 | adc a,a \ daa \ rl l 19 | adc a,a \ daa \ rl l 20 | ret 21 | -------------------------------------------------------------------------------- /ti8x/VAT/ChkFindSym.z80: -------------------------------------------------------------------------------- 1 | ; This can be used to replace TI-OS' _ChkFindSym 2 | 3 | #ifndef included_ChkFindSym 4 | #define included_ChkFindSym 5 | 6 | #include "ti8x/VAT/VAT_search_named.z80" 7 | #include "ti8x/VAT/findsym.z80" 8 | 9 | ChkFindSym: 10 | ld de,OP1 11 | ChkFindSym_DE: 12 | ex de,hl 13 | ChkFindSym_HL: 14 | ld a,(hl) 15 | and $1F 16 | dec a \ jp z,VAT_search_HL 17 | sub 4 \ jp z,VAT_search_HL 18 | dec a \ jp z,VAT_search_HL 19 | cp 7 \ jp z,VAT_search_HL 20 | sub 15 21 | cp 3 \ jp c,VAT_search_HL 22 | inc hl 23 | jp FindVarSymHL 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /math/multiplication/mul8_faster_smaller.z80: -------------------------------------------------------------------------------- 1 | H_Times_E: 2 | mul8: 3 | ;Inputs: H,E 4 | ;Outputs: HL is the product, D is 0 5 | ;Destroys: A 6 | ;187+6{0,6}+{0,15} 7 | ;min: 187cc 8 | ;max: 238cc 9 | ;avg: 212.5cc 10 | ;35 bytes 11 | ld d,0 12 | sla h 13 | sbc a,a 14 | and e 15 | ld l,a 16 | add hl,hl \ jr nc,$+3 \ add hl,de 17 | add hl,hl \ jr nc,$+3 \ add hl,de 18 | add hl,hl \ jr nc,$+3 \ add hl,de 19 | add hl,hl \ jr nc,$+3 \ add hl,de 20 | add hl,hl \ jr nc,$+3 \ add hl,de 21 | add hl,hl \ jr nc,$+3 \ add hl,de 22 | add hl,hl \ ret nc \ add hl,de \ ret 23 | -------------------------------------------------------------------------------- /ti8x/gfx/getpixelloc.z80: -------------------------------------------------------------------------------- 1 | GetPixelloc: 2 | ;Input: (B,C) is (X,Y) 3 | ;Output: A is the mask, HL is the byte the pixel is on, nc if out-of-bounds, B=0 4 | ;Destroys: C 5 | 6 | ;Check bounds 7 | ld a,c 8 | cp 64 9 | ret nc 10 | ld a,b 11 | cp 96 12 | ret nc 13 | 14 | ld b,0 15 | ld h,b 16 | ld l,c 17 | add hl,hl 18 | add hl,bc 19 | add hl,hl 20 | add hl,hl 21 | ld c,a 22 | srl c 23 | srl c 24 | srl c 25 | add hl,bc 26 | ld bc,plotSScreen 27 | add hl,bc 28 | and 7 29 | ld b,a 30 | ld a,$80 31 | jr z,$+5 32 | rrca 33 | djnz $-1 34 | scf 35 | ret 36 | -------------------------------------------------------------------------------- /math/squareroot/sqrtDE_slower.z80: -------------------------------------------------------------------------------- 1 | sqrtDE: 2 | ;returns HL as the sqrt, DE as the remainder 3 | ;33 bytes 4 | ;min: 928cc 5 | ;max: 1120cc 6 | ;avg: 1024cc 7 | ;928+8{24,0} 8 | 9 | ld b,$80 10 | xor a 11 | ld h,a 12 | ld l,a 13 | sqrt_loop: 14 | srl b 15 | rra 16 | ld c,a 17 | add hl,bc 18 | ex de,hl 19 | sbc hl,de 20 | jr nc,+_ 21 | add hl,de 22 | ex de,hl 23 | or a 24 | sbc hl,bc 25 | .db $DA ;start of jp c,** which is 10cc to skip the next two bytes. 26 | _: 27 | ex de,hl 28 | add hl,bc 29 | srl h 30 | rr l 31 | srl b 32 | rra 33 | jr nc,sqrt_loop 34 | ret 35 | -------------------------------------------------------------------------------- /conversion/atoui8.z80: -------------------------------------------------------------------------------- 1 | atoui8: 2 | strtob: 3 | ;Input: 4 | ; HL is a string, terminated by a non-numeric ASCII char 5 | ;Output: 6 | ; A has the 8-bit value 7 | strtob: 8 | xor a 9 | jr inloop 10 | loop: 11 | ld e,a 12 | ld a,d 13 | add a,a ;double our accumulator 14 | add a,a ;double again (now x4) 15 | add a,d ;add the original (now x5) 16 | add a,a ;double again (now x10) 17 | add a,e ;add in the incoming digit 18 | inc hl 19 | inloop: 20 | ld d,a 21 | ld a,(hl) 22 | sub '9'+1 23 | add 10 24 | jr c,loop 25 | ld a,d 26 | ret 27 | -------------------------------------------------------------------------------- /ti8x/utility/getKey.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_getKey 2 | #define included_getkey 3 | getKey: 4 | ;Input: 5 | ; Expects that interrupts are either off or won't interfere with port 1. 6 | ;Outputs: 7 | ; A is a value from 0 to 56 that is the keypress 8 | ;Destroys: 9 | ; C, DE 10 | ; C is actually 1 11 | ; E is actually a copy of the keypress 12 | ld c,1 13 | ld de,$FEFF 14 | _: 15 | out (c),d 16 | rlc d 17 | ret nc 18 | inc e 19 | in a,(1) 20 | inc a 21 | jr z,-_ 22 | dec a 23 | sla e 24 | sla e 25 | sla e 26 | _: 27 | inc e 28 | rra 29 | jr c,-_ 30 | ld a,e 31 | ret 32 | #endif 33 | -------------------------------------------------------------------------------- /math/multiplication/sqrA.z80: -------------------------------------------------------------------------------- 1 | sqrA: 2 | ;A*A->A 3 | ;Destroys: HL 4 | ;76cc or 79cc or 82cc 5 | ;Avg: 79cc 6 | ;51 bytes 7 | add a,a 8 | add a,a 9 | jr nc,$+4 10 | neg 11 | rrca 12 | rrca 13 | ld l,a 14 | srl l 15 | ld h,sqrLUT/256 16 | jr c,$+4 17 | neg 18 | add a,(hl) 19 | ret 20 | sqrLUT: 21 | ;MUST BE ALIGNED to a 256-byte boundary. 22 | ;Can use: 23 | ; #if 0!=$&255 24 | ; .fill 256-($&255),0 25 | ; #endif 26 | .db $00,$06,$14,$2A,$48,$6E,$9C,$D2 27 | .db $10,$56,$A4,$FA,$58,$BE,$2C,$A2 28 | .db $20,$A6,$34,$CA,$68,$0E,$BC,$72 29 | .db $30,$F6,$C4,$9A,$78,$5E,$4C,$42 30 | -------------------------------------------------------------------------------- /utility/pushpop.z80: -------------------------------------------------------------------------------- 1 | ;Call this routine at the start of a routine and this will push HL,DE,BC, and AF 2 | ;onto the stack, set up a return so that at the end of the calling routine, 3 | ;those registers are restored. 4 | 5 | pushpop: 6 | ;26 bytes, adds 229cc to the calling routine 7 | ex (sp),hl 8 | push de 9 | push bc 10 | push af 11 | push hl 12 | ld hl,pushpopret 13 | ex (sp),hl 14 | push hl 15 | push af 16 | ld hl,12 17 | add hl,sp 18 | ld a,(hl) 19 | inc hl 20 | ld h,(hl) 21 | ld l,a 22 | pop af 23 | ret 24 | pushpopret: 25 | pop af 26 | pop bc 27 | pop de 28 | pop hl 29 | ret 30 | -------------------------------------------------------------------------------- /search/cpstr_nocase_faster.z80: -------------------------------------------------------------------------------- 1 | cpstr_nocase: 2 | ;Compare two strings at HL and DE, with lowercase being equal to uppercase 3 | ;returns z if they are equal 4 | ;returns c if HL points to the smaller string 5 | ;returns nc if HL is the bigger (or equal) string. 6 | ;destroys A,C,DE,HL 7 | ;preserves B 8 | ;31 bytes. 9 | ld a,(de) 10 | cp 'a' 11 | jr c,+_ 12 | cp 'z'+1 13 | jr nc,+_ 14 | sub 'a'-'A' 15 | _: 16 | ld c,a 17 | 18 | ld a,(hl) 19 | cp 'a' 20 | jr c,+_ 21 | cp 'z'+1 22 | jr nc,+_ 23 | sub 'a'-'A' 24 | _: 25 | 26 | cp c 27 | inc de 28 | inc hl 29 | ret nz 30 | or a 31 | jr nz,cpstr 32 | ret 33 | -------------------------------------------------------------------------------- /math/rng/rand16.z80: -------------------------------------------------------------------------------- 1 | ;#define smc ;uncomment if you are using SMC 2 | rand16: 3 | ;collaboration by Zeda with Runer112 4 | ;160cc or 148cc if using SMC 5 | ;26 bytes 6 | ;cycle: 4,294,901,760 (almost 4.3 billion) 7 | #ifdef smc 8 | seed1=$+1 9 | ld hl,9999 10 | #else 11 | ld hl,(seed1) 12 | #endif 13 | ld b,h 14 | ld c,l 15 | add hl,hl 16 | add hl,hl 17 | inc l 18 | add hl,bc 19 | ld (seed1),hl 20 | #ifdef smc 21 | seed2=$+1 22 | ld hl,9999 23 | #else 24 | ld hl,(seed2) 25 | #endif 26 | add hl,hl 27 | sbc a,a 28 | and %00101101 29 | xor l 30 | ld l,a 31 | ld (seed2),hl 32 | add hl,bc 33 | ret 34 | -------------------------------------------------------------------------------- /math/division/HL_Div_5.z80: -------------------------------------------------------------------------------- 1 | HL_Div_5: 2 | ;HL/5 3 | ;HL/4+HL*3*17*257 4 | ;234cc to 245cc 5 | xor a 6 | ld b,h 7 | ld c,l 8 | ld d,a 9 | add hl,hl \ rla 10 | add hl,bc \ adc a,d ;3 11 | add hl,hl \ rla ;6 12 | add hl,hl \ rla ;12 13 | add hl,hl \ rla ;24 14 | add hl,bc \ adc a,d ;25 15 | add hl,hl \ rla ;50 16 | add hl,bc \ adc a,d ;51 17 | ;AHL0+AHL+BC/2 18 | ;AHL*257/256 =AHL+A 19 | srl b \ rr c 20 | srl b \ rr c 21 | ld d,a 22 | ld a,b 23 | add a,l 24 | ld b,a 25 | ld e,h 26 | jr nc,$+3 27 | inc de 28 | add hl,bc 29 | ld a,d 30 | add a,e 31 | ld e,a 32 | ret nc 33 | inc d 34 | ret 35 | -------------------------------------------------------------------------------- /math/division/DEHL_Div_10_fast.z80: -------------------------------------------------------------------------------- 1 | DEHL_Div_10: 2 | ;Inputs: 3 | ; DEHL 4 | ;Outputs: 5 | ; DEHL is the quotient 6 | ; A is the remainder 7 | ; B is the remainder 8 | ; C is 10 9 | ;1300cc~1329cc 10 | ;49 bytes 11 | xor a 12 | ld bc,05F6h 13 | rl d \ rla 14 | rl d \ rla 15 | rl d \ rla 16 | rl d \ rla \ add a,c \ jr c,$+3 \ sub c \ djnz $-7 17 | ld b,8 18 | rl e \ rla \ add a,c \ jr c,$+3 \ sub c \ djnz $-7 19 | ld b,8 20 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c \ djnz $-7 21 | ld b,8 22 | rl l \ rla \ add a,c \ jr c,$+3 \ sub c \ djnz $-7 23 | 24 | adc hl,hl 25 | rl e 26 | rl d 27 | ret 28 | -------------------------------------------------------------------------------- /ti8x/gfx/fillgbuf_very_fast.z80: -------------------------------------------------------------------------------- 1 | clrgbuf: 2 | ;Input: HL points to the gbuf 3 | xor a 4 | fillgbuf: 5 | ;Input: HL points to the gbuf, A is the byte to fill with. 6 | ;NOTE: Disables interrupts! 7 | ;NOTE: Uses Self Modifying Code 8 | 9 | ;Disable interrupts 10 | di 11 | 12 | ;preserve stack pointer 13 | ld (fillgbuf_spsave+1),sp 14 | 15 | ;add 768 to HL 16 | inc h 17 | inc h 18 | inc h 19 | 20 | ;Load HL into SP 21 | ld sp,hl ;6cc 22 | 23 | ;load A into H and L 24 | ld h,a 25 | ld l,a 26 | 27 | ;now for the loop 28 | ld b,128 29 | 30 | _: 31 | push hl 32 | push hl 33 | push hl 34 | djnz -_ 35 | 36 | fillgbuf_spsave: 37 | ld sp,0 38 | ret 39 | -------------------------------------------------------------------------------- /ti8x/utility/dispfixed1616.z80: -------------------------------------------------------------------------------- 1 | #include "conversion/fixed1616_to_str.z80" 2 | dispfixed1616: 3 | ;Inputs: 4 | ; DE.BC is an 8.8 fixed-point number 5 | ;Output: 6 | ; DE.BC is printed to the screen at (curCol, curRow) 7 | ; curCol is set to 0 8 | ; curRow is advanced. 9 | ; If curRow is 8, then the contents of the homescreen 10 | ; are shifted up one row and curRow is set to 7. 11 | ;Destroys: 12 | ; 9 bytes at OP1 13 | ;Notes: Preserves registers. 14 | push hl 15 | push de 16 | push bc 17 | push af 18 | ld hl,OP1 19 | call fixed1616_to_str 20 | bcall(_PutS) 21 | bcall(_NewLine) 22 | pop af 23 | pop bc 24 | pop de 25 | pop hl 26 | ret 27 | -------------------------------------------------------------------------------- /ti8x/utility/dispfixed88.z80: -------------------------------------------------------------------------------- 1 | #include "conversion/fixed88_to_str.z80" 2 | dispfixed88: 3 | ;Inputs: 4 | ; H.L is an 8.8 fixed-point number 5 | ;Output: 6 | ; H.L is printed to the screen at (curCol, curRow) 7 | ; curCol is set to 0 8 | ; curRow is advanced. 9 | ; If curRow is 8, then the contents of the homescreen 10 | ; are shifted up one row and curRow is set to 7. 11 | ;Destroys: 12 | ; 9 bytes at OP1 13 | ;Notes: Preserves registers. 14 | push hl 15 | push de 16 | push bc 17 | push af 18 | ex de,hl 19 | ld hl,OP1 20 | call fixed88_to_str 21 | bcall(_PutS) 22 | bcall(_NewLine) 23 | pop af 24 | pop bc 25 | pop de 26 | pop hl 27 | ret 28 | -------------------------------------------------------------------------------- /math/division/HL_Div_C_round.z80: -------------------------------------------------------------------------------- 1 | HL_Div_C_round: 2 | ;Inputs: 3 | ; HL is the numerator 4 | ; C<128 is the denominator 5 | ;Outputs: 6 | ; A is twice the remainder of the unrounded value 7 | ; B is 0 8 | ; C is not changed 9 | ; DE is not changed 10 | ; HL is the rounded quotient 11 | ; c flag set means no rounding was performed 12 | ; reset means the value was rounded 13 | ; 14 | ld b,16 15 | xor a 16 | add hl,hl 17 | rla 18 | cp c 19 | jr c,$+4 20 | inc l 21 | sub c 22 | djnz $-7 23 | add a,a 24 | cp c 25 | ret c 26 | inc hl 27 | ret 28 | -------------------------------------------------------------------------------- /math/multiplication/DEBC_Times_A.z80: -------------------------------------------------------------------------------- 1 | DEBC_Times_A: 2 | ;Inputs: 3 | ; DEBC is a 32-bit multiplicand 4 | ; A is an 8-bit multiplicand 5 | ;Outputs: 6 | ; AHLIX is the 40-bit result 7 | ; carry reset 8 | ; z set if top 8 bits are 0 9 | ; sign flag set as expected 10 | ;=============================================================== 11 | 12 | ;503+8{0,41} 13 | ;min: 503cc 14 | ;max: 831cc 15 | ;avg: 667cc 16 | ;29 bytes 17 | ld hl,0 18 | ld ix,0 19 | call +_ 20 | _: 21 | ;231+4{0,41} 22 | call +_ 23 | _: 24 | ;107+2{0,41} 25 | call +_ 26 | _: 27 | ;45+{0,41} 28 | add ix,ix 29 | adc hl,hl 30 | adc a,a 31 | ret nc 32 | add ix,bc 33 | adc hl,de 34 | adc a,0 35 | ret 36 | -------------------------------------------------------------------------------- /math/subtraction/BC_Minus_A.z80: -------------------------------------------------------------------------------- 1 | ;written by calc84maniac 2 | ;comment from calc84maniac: 3 | ; To clarify why I did a cpl/scf/adc instead of a cpl/inc/add or neg/add, 4 | ; is that it handles the case of A=0 properly. Typically, SUB N and 5 | ; ADD A,-N give opposite carry outputs, but SUB 0 and ADD A,-0 both reset the 6 | ; carry flag. On the other hand, SCF \ ADC A,255 will set the carry flag like 7 | ; we want it to. 8 | 9 | ;NOTE: This is an in-line routine-- there is no RET 10 | cpl 11 | scf 12 | adc a,c 13 | ld c,a 14 | jr c,$+3 15 | dec b 16 | 17 | 18 | ; Here is a callable routine: 19 | cpl 20 | scf 21 | adc a,c 22 | ld c,a 23 | ret c 24 | dec b 25 | ret 26 | -------------------------------------------------------------------------------- /math/multiplication/sqr_L.z80: -------------------------------------------------------------------------------- 1 | L_sqrd: 2 | ;Input: L 3 | ;Output: L*L->A 4 | ;147 t-states 5 | ;36 bytes 6 | ld b,l 7 | ;First iteration, get the lowest 3 bits of -x^2 8 | sla l 9 | rrc b 10 | sbc a,a 11 | or l 12 | ld c,a 13 | ;second iteration, get the next 2 bits of -x^2 14 | rrc b 15 | sbc a,a 16 | xor l 17 | and $F8 18 | add a,c 19 | ld c,a 20 | ;third iteration, get the next 2 bits of -x^2 21 | sla l 22 | rrc b 23 | sbc a,a 24 | xor l 25 | and $E0 26 | add a,c 27 | ld c,a 28 | ;fourth iteration, get the eight bit of x^2 29 | sla l 30 | rrc b 31 | sbc a,a 32 | xor l 33 | and $80 34 | sub c 35 | ret 36 | -------------------------------------------------------------------------------- /utility/diRestore.z80: -------------------------------------------------------------------------------- 1 | ;Call this from a routine. 2 | ;This disables interrupts, but sets up a return routine that restores interrupts 3 | ;to the state they were in previously. Very useful if an environment may need 4 | ;interrupts enabled, but your routine needs them disabled. 5 | 6 | diRestore: 7 | ex (sp),hl 8 | push hl 9 | push af 10 | ld hl,restoreei 11 | ld a,r 12 | jp pe,+_ 13 | dec hl 14 | dec hl 15 | _: 16 | di 17 | inc sp 18 | inc sp 19 | inc sp 20 | inc sp 21 | ex (sp),hl 22 | dec sp 23 | dec sp 24 | dec sp 25 | dec sp 26 | pop af 27 | ret 28 | restoredi: 29 | di 30 | ret 31 | restoreei: 32 | ei 33 | ret 34 | -------------------------------------------------------------------------------- /math/division/HL_Div_3_better.z80: -------------------------------------------------------------------------------- 1 | HL_Div_3: 2 | ;HL/3 --> DE 3 | ;209cc to 219cc 4 | xor a 5 | ld b,a 6 | ld d,h 7 | ld e,l 8 | add hl,hl \ rla 9 | add hl,hl \ rla 10 | add hl,de \ adc a,b 11 | add hl,hl \ rla 12 | add hl,hl \ rla 13 | add hl,de \ adc a,b 14 | add hl,hl \ rla 15 | add hl,hl \ rla 16 | add hl,de \ adc a,b 17 | ;AHL+(AHL+(DE>>1))/256 18 | srl d \ rr e 19 | ;AHL+(AHL+DE)/256 20 | ;AH.L+A.HL+.DE 21 | ld b,h 22 | ld c,l 23 | ;AB.C+A.HL+.DE 24 | add hl,de 25 | ;AB.C+A.HL+carry 26 | ld d,a 27 | ;DB.C+A.H+carry 28 | adc a,b 29 | ld e,a 30 | jr nc,$+3 31 | inc d 32 | ;DE.C+0.H+carry 33 | ld a,h 34 | add a,c 35 | ex de,hl 36 | ret nc 37 | inc hl 38 | ret 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 1. This License does not apply to any file with a separate License header. 2 | 2. Permission is granted, free of charge, to use, modify, and/or distribute any part of this software for any purpose. 3 | 4 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 5 | 6 | Written by Zeda Thomas , Aug 2019 7 | -------------------------------------------------------------------------------- /math/misc/HL_divisible_by_3.z80: -------------------------------------------------------------------------------- 1 | HL_divisible_by_3: 2 | ;Inputs: HL 3 | ;Outputs: pe if HL was divisible by 3, else po. 4 | ;Destroys: HL 5 | ;103+{0,2}+{0,1} 6 | ;min: 103 7 | ;max: 106 8 | ;avg: 104.5 9 | ld a,h 10 | add a,l 11 | adc a,0 12 | 13 | A_divisible_by_3: 14 | ;Inputs: A 15 | ;Outputs: pe if A was divisible by 3, po if A was not divisible by 3 16 | ;Destroys: HL 17 | ;88+{0,2}+{0,1} 18 | ;min: 88 19 | ;max: 91 20 | ;avg: 89.5 21 | ld h,$C0 22 | ld l,a ;save a copy of a 23 | add a,a 24 | add a,a 25 | add a,a 26 | add a,a 27 | add a,l 28 | jr nc,$+4 29 | add a,16 30 | ld l,a 31 | add a,a 32 | add a,a 33 | and h 34 | add a,l 35 | jr nc,$+3 36 | sub h 37 | and h 38 | ret 39 | -------------------------------------------------------------------------------- /ti8x/utility/typewritertext.z80: -------------------------------------------------------------------------------- 1 | ;NOTE: This routine may be under a different License. 2 | ;posted in this topic: https://www.cemetech.net/projects/uti/viewtopic.php?t=1279&postdays=0&postorder=asc&start=0 3 | ;with the rule: 4 | ; "3) By posting a routine you're granting everyone the right to use it freely." 5 | 6 | ;WikiGuru, optimized by DarkerLine, then Zeda 7 | ;input: hl points to string (optional argument: b to set type speed) 8 | ;output: string displayed at set location (must set penrow and pencol before calling) 9 | ;destroyed: all but c 10 | 11 | type: 12 | ld a,(hl) 13 | or a 14 | ret z 15 | inc hl 16 | ld b,30 17 | ei 18 | pause: 19 | halt 20 | djnz pause 21 | bcall(_VPutMap) 22 | jr type 23 | -------------------------------------------------------------------------------- /ti8x/gfx/getpixelloc_faster.z80: -------------------------------------------------------------------------------- 1 | pixLUT: 2 | .db $80,$40,$20,$10,$08,$04,$02,$01 3 | 4 | getpixelloc: 5 | ;Input: (B,C) is (X,Y) 6 | ;Output: A is the mask, HL is the byte the pixel is on, nc if out-of-bounds, B=0 7 | ;Destroys: C 8 | 9 | ;Check bounds 10 | ld a,c 11 | cp 64 12 | ret nc 13 | ld a,b 14 | cp 96 15 | ret nc 16 | 17 | ld b,0 18 | ld h,b 19 | ld l,c 20 | add hl,hl 21 | add hl,bc 22 | add hl,hl 23 | add hl,hl 24 | ld c,a 25 | srl c 26 | srl c 27 | srl c 28 | add hl,bc 29 | ld bc,plotSScreen 30 | add hl,bc 31 | 32 | and 7 33 | ld bc,pixLUT 34 | add a,c 35 | ld c,a 36 | #if (pixLUT&255)>248 37 | jr nc,$+3 38 | inc b 39 | #endif 40 | ld a,(bc) 41 | scf 42 | ret 43 | -------------------------------------------------------------------------------- /ti8x/utility/dispi8.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_dispi8 2 | #define included_dispi8 3 | 4 | #include "conversion/itoa_8.z80" 5 | 6 | dispi8: 7 | ;Inputs: 8 | ; A is an 8-bit signed integer to display 9 | ;Output: 10 | ; A is printed to the screen at (curCol, curRow) 11 | ; curCol is set to 0 12 | ; curRow is advanced. 13 | ; If curRow is 8, then the contents of the homescreen 14 | ; are shifted up one row and curRow is set to 7. 15 | ;Destroys: 16 | ; 5 bytes at OP1 17 | ;Notes: Preserves registers. 18 | push hl 19 | push de 20 | push bc 21 | push af 22 | ld hl,OP1 23 | call itoa_8 24 | bcall(_PutS) 25 | bcall(_NewLine) 26 | pop af 27 | pop bc 28 | pop de 29 | pop hl 30 | ret 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /search/cpstr_nocase.z80: -------------------------------------------------------------------------------- 1 | cpstr_nocase: 2 | ;Compare two strings at HL and DE, with lowercase being equal to uppercase 3 | ;returns z if they are equal 4 | ;returns c if HL points to the smaller string 5 | ;returns nc if HL is the bigger (or equal) string. 6 | ;destroys A,C,DE,HL 7 | ;preserves B 8 | ;26 bytes 9 | 10 | ld a,(de) 11 | call toUpper 12 | ld c,a 13 | ld a,(hl) 14 | call toUpper 15 | cp c 16 | inc de 17 | inc hl 18 | ret nz 19 | or a 20 | jr nz,cpstr 21 | ret 22 | 23 | toUpper: 24 | ;A is the char. 25 | ;If A is a lowercase letter, this sets it to the matching uppercase 26 | ;18cc or 30cc or 41cc 27 | ;avg: 26.75cc 28 | cp 'a' 29 | ret c 30 | cp 'z'+1 31 | ret nc 32 | sub 'a'-'A' 33 | ret 34 | -------------------------------------------------------------------------------- /math/division/HL_Div_7_round.z80: -------------------------------------------------------------------------------- 1 | HL_Div_7_round: 2 | ;;270cc or 280cc 3 | 4 | xor a 5 | ld d,h 6 | ld e,l 7 | ld b,a 8 | add hl,hl \ rla 9 | add hl,hl \ rla 10 | add hl,hl \ rla 11 | add hl,de \ adc a,b 12 | ld d,h 13 | ld e,l 14 | ld c,a 15 | add hl,hl \ rla 16 | add hl,hl \ rla 17 | ld d,h 18 | ld e,l 19 | ld c,a 20 | add hl,hl \ rla 21 | add hl,hl \ rla 22 | ld d,a 23 | ld d,h 24 | ld e,l 25 | ld c,a 26 | ld l,a 27 | ld h,b 28 | add hl,hl 29 | add hl,hl 30 | add hl,hl 31 | add hl,hl 32 | add hl,de 33 | adc a,b 34 | sla l 35 | ld l,h 36 | ld h,a 37 | ret nc 38 | inc hl 39 | ret 40 | AH/16 41 | 42 | -------------------------------------------------------------------------------- /math/rng/rand24.z80: -------------------------------------------------------------------------------- 1 | rand24: 2 | ;;219cc 3 | #ifdef smc 4 | seed1_0=$+1 5 | ld hl,12345 6 | seed1_1=$+1 7 | ld a,67 8 | #else 9 | ld hl,(seed1_0) 10 | ld a,(seed1_1) 11 | #endif 12 | ld b,h 13 | ld c,l 14 | ld d,a 15 | add hl,hl \ rla 16 | add hl,hl \ rla 17 | inc l 18 | add hl,bc \ adc a,0 19 | ld (seed1_0),hl 20 | ld (seed1_1),a 21 | ld c,b 22 | ld b,a 23 | #ifdef smc 24 | seed2_0=$+1 25 | ld hl,65432 26 | seed2_1=$+1 27 | ld a,10 28 | #else 29 | ld hl,(seed2_0) 30 | ld a,(seed2_1) 31 | #endif 32 | add hl,hl 33 | rla 34 | ld (seed2_1),a 35 | sbc a,a 36 | and %10000111 37 | xor l 38 | ld l,a 39 | ld (seed2_0),hl 40 | add hl,bc 41 | ret 42 | -------------------------------------------------------------------------------- /ti8x/utility/dispui8.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_dispui8 2 | #define included_dispui8 3 | 4 | #include "conversion/uitoa_8.z80" 5 | 6 | 7 | dispui8: 8 | ;Inputs: 9 | ; A is an 8-bit unsigned integer to display 10 | ;Output: 11 | ; A is printed to the screen at (curCol, curRow) 12 | ; curCol is set to 0 13 | ; curRow is advanced. 14 | ; If curRow is 8, then the contents of the homescreen 15 | ; are shifted up one row and curRow is set to 7. 16 | ;Destroys: 17 | ; 4 bytes at OP1 18 | ;Notes: Preserves registers. 19 | push hl 20 | push de 21 | push bc 22 | push af 23 | ld hl,OP1 24 | call uitoa_8 25 | bcall(_PutS) 26 | bcall(_NewLine) 27 | pop af 28 | pop bc 29 | pop de 30 | pop hl 31 | ret 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /math/division/HL_Div_3.z80: -------------------------------------------------------------------------------- 1 | HL_Div_3: 2 | ;Input: HL 3 | ;Output: HL is the input divided by 3 4 | ;Destroys: B,C,E,A 5 | ;217cc 6 | 7 | ;increment HL, putting overflow in A 8 | ld bc,1 9 | ld a,b 10 | add hl,bc 11 | adc a,b 12 | 13 | ;We want a difference of a factor of 2 shifts 14 | ld b,h 15 | ld c,l 16 | ld e,a 17 | add hl,hl \ rla 18 | add hl,hl \ rla 19 | add hl,bc \ adc a,e 20 | 21 | ;We want a difference of a factor of 4 shifts 22 | ld b,h 23 | ld c,l 24 | ld e,a 25 | add hl,hl \ rla 26 | add hl,hl \ rla 27 | add hl,hl \ rla 28 | add hl,hl \ rla 29 | add hl,bc \ adc a,e 30 | 31 | ld b,a 32 | ld c,h 33 | add hl,bc 34 | adc a,0 35 | ld l,h 36 | ld h,a 37 | ;now HL is our result 38 | 39 | ret 40 | -------------------------------------------------------------------------------- /ti8x/utility/dispi16.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_dispi16 2 | #define included_dispi16 3 | 4 | #include "conversion/itoa_16.z80" 5 | 6 | 7 | dispi16: 8 | ;Inputs: 9 | ; HL is a 16-bit signed integer 10 | ;Output: 11 | ; HL is printed to the screen at (curCol, curRow) 12 | ; curCol is set to 0 13 | ; curRow is advanced. 14 | ; If curRow is 8, then the contents of the homescreen 15 | ; are shifted up one row and curRow is set to 7. 16 | ;Destroys: 17 | ; 7 bytes at OP1 18 | ;Notes: Preserves registers. 19 | push hl 20 | push de 21 | push bc 22 | push af 23 | ex de,hl 24 | ld hl,OP1 25 | call itoa_16 26 | bcall(_PutS) 27 | bcall(_NewLine) 28 | pop af 29 | pop bc 30 | pop de 31 | pop hl 32 | ret 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /examples/chaosgame/readme.md: -------------------------------------------------------------------------------- 1 | **Chaos Game** (TI-83+/84+ Z80 calculators) 2 | 3 | by Zeda Thomas 4 | 5 | The Chaos Game is not actually a game, sorry :( Instead, it is a mathematical 6 | tool that is useful for visualizing the output of chaotic systems. The rules are: 7 | 8 | * Give a starting point. 9 | * Define N control points. 10 | * Iterate the following forever (or truncate to a finite amount of iterations) 11 | * Randomly pick one of the N control points. 12 | * Jump halfway there and plot the pixel. 13 | 14 | It is simple enough, but the results can be quite surprising to those not familiar 15 | with the Chaos Game! 16 | 17 | # Compile 18 | To compile run something like the following: 19 | ``` 20 | spasm chaos.z80 chaos.8xp -I ../../ 21 | ``` 22 | -------------------------------------------------------------------------------- /ti8x/utility/dispui16.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_dispui16 2 | #define included_dispui16 3 | 4 | #include "conversion/uitoa_16.z80" 5 | 6 | 7 | dispui16: 8 | ;Inputs: 9 | ; HL is a 16-bit unsigned integer 10 | ;Output: 11 | ; HL is printed to the screen at (curCol, curRow) 12 | ; curCol is set to 0 13 | ; curRow is advanced. 14 | ; If curRow is 8, then the contents of the homescreen 15 | ; are shifted up one row and curRow is set to 7. 16 | ;Destroys: 17 | ; 6 bytes at OP1 18 | ;Notes: Preserves registers. 19 | push hl 20 | push de 21 | push bc 22 | push af 23 | ex de,hl 24 | ld hl,OP1 25 | call uitoa_16 26 | bcall(_PutS) 27 | bcall(_NewLine) 28 | pop af 29 | pop bc 30 | pop de 31 | pop hl 32 | ret 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /math/multiplication/HL_Times_12_special.z80: -------------------------------------------------------------------------------- 1 | ;NOTE: This is a set of in-line routines! 2 | 3 | 4 | ; Input: HL 5 | ; Output: BC is the input, HL is 12 times the input 6 | ; 6 bytes, 52cc 7 | ld b,h 8 | ld c,l 9 | add hl,hl 10 | add hl,bc 11 | add hl,hl 12 | add hl,hl 13 | 14 | 15 | ;Destroys only register E and F 16 | ; Input: HL <= 85, 17 | ; 8 bytes, 46cc 18 | ld e,a 19 | ld a,l 20 | add a,a ; hl*2 21 | add a,l ; hl*3 22 | ld l,a 23 | ld a,e 24 | add hl,hl ; hl*6 25 | add hl,hl ; hl*12 26 | 27 | 28 | ;Destroys only register E and F 29 | ; Input: HL <= 85, 30 | ; 7 bytes, 55cc 31 | ld e,l 32 | add hl,hl ; hl*2 33 | add hl,de ; hl*3+d*256 34 | ld h,0 ; hl*3 35 | add hl,hl ; hl*6 36 | add hl,hl ; hl*12 37 | -------------------------------------------------------------------------------- /ti8x/gfx/getpixelloc_0x9340_nobounds.z80: -------------------------------------------------------------------------------- 1 | pixLUT: 2 | .db $80,$40,$20,$10,$08,$04,$02,$01 3 | 4 | getpixelloc: 5 | ;Input: (B,C) is (X,Y) 6 | ;Output: A is the mask, HL is the byte the pixel is on 7 | ;Destroys: BC 8 | ;NOTE: Assumes plotSScreen = 9340h 9 | ;36 bytes (or 39 bytes if the pixLUT crosses a 256-byte boundary) 10 | ;152cc (or 163~164 if the pixLUT crosses a 256-byte boundary) 11 | 12 | ld a,b 13 | ld b,11 14 | ld h,b 15 | ld l,c 16 | add hl,hl 17 | add hl,bc 18 | inc h 19 | add hl,hl 20 | add hl,hl 21 | ld c,a 22 | srl c 23 | scf 24 | rr c 25 | srl c 26 | add hl,bc 27 | 28 | and 7 29 | ld bc,pixLUT 30 | add a,c 31 | ld c,a 32 | #if (pixLUT&255)>248 33 | jr nc,$+3 34 | inc b 35 | #endif 36 | ld a,(bc) 37 | ret 38 | -------------------------------------------------------------------------------- /ti8x/utility/CRC16.z80: -------------------------------------------------------------------------------- 1 | ;Adapted from Z80 Bits 2 | ;"The following routine calculates standard CRC-CCITT bit-by-bit using 3 | ;polynomial 1021h. Another common scheme CRC-16 uses polynomial A001h and starts 4 | ;with value 0 (so it's likely that you misinterpret bunch of zeros as valid data). 5 | ;It might be useful to extend the code to use 16-bit byte counter." 6 | 7 | Crc16: 8 | ;Input: DE = address of input data, C = number of bytes to process 9 | ;Output: HL = CRC 10 | ld hl,FFFFh 11 | crcRead: 12 | ld a,(de) 13 | inc de 14 | xor h 15 | ld h,a 16 | ld b,8 17 | CrcByte: 18 | add hl,hl 19 | jr nc,crcNext 20 | ld a,h 21 | xor 10h 22 | ld h,a 23 | ld a,l 24 | xor 21h 25 | ld l,a 26 | crcNext: 27 | djnz CrcByte 28 | dec c 29 | jr nz,crcRead 30 | ret 31 | -------------------------------------------------------------------------------- /math/division/AL_Div_100.z80: -------------------------------------------------------------------------------- 1 | AL_div_100: 2 | ;Divides a 16-bit integer by 100, where A holds the upper 8 bits and L holds the lower 3 | ;Result is in HL, A is the remainder 4 | ;min:256 5 | ;max:329 6 | ;avg:305.5625cc 7 | ld c,100 8 | AL_Div_C: 9 | ;Note: C<128 10 | ld h,-1 11 | inc h \ sub c \ jr nc,$-2 12 | add a,c 13 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 14 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 15 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 16 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 17 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 18 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 19 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 20 | sla l \ rla \ cp c \ ret c \ sub a,c \ inc l 21 | ret -------------------------------------------------------------------------------- /ti8x/gfx/rectOR.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/rect.z80" 2 | 3 | rectOR: 4 | ; (B,C) = (x,y) signed 5 | ; (D,E) = (w,h) unsigned 6 | ; HL points to buf 7 | call rectSub 8 | ret nc 9 | dec b 10 | jp m,orrect0 11 | inc b 12 | or_rect_loop: 13 | push bc 14 | push hl 15 | ld a,(hl) \ or d \ ld (hl),a 16 | ld a,-1 17 | .db $FE ;sart of `cp *` to skip the folowing byte 18 | ld (hl),a \ inc hl \ djnz $-2 19 | ld a,(hl) \ or e \ ld (hl),a 20 | ld bc,12 21 | pop hl 22 | add hl,bc 23 | pop bc 24 | dec c 25 | jr nz,or_rect_loop 26 | ret 27 | orrect0: 28 | ld a,d 29 | and e 30 | ld b,c 31 | ld c,a 32 | ld de,12 33 | ld a,c 34 | or (hl) 35 | ld (hl),a 36 | add hl,de 37 | djnz $-4 38 | ret 39 | -------------------------------------------------------------------------------- /ti8x/utility/dispfixed412.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_dispfixed412 2 | #define included_dispfixed412 3 | 4 | #include "conversion/fixed_4_12_to_str.z80" 5 | 6 | 7 | dispfixed412: 8 | ;Inputs: 9 | ; HL is a 16-bit signed integer 10 | ;Output: 11 | ; HL is printed to the screen at (curCol, curRow) 12 | ; curCol is set to 0 13 | ; curRow is advanced. 14 | ; If curRow is 8, then the contents of the homescreen 15 | ; are shifted up one row and curRow is set to 7. 16 | ;Destroys: 17 | ; 8 bytes at OP1 18 | ;Notes: Preserves registers. 19 | push hl 20 | push de 21 | push bc 22 | push af 23 | ex de,hl 24 | ld hl,OP1 25 | call fixed_4_12_to_str 26 | bcall(_PutS) 27 | bcall(_NewLine) 28 | pop af 29 | pop bc 30 | pop de 31 | pop hl 32 | ret 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /ti8x/utility/getappnumpages.z80: -------------------------------------------------------------------------------- 1 | ;NOTE: This routine may be under a different License. 2 | ;Code is at https://www.omnimaga.org/asm-language/asm-optimized-routines/msg310060/#msg310060 3 | 4 | ;Routine by Runer112, based on a routine by Zeda 5 | ;Neither routine properly parses the app header, so technically it is 6 | ;feasible that this won't work, but an app would almost have to be 7 | ;inentionally designed for the specific purpose of breaking this code. 8 | 9 | getappnumpages: 10 | ;Inputs: 11 | ; The app base page is loaded in MemBank1 12 | ;Outputs: 13 | ; A, (HL) is the number of app pages 14 | 15 | ld hl,4000h 16 | ld a,81h 17 | ld c,a 18 | FNPLoop: 19 | dec a 20 | cpir 21 | inc a 22 | cp (hl) 23 | jr nz,FNPLoop 24 | inc l 25 | ld a,(hl) 26 | ret 27 | -------------------------------------------------------------------------------- /ti8x/gfx/rectXOR.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/rect.z80" 2 | 3 | rectXOR: 4 | ; (B,C) = (x,y) signed 5 | ; (D,E) = (w,h) unsigned 6 | ; HL points to buf 7 | call rectSub 8 | ret nc 9 | dec b 10 | jp m,xorrect0 11 | inc b 12 | xor_rect_loop: 13 | push bc 14 | push hl 15 | ld a,(hl) \ xor d 16 | .db $DA ;start of jp c,**, will skip the next two bytes since `xor d` reset carry 17 | ld a,(hl) \ cpl \ ld (hl),a \ inc hl \ djnz $-4 18 | ld a,(hl) \ xor e \ ld (hl),a 19 | ld bc,12 20 | pop hl 21 | add hl,bc 22 | pop bc 23 | dec c 24 | jr nz,xor_rect_loop 25 | ret 26 | xorrect0: 27 | ld a,d 28 | and e 29 | ld b,c 30 | ld c,a 31 | ld de,12 32 | ld a,c 33 | xor (hl) 34 | ld (hl),a 35 | add hl,de 36 | djnz $-4 37 | ret 38 | -------------------------------------------------------------------------------- /math/misc/lnfixed_88.z80: -------------------------------------------------------------------------------- 1 | 2 | ln_88: 3 | ;Input: HL is a fixed point number 4 | ;Output: ln(H.L)->H.L 5 | ;Speed: Avg: 340+(325 worst case) 6 | call lg_88 7 | ;now signed multiply HL by 355, then divide by 2 (rounding) 8 | ld de,0 9 | bit 7,h 10 | jr z,$+9 11 | dec e \ xor a \ sub l \ ld l,a 12 | sbc a,a \ sub h \ ld h,a 13 | ld b,h 14 | ld c,l 15 | xor a 16 | add hl,hl 17 | add hl,hl \ rla 18 | add hl,bc \ adc a,d 19 | add hl,hl \ rla 20 | add hl,bc \ adc a,d 21 | add hl,hl \ rla 22 | add hl,hl \ rla 23 | add hl,hl \ rla 24 | add hl,hl \ rla 25 | add hl,bc \ adc a,d 26 | add hl,hl \ rla 27 | add hl,bc \ adc a,d 28 | sra a \ rr h 29 | ld l,h 30 | ld h,a 31 | inc e 32 | ret nz 33 | xor a \ sub l \ ld l,a 34 | sbc a,a \ sub h \ ld h,a 35 | ret 36 | -------------------------------------------------------------------------------- /ti8x/utility/centertext.z80: -------------------------------------------------------------------------------- 1 | ;NOTE: This routine may be under a different License. 2 | ;posted in this topic: https://www.cemetech.net/projects/uti/viewtopic.php?t=1279&postdays=0&postorder=asc&start=0 3 | ;with the rule: 4 | ; "3) By posting a routine you're granting everyone the right to use it freely." 5 | 6 | ;created by WikiGuru 7 | ;input:hl points to string 8 | ;output: string displayed centered on screen 9 | ;destroyed: all registers 10 | ;other remarks: (penrow) must be set before calling this sub-routine 11 | ; first byte of string must be the length of the string 12 | 13 | centertxt: 14 | bcall(_SStringLength) 15 | ld a,96 ;width of screen 16 | sub b ;subtract width of string 17 | rra ;divide by 2 to be centered 18 | ld (pencol),a 19 | ld b,(hl) 20 | inc hl 21 | bcall(_VPutSN) 22 | ret 23 | -------------------------------------------------------------------------------- /ti8x/gfx/getpixelloc_0x9340.z80: -------------------------------------------------------------------------------- 1 | pixLUT: 2 | .db $80,$40,$20,$10,$08,$04,$02,$01 3 | 4 | getpixelloc: 5 | ;Input: (B,C) is (X,Y) 6 | ;Output: A is the mask, HL is the byte the pixel is on, nc if out-of-bounds 7 | ;Destroys: BC 8 | ;NOTE: Assumes plotSScreen = 9340h 9 | ;44 bytes (or 47 bytes if the pixLUT crosses a 256-byte boundary) 10 | ;184cc (or 195~196 if the pixLUT crosses a 256-byte boundary) 11 | ld a,c 12 | cp 64 13 | ret nc 14 | ld a,b 15 | cp 96 16 | ret nc 17 | 18 | ld b,11 19 | ld h,b 20 | ld l,c 21 | add hl,hl 22 | add hl,bc 23 | inc h 24 | add hl,hl 25 | add hl,hl 26 | ld c,a 27 | srl c 28 | scf 29 | rr c 30 | srl c 31 | add hl,bc 32 | 33 | and 7 34 | ld bc,pixLUT 35 | add a,c 36 | ld c,a 37 | #if (pixLUT&255)>248 38 | jr nc,$+3 39 | inc b 40 | #endif 41 | ld a,(bc) 42 | scf 43 | ret 44 | -------------------------------------------------------------------------------- /math/addition/addBCD_16.z80: -------------------------------------------------------------------------------- 1 | ;Adds two, little-endian 16-digit BCD integers (8 bytes) 2 | 3 | addBCD_16: 4 | ;Input: 5 | ; HL points to one BCD integer 6 | ; DE points to another BCD integer 7 | ;Output: 8 | ; The sum is wrriten over the integer at HL. 9 | ; HL and DE point to the last digit of their integers. 10 | ;46 bytes, 284cc 11 | ld a,(de) \ add a,(hl) \ daa \ ld (de),a \ inc hl \ inc de 12 | ld a,(de) \ adc a,(hl) \ daa \ ld (de),a \ inc hl \ inc de 13 | ld a,(de) \ adc a,(hl) \ daa \ ld (de),a \ inc hl \ inc de 14 | ld a,(de) \ adc a,(hl) \ daa \ ld (de),a \ inc hl \ inc de 15 | ld a,(de) \ adc a,(hl) \ daa \ ld (de),a \ inc hl \ inc de 16 | ld a,(de) \ adc a,(hl) \ daa \ ld (de),a \ inc hl \ inc de 17 | ld a,(de) \ adc a,(hl) \ daa \ ld (de),a \ inc hl \ inc de 18 | ld a,(de) \ adc a,(hl) \ daa \ ld (de),a 19 | ret 20 | -------------------------------------------------------------------------------- /ti8x/gfx/getpixelloc_nobounds.z80: -------------------------------------------------------------------------------- 1 | getpixelloc: 2 | ;Input: (B,C) is (X,Y) 3 | ;Output: A is the mask, HL is the byte the pixel is on 4 | ;Destroys: BC 5 | ;37 bytes (or 40 bytes if the pixLUT crosses a 256-byte boundary) 6 | ;155cc (or 166~167 if the pixLUT crosses a 256-byte boundary) 7 | 8 | ld a,b 9 | ld b,0 10 | ld h,b 11 | ld l,c 12 | add hl,hl 13 | add hl,bc 14 | add hl,hl 15 | add hl,hl 16 | ld c,a 17 | 18 | #if (plotSScreen&255) = 64 19 | srl c 20 | scf 21 | rr c 22 | srl c 23 | ld b,plotSScreen>>8 24 | #else 25 | srl c 26 | srl c 27 | srl c 28 | add hl,bc 29 | ld bc,plotSScreen 30 | #endif 31 | add hl,bc 32 | 33 | and 7 34 | ld bc,pixLUT 35 | add a,c 36 | ld c,a 37 | #if (pixLUT&255)>248 38 | jr nc,$+3 39 | inc b 40 | #endif 41 | ld a,(bc) 42 | ret 43 | 44 | pixLUT: 45 | .db $80,$40,$20,$10,$08,$04,$02,$01 46 | -------------------------------------------------------------------------------- /math/division/ALDE_div_100.z80: -------------------------------------------------------------------------------- 1 | ALDE_div_100: 2 | ;Divides a 32-bit integer by 100, where A holds the upper 8 bits and L holds the next 8, followed by DE 3 | ;Result is in DEHL, A is the remainder 4 | ld c,100 5 | ALDE_Div_C: 6 | ;Note: C<128 7 | ld h,-1 8 | inc h \ sub c \ jr nc,$-2 9 | add a,c 10 | call +_ 11 | push hl 12 | ld l,d 13 | call +_ 14 | ld h,l 15 | ld l,e 16 | pop de 17 | _: 18 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 19 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 20 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 21 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 22 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 23 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 24 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 25 | sla l \ rla \ cp c \ ret c \ sub a,c \ inc l 26 | ret -------------------------------------------------------------------------------- /ti8x/gfx/rectErase.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/rect.z80" 2 | 3 | rectErase: 4 | ; (B,C) = (x,y) signed 5 | ; (D,E) = (w,h) unsigned 6 | ; HL points to buf 7 | call rectSub 8 | ret nc 9 | ld a,d 10 | cpl 11 | ld d,a 12 | ld a,e 13 | cpl 14 | ld e,a 15 | dec b 16 | jp m,eraserect0 17 | inc b 18 | erase_rect_loop: 19 | push bc 20 | push hl 21 | ld a,(hl) \ and d \ ld (hl),a 22 | xor a 23 | .db $FE ;sart of `cp *` to skip the folowing byte 24 | ld (hl),a \ inc hl \ djnz $-2 25 | ld a,(hl) \ and e \ ld (hl),a 26 | ld bc,12 27 | pop hl 28 | add hl,bc 29 | pop bc 30 | dec c 31 | jr nz,erase_rect_loop 32 | ret 33 | eraserect0: 34 | ld a,d 35 | xor e 36 | ld b,c 37 | ld c,a 38 | ld de,12 39 | ld a,c 40 | and (hl) 41 | ld (hl),a 42 | add hl,de 43 | djnz $-4 44 | ret 45 | -------------------------------------------------------------------------------- /ti8x/gfx/shiftgbufupA.z80: -------------------------------------------------------------------------------- 1 | ;shift the gbuf up by A bytes 2 | 3 | shiftgbufup_A: 4 | ;If A is 0, do nothing 5 | or a 6 | ret z 7 | 8 | ;If A is 64 or more, just set it to 64 9 | cp 64 10 | jr c,$+4 11 | ld a,64 12 | 13 | ;Multiply A by 12 14 | ld l,a 15 | ld h,0 16 | add a,a 17 | add a,l 18 | ld l,a 19 | add hl,hl 20 | add hl,hl 21 | 22 | ;HL is the number of bytes that we will zero 23 | push hl 24 | ld b,h 25 | ld c,l 26 | ld hl,plotSScreen 27 | ld d,h 28 | ld e,l 29 | add hl,bc 30 | ;need to move 768-BC bytes 31 | xor a 32 | sub c 33 | ld c,a 34 | ld a,3 35 | sbc a,b 36 | ld b,a 37 | 38 | ;if BC is 0, do nothing! 39 | or c 40 | jr z,$+4 41 | ldir 42 | 43 | ;now DE points to the bottom of where we need to start zeroing 44 | ld h,d 45 | ld l,e 46 | ld (hl),b 47 | inc de 48 | 49 | pop bc ;Guaranteed that BC is not zero! 50 | dec bc 51 | ldir 52 | ret 53 | -------------------------------------------------------------------------------- /utility/fastLDIR.z80: -------------------------------------------------------------------------------- 1 | fastldir: 2 | ;copy BC bytes from HL to DE 3 | ; 4 | ;116 + 16*BC + 10*ceil(BC/16) 5 | ; 6 | ;If you call this routine, add 17cc as overhead, and it breaks even with LDIR at 34 bytes 7 | ;If you jp to this routine, add 10cc as overhead, and break-even is 31 bytes 8 | ; 9 | push hl 10 | push af 11 | xor a 12 | sub c 13 | and 15 ;change to n-1, n must be a power of 2 14 | add a,a 15 | add a,ldirloop&255 16 | ld l,a 17 | adc a,ldirloop>>8 18 | sub l 19 | ld h,a 20 | pop af 21 | ex (sp),hl 22 | ret 23 | 24 | ldirloop: 25 | ;n=16, (number of LDI instructions, use qty of 4,8,16,32,64) 26 | ldi 27 | ldi 28 | ldi 29 | ldi 30 | ldi 31 | ldi 32 | ldi 33 | ldi 34 | ldi 35 | ldi 36 | ldi 37 | ldi 38 | ldi 39 | ldi 40 | ldi 41 | _ldirloop_end: 42 | ldi 43 | jp pe,ldirloop 44 | ret 45 | -------------------------------------------------------------------------------- /ti8x/gfx/shiftgbufdownA.z80: -------------------------------------------------------------------------------- 1 | ;shift the gbuf down by A bytes 2 | 3 | shiftgbufdown_A: 4 | ;If A is 0, do nothing 5 | or a 6 | ret z 7 | 8 | ;If A is 64 or more, just set it to 64 9 | cp 64 10 | jr c,$+4 11 | ld a,64 12 | 13 | ;Multiply A by 12 14 | ld l,a 15 | ld h,0 16 | add a,a 17 | add a,l 18 | ld l,a 19 | add hl,hl 20 | add hl,hl 21 | 22 | ;HL is the number of bytes that we will zero 23 | push hl 24 | ld b,h 25 | ld c,l 26 | ld hl,plotSScreen+767 27 | ld d,h 28 | ld e,l 29 | sbc hl,bc 30 | ;need to move 768-BC bytes 31 | xor a 32 | sub c 33 | ld c,a 34 | ld a,3 35 | sbc a,b 36 | ld b,a 37 | 38 | ;if BC is 0, do nothing! 39 | or c 40 | jr z,$+4 41 | lddr 42 | 43 | ;now DE points to the bottom of where we need to start zeroing 44 | ld h,d 45 | ld l,e 46 | ld (hl),b 47 | dec de 48 | 49 | pop bc ;Guaranteed that BC is not zero! 50 | dec bc 51 | lddr 52 | ret 53 | -------------------------------------------------------------------------------- /ti8x/utility/getKeyDebounce.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_getKeyDebounce 2 | #define included_getkeyDebounce 3 | #include "ti8x/utility/getKey.z80" 4 | 5 | ;Needs the following defined. 6 | ;Feel free to change the constants 7 | ;#define K_DELAY_DEFAULT 13 8 | ;#define K_DELAY_ACCEL 3 9 | ;k_save = 8000h 10 | 11 | getKeyDebounce: 12 | k_count = k_save+1 13 | k_delay = k_count+1 14 | ei 15 | halt 16 | call GetKey 17 | ld hl,k_save 18 | cp (hl) 19 | jr nz,newkeypress 20 | ;if the keys match, decrement k_count 21 | inc hl 22 | dec (hl) 23 | jr z,+_ 24 | xor a 25 | ret 26 | _: 27 | inc hl 28 | ld a,(hl) 29 | sub K_DELAY_ACCEL+1 30 | jr nc,+_ 31 | xor a 32 | _: 33 | inc a 34 | ld (hl),a 35 | dec hl 36 | ld (hl),a 37 | dec hl 38 | ld a,(hl) 39 | ret 40 | newkeypress: 41 | ld (hl),a 42 | inc hl 43 | ld (hl),K_DELAY_DEFAULT 44 | inc hl 45 | ld (hl),K_DELAY_DEFAULT 46 | ret 47 | #endif 48 | -------------------------------------------------------------------------------- /math/division/BC_Div_DE_fast.z80: -------------------------------------------------------------------------------- 1 | BC_Div_DE: 2 | ;BC/DE ==> BC, remainder in HL 3 | ;NOTE: BC/0 returns 0 as the quotient. 4 | ;min: 773cc 5 | ;max: 933cc 6 | ;avg: 853cc 7 | ;82 bytes 8 | xor a 9 | ld h,a 10 | ld l,a 11 | sub e 12 | ld e,a 13 | sbc a,a 14 | sub d 15 | ld d,a 16 | 17 | ld a,b 18 | ld b,c 19 | call BC_Div_DE_sub 20 | ld a,b 21 | ld b,c 22 | 23 | BC_Div_DE_sub: 24 | ;min: 354cc 25 | ;max: 434cc 26 | ;avg: 394cc 27 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 28 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 29 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 30 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 31 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 32 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 33 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 34 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 35 | rla 36 | ld c,a 37 | ret 38 | -------------------------------------------------------------------------------- /math/squareroot/sqrtL.z80: -------------------------------------------------------------------------------- 1 | SqrtL: 2 | ;Inputs: 3 | ; L is the value to find the square root of 4 | ;Outputs: 5 | ; C is the result 6 | ; B,L are 0 7 | ; DE is not changed 8 | ; H is how far away it is from the next smallest perfect square 9 | ; L is 0 10 | ; z flag set if it was a perfect square 11 | ;Destroyed: 12 | ; A 13 | ld bc,400h ; 10 10 14 | ld h,c ; 4 4 15 | sqrt8Loop: ; 16 | add hl,hl ;11 44 17 | add hl,hl ;11 44 18 | rl c ; 8 32 19 | ld a,c ; 4 16 20 | rla ; 4 16 21 | sub a,h ; 4 16 22 | jr nc,$+5 ;12|19 48+7x 23 | inc c 24 | cpl 25 | ld h,a 26 | djnz sqrt8Loop ;13|8 47 27 | ret ;10 10 28 | ;287+7x, x is the number of bits in the result 29 | ;min: 287 30 | ;max: 315 31 | ;19 bytes 32 | -------------------------------------------------------------------------------- /ti8x/utility/text_len.z80: -------------------------------------------------------------------------------- 1 | ;Created by E37, optimized by Zeda 2 | 3 | #include "ti8x/utility/get_sFont_custom.z80" 4 | 5 | text_len: 6 | ;finds the length in pixels the string 7 | ;inputs: 8 | ; hl = zero terminated string 9 | ;returns: 10 | ; de = length of the string in pixels 11 | 12 | ld bc, 0 13 | 14 | text_len_max: 15 | ;inputs: 16 | ; hl = zero terminated string 17 | ; bc = maximum number of characters (it will stop after BC characters or when 0 is reached, whichever comes first) 18 | ;returns: 19 | ; de = length of the string in pixels 20 | 21 | xor a 22 | ld d,a 23 | ld e,a 24 | TextRLoop: 25 | or (hl) 26 | ret z 27 | ; push bc 28 | push hl 29 | push de 30 | 31 | call get_sFont_custom ;preserves BC 32 | xor a 33 | ld l, (hl) 34 | ld h, a 35 | pop de 36 | add hl, de 37 | ex de,hl 38 | 39 | pop hl 40 | ; pop bc 41 | cpi 42 | jp pe, TextRLoop 43 | ret 44 | -------------------------------------------------------------------------------- /math/trig/atan8.z80: -------------------------------------------------------------------------------- 1 | atan8: 2 | ;computes 256*atan(A/256)->A 3 | ;56 bytes including the LUT 4 | ;min: 246cc 5 | ;max: 271cc 6 | ;avg: 258.5cc 7 | rlca 8 | rlca 9 | rlca 10 | ld d,a 11 | and 7 12 | ld hl,atan8LUT 13 | add a,l 14 | ld l,a 15 | #if (atan8LUT&255)>248 ;this section not included in size/speed totals 16 | jr nc,$+3 ;can add three bytes, 12cc to max, 11cc to min, and 11.5cc to avg 17 | inc h 18 | #endif 19 | ld c,(hl) 20 | inc hl 21 | ld a,(hl) 22 | sub c 23 | ld e,0 24 | ex de,hl 25 | ld d,l 26 | ld e,a 27 | sla h \ jr nc,$+3 \ ld l,e 28 | add hl,hl \ jr nc,$+3 \ add hl,de 29 | add hl,hl \ jr nc,$+3 \ add hl,de 30 | add hl,hl \ jr nc,$+3 \ add hl,de 31 | add hl,hl \ jr nc,$+3 \ add hl,de 32 | add hl,hl 33 | add hl,hl 34 | add hl,hl 35 | ; add hl,hl ;used in rounding... 36 | ld a,h 37 | ; rra ;but doesn't seem to improve the error 38 | adc a,c 39 | ret 40 | atan8LUT: 41 | .db 0,32,63,92,119,143,165,184,201 -------------------------------------------------------------------------------- /conversion/i16toa_destructive.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_itoa_16 2 | #define included_itoa_16 3 | #include conversion/u16toa_destructive.z80 4 | 5 | 6 | ; A related routine can be found at conversion/itoa_16.z80 which preserves 7 | ; registers. 8 | 9 | ;written by Zeda 10 | ;Converts a 16-bit signed integer to an ASCII string. 11 | ;Note that this version destroys registers. 12 | 13 | #ifndef TOK_NEG 14 | #define TOK_NEG '-' 15 | #endif 16 | 17 | i16toa: 18 | ;Input: 19 | ; DE is the number to convert 20 | ; HL points to where to write the ASCII string (up to 7 bytes needed). 21 | ;Output: 22 | ; HL points to the null-terminated ASCII string 23 | ; NOTE: This isn't necessarily the same as the input HL. 24 | ;Destroys: 25 | ; DE, BC, AF 26 | ld a,d 27 | add a,a 28 | jp nc,u16toa 29 | xor a 30 | sub e 31 | ld e,a 32 | sbc a,a 33 | sub d 34 | ld d,a 35 | inc hl ; make space for a negative sign 36 | call u16toa 37 | dec hl 38 | ld (hl),TOK_NEG 39 | ret 40 | #endif 41 | -------------------------------------------------------------------------------- /math/multiplication/mul24.z80: -------------------------------------------------------------------------------- 1 | ;And mul24 needs 6 bytes at var48 defined. 2 | 3 | mul24: 4 | ;BDE*CHL -> HLBCDE 5 | ;155 bytes 6 | ;402+3*C_Times_BDE 7 | ;fastest:1201cc 8 | ;slowest:1753cc 9 | ;avg: 1464.9033203125cc (1464+925/1024) 10 | ;min: 825cc 11 | ;max: 1926cc 12 | ;avg: 1449.63839751681cc 13 | 14 | push bc 15 | ld c,l 16 | push hl 17 | call C_Times_BDE 18 | ld (var48),hl 19 | ld l,a 20 | ld h,c 21 | ld (var48+2),hl 22 | 23 | pop hl 24 | ld c,h 25 | call C_Times_BDE 26 | push bc 27 | ld bc,(var48+1) 28 | add hl,bc 29 | ld (var48+1),hl 30 | pop bc 31 | ld b,c 32 | ld c,a 33 | ld hl,(var48+3) 34 | ld h,0 35 | adc hl,bc 36 | ld (var48+3),hl 37 | 38 | pop bc 39 | call C_Times_BDE 40 | ld de,(var48+2) 41 | add hl,de 42 | ld (var48+2),hl 43 | ld d,c 44 | ld e,a 45 | ld b,h 46 | ld c,l 47 | ld hl,(var48+4) 48 | ld h,0 49 | adc hl,de 50 | ld de,(var48) 51 | ret 52 | -------------------------------------------------------------------------------- /math/rng/rand32.z80: -------------------------------------------------------------------------------- 1 | rand32: 2 | ;Tested and passes all CAcert tests 3 | ;Uses a very simple 32-bit LCG and 32-bit LFSR 4 | ;it has a period of 18,446,744,069,414,584,320 5 | ;roughly 18.4 quintillion. 6 | ;LFSR taps: 0,2,6,7 = 11000101 7 | ;291cc 8 | ;Thanks to Runer112 for his help on optimizing the LCG and suggesting to try the much simpler LCG. On their own, the two are terrible, but together they are great. 9 | ;58 bytes 10 | seed1_0=$+1 11 | ld hl,12345 12 | seed1_1=$+1 13 | ld de,6789 14 | ld b,h 15 | ld c,l 16 | add hl,hl \ rl e \ rl d 17 | add hl,hl \ rl e \ rl d 18 | inc l 19 | add hl,bc 20 | ld (seed1_0),hl 21 | ld hl,(seed1_1) 22 | adc hl,de 23 | ld (seed1_1),hl 24 | ex de,hl 25 | ;;lfsr 26 | seed2_0=$+1 27 | ld hl,9876 28 | seed2_1=$+1 29 | ld bc,54321 30 | add hl,hl \ rl c \ rl b 31 | ld (seed2_1),bc 32 | sbc a,a 33 | and %11000101 34 | xor l 35 | ld l,a 36 | ld (seed2_0),hl 37 | ex de,hl 38 | add hl,bc 39 | ret 40 | -------------------------------------------------------------------------------- /ti8x/gfx/vbufToLCD.z80: -------------------------------------------------------------------------------- 1 | vbufToLCD: 2 | ;Inputs: (buf0) is the buffer to render (vertically aligned) 3 | push hl 4 | push bc 5 | push af 6 | 7 | ;This chunk of code sets the LCD increment mode 8 | ;This is how the OS has it, so you probably don't need to change it 9 | ; ld a,5 10 | ; out (16),a 11 | ; in a,(16) \ add a,a \ jr c,$-3 12 | 13 | ;This chunk of code moves the LCD pointer to the top row of pixels 14 | ;You only need this if there are other routines that might mess with the LCD 15 | ;pointer (like OS interrupts). I set this once at the start of my programs. 16 | ; ld a,80h 17 | ; out (16),a 18 | ; in a,(16) \ add a,a \ jr c,$-3 19 | 20 | 21 | buf0=$+1 22 | ld hl,plotSScreen 23 | ld a,20h 24 | rowloop: 25 | out (16),a 26 | ld bc,$4011 27 | push af 28 | colloop: 29 | in a,(16) \ add a,a \ jr c,$-3 30 | outi 31 | jr nz,colloop 32 | pop af 33 | inc a 34 | cp 2Ch 35 | jp nz,rowloop 36 | pop af 37 | pop bc 38 | pop hl 39 | ret 40 | -------------------------------------------------------------------------------- /conversion/atoui32.z80: -------------------------------------------------------------------------------- 1 | atoui32: 2 | ;=============================================================== 3 | ;Input: 4 | ; DE points to the base 10 number string in RAM. 5 | ;Outputs: 6 | ; HLIX is the 32-bit value of the number 7 | ; DE points to the byte after the number 8 | ; BC points to the start of the number 9 | ; z flag means it ended on a decimal point. 10 | ;Destroys: 11 | ; A (actually, add 30h and you get the ending token) 12 | ; BC 13 | ;=============================================================== 14 | ld hl,0 15 | ld ix,0 16 | push de ;save the pointer 17 | jr atoui16_start 18 | _: 19 | inc de 20 | ld b,ixh 21 | ld c,ixl 22 | push hl 23 | add ix,ix \ adc hl,hl 24 | add ix,ix \ adc hl,hl 25 | inc ix 26 | dec ix 27 | add ix,bc \ pop bc \ adc hl,bc 28 | add ix,ix \ adc hl,hl 29 | add a,ixl 30 | ld ixl,a 31 | jr nc,atoui16_start 32 | inc ixh 33 | jr nz,atoui16_start 34 | inc hl 35 | atoui16_start: 36 | ld a,(de) 37 | sub 30h 38 | cp 10 39 | jr c,-_ 40 | pop bc 41 | ret 42 | -------------------------------------------------------------------------------- /math/division/bignum_div_100.z80: -------------------------------------------------------------------------------- 1 | bignum_div_100: 2 | ;Input: 3 | ; HL points to the bignum (1 byte size prefix (0 -> 1 byte, 1 -> 2 bytes, n-1 -> n bytes), n subsequent bytes) 4 | ;Output: 5 | ; bignum is divided in-place, not renormalized 6 | ; A is the remainder 7 | ; BC is 100 8 | ld c,100 9 | bignum_div_C: 10 | ;Note: C<128 11 | ld b,(hl) 12 | inc hl 13 | ld a,(hl) 14 | ld h,-1 15 | inc h \ sub c \ jr nc,$-2 16 | add a,c 17 | ld (hl),a 18 | inc b 19 | dec b 20 | ret z 21 | _: 22 | inc hl 23 | ld e,(hl) 24 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 25 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 26 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 27 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 28 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 29 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 30 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 31 | sla e \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc e 32 | ld (hl),a 33 | djnz -_ 34 | ret 35 | -------------------------------------------------------------------------------- /ti8x/gfx/UpdateLCD.z80: -------------------------------------------------------------------------------- 1 | ;**NOTE:** (1 March 2020) 2 | ; It seems in the past year or two, some calculators' LCDs don't report status 3 | ; correctly, so this routine might not work for them! The crude workaround is 4 | ; to put a long-ish delay where you see: 5 | ; in a,(16) \ rla \ jr c,$-3 6 | ; For example: 7 | ; call LCD_BUSY_QUICK 8 | 9 | 10 | #ifndef included_UpdateLCD 11 | #define included_UpdateLCD 12 | 13 | UpdateLCD: 14 | ;This copies the contents of gbuf to the LCD. 15 | ;Preserves all registers. 16 | push hl 17 | push de 18 | push bc 19 | push af 20 | ld hl,gbuf 21 | in a,(16) \ rla \ jr c,$-3 22 | ld a,$80 23 | out (16),a 24 | 25 | ld de,11 26 | in a,(16) \ rla \ jr c,$-3 27 | ld a,$20 28 | col: 29 | out (10h),a 30 | push af 31 | ld bc,$4011 32 | row: 33 | in a,(16) \ rla \ jr c,$-3 34 | outi 35 | add hl,de 36 | jr nz,row 37 | pop af 38 | inc a 39 | dec h 40 | dec h 41 | dec h 42 | inc hl 43 | cp $2C 44 | jp nz,col 45 | pop af 46 | pop bc 47 | pop de 48 | pop hl 49 | ret 50 | #endif 51 | -------------------------------------------------------------------------------- /math/division/ALDEIX_Div_100.z80: -------------------------------------------------------------------------------- 1 | ALDEIX_div_100: 2 | ;Divides a 48-bit integer by 100, where A holds the upper 8 bits and L holds the next 8, followed by DE and IX 3 | ;Result is in HLDEIX, A is the remainder 4 | ld c,100 5 | ALDEIX_Div_C: 6 | ;Note: C<128 7 | ld h,-1 8 | inc h \ sub c \ jr nc,$-2 9 | add a,c 10 | call +_ 11 | push hl 12 | ld l,d 13 | call +_ 14 | ld h,l 15 | ld l,e 16 | call +_ 17 | push hl 18 | push ix 19 | pop de 20 | ld l,d 21 | call +_ 22 | ld h,l 23 | ld l,e 24 | call +_ 25 | pop de 26 | ex (sp),ix 27 | pop hl 28 | ret 29 | _: 30 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 31 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 32 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 33 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 34 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 35 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 36 | sla l \ rla \ cp c \ jr c,$+4 \ sub a,c \ inc l 37 | sla l \ rla \ cp c \ ret c \ sub a,c \ inc l 38 | ret -------------------------------------------------------------------------------- /math/trig/atanE.z80: -------------------------------------------------------------------------------- 1 | atanE: 2 | ;returns H=256*arctan(E/256) 3 | ;min: 496cc 4 | ;max: 539cc 5 | ;avg: 517.5cc 6 | ;multiply E by 201 7 | ld d,0 8 | ld h,d 9 | ld l,e 10 | add hl,hl 11 | add hl,de 12 | add hl,hl 13 | add hl,hl 14 | add hl,hl 15 | add hl,de 16 | add hl,hl 17 | add hl,hl 18 | add hl,hl 19 | add hl,de 20 | ld b,h 21 | ld c,l 22 | 23 | ;E*(256-E) 24 | xor a 25 | ld d,a 26 | sub e 27 | ld h,a 28 | ld l,d 29 | sla h \ jr nc,$+3 \ ld l,e 30 | add hl,hl \ jr nc,$+3 \ add hl,de 31 | add hl,hl \ jr nc,$+3 \ add hl,de 32 | add hl,hl \ jr nc,$+3 \ add hl,de 33 | add hl,hl \ jr nc,$+3 \ add hl,de 34 | add hl,hl \ jr nc,$+3 \ add hl,de 35 | add hl,hl \ jr nc,$+3 \ add hl,de 36 | add hl,hl \ jr nc,$+3 \ add hl,de 37 | ;.HL*70 38 | ld d,h 39 | ld e,l 40 | xor a 41 | add hl,hl 42 | add hl,hl \ rla ;rla needed for the case when input = 128 :( 43 | add hl,hl \ rla 44 | add hl,hl \ rla 45 | add hl,de \ adc a,0 46 | add hl,hl \ rla 47 | add hl,de \ adc a,0 48 | add hl,hl \ rla 49 | ld l,h 50 | ld h,a 51 | add hl,bc 52 | ret 53 | -------------------------------------------------------------------------------- /math/rng/xs32.z80: -------------------------------------------------------------------------------- 1 | xs32: 2 | ;32-bit xorshift 3 | ;seed^=seed<<23 4 | ;seed^=seed>>15 5 | ;seed^=seed<<17 6 | ;min: 209cc (193cc if using SMC) 7 | ;max: 239cc (223cc if using SMC) 8 | ;avg: 224cc (208cc if using SMC) 9 | ;53 bytes (52 bytes if using SMC) 10 | #ifdef SMC 11 | seed1 = $+1 12 | ld hl,12345 13 | seed2 = $+1 14 | ld de,6789 15 | #else 16 | ld hl,(seed1) 17 | ld de,(seed2) 18 | #endif 19 | 20 | ;first, XOR it with itself, shifted left 23 bits 21 | ;low bit of d needs to be shifted in 22 | ld a,h 23 | rra 24 | ld a,l 25 | rra 26 | jr nc,+_ 27 | rl e 28 | ccf 29 | rr e 30 | _: 31 | xor d 32 | ld d,a 33 | 34 | ;XOR it with itself, shifted right 15 bits 35 | ld a,h 36 | rla 37 | ld a,e 38 | rla 39 | xor l 40 | ld l,a 41 | 42 | ld a,e 43 | rla 44 | ld a,d 45 | rla 46 | jr nc,+_ 47 | rr e 48 | ccf 49 | rl e 50 | _: 51 | xor h 52 | ld h,a 53 | 54 | ;XOR it with itself, shifted left 17 bits 55 | ;HL<<1 56 | ld (seed1),hl 57 | add hl,hl 58 | ld a,h 59 | xor d 60 | ld h,a 61 | 62 | ld a,l 63 | xor e 64 | ld l,a 65 | ld (seed2),hl 66 | ret 67 | -------------------------------------------------------------------------------- /ti8x/utility/setXXX_signed.z80: -------------------------------------------------------------------------------- 1 | setXXX_signed: 2 | ;Inputs: A is the signed int 3 | ; HL is where to write the TI float 4 | ld c,0 5 | ld (hl),c 6 | add a,a 7 | jr c,$+6 8 | neg 9 | ld (hl),80h 10 | inc hl 11 | ld (hl),81h 12 | ld d,h 13 | ld e,l 14 | inc hl \ ld (hl),c \ djnz $-2 15 | or a \ ret z 16 | ld l,a ;\ 17 | ld h,c ; | 18 | add hl,hl ; |Start converting A to BCD 19 | add hl,hl ; | 20 | add hl,hl ; | 21 | add hl,hl ; | 22 | ld a,h \ daa \ rl l ; |Finish converting A to BCD 23 | adc a,a \ daa \ rl l ; |Number is in cA 24 | adc a,a \ daa \ rl l ; |(c is carry) 25 | adc a,a \ daa ;/ 26 | ex de,hl 27 | jr nc,$+15 28 | ld (hl),82h 29 | inc hl 30 | inc hl 31 | ld (hl),a 32 | xor a 33 | rld 34 | or $10 35 | dec hl 36 | ld (hl),a 37 | ret 38 | inc hl 39 | ld (hl),a 40 | and $F0 41 | ret nz 42 | rld ;\ Rotate up 1 digit 43 | dec hl ; | 44 | ld (hl),80h ; | 45 | ret ; / 46 | -------------------------------------------------------------------------------- /utility/im2setup_smaller.z80: -------------------------------------------------------------------------------- 1 | ; This smaller ariant of the im2 interrupt setup is a little slower (~500cc), 2 | ; but this is rarely (if ever) a time-critical piece of code. 3 | ; 4 | ; It sets up the 257-byte interrut vector at im2table. Note that im2table needs 5 | ; to be a multiple of 256, for example, 0x8800 is 0x88*256. In that example, the 6 | ; the im2table is filled with 0x89. If im2table == 0x9000, then it would be 7 | ; filled ith 0x91, and in general, (im2table/256)+1. 8 | 9 | setupim2: 10 | di 11 | ld hl,im2table ; multiple of 256 which means L = 0 12 | ld a,h 13 | ld i,a 14 | im 2 15 | inc a 16 | loop: 17 | ld (hl),a 18 | inc l 19 | jr nz,loop 20 | inc h 21 | ld (hl),a 22 | ld l,a 23 | 24 | ; HL points to where the interrupt handler should be, so store whatever needs 25 | ; to be there. For example, if your interrupt is my_interrupt, you could store 26 | ; a `jp my_interrupt` command at HL: 27 | 28 | ; ld (hl),$c3 29 | ; inc l 30 | ; ld (hl),my_interrupt & $ff 31 | ; inc l 32 | ; ld (hl),my_interrupt >> 8 33 | 34 | 35 | ei 36 | ret 37 | -------------------------------------------------------------------------------- /math/division/HLDE_Div_C.z80: -------------------------------------------------------------------------------- 1 | HLDE_Div_C: 2 | ;Input: HLDE is numerator, C<129 is the divisor. 3 | ;Output: HLDE is quotient, A is remainder, C is negated 4 | ;1021+4{0,15} 5 | ;min: 1021cc 6 | ;max: 1081cc 7 | ;min: 1051cc 8 | ;87 bytes 9 | xor a 10 | sub c 11 | ld c,a 12 | HLDE_Div_negC: 13 | ;Note: -C<129 14 | ;1009+4{0,15} 15 | ;min: 1009cc 16 | ;max: 1069cc 17 | ;min: 1039cc 18 | ;84 bytes 19 | xor a 20 | call +_ 21 | ld b,h 22 | 23 | ld h,l 24 | call +_ 25 | ld l,h 26 | 27 | ld h,d 28 | call +_ 29 | ld d,h 30 | 31 | ld h,e 32 | call +_ 33 | ld e,h 34 | 35 | ld h,b 36 | rl e 37 | rl d 38 | adc hl,hl 39 | ret 40 | 41 | _: 42 | ;216+7{0,1}+{0,8} 43 | ;min: 216cc 44 | ;max: 231cc 45 | ;avg: 224.5cc 46 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c 47 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c 48 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c 49 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c 50 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c 51 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c 52 | rl h \ rla \ add a,c \ jr c,$+3 \ sub c 53 | rl h \ rla \ add a,c \ ret c \ sub c 54 | ret 55 | -------------------------------------------------------------------------------- /conversion/uint32tostr_baseC.z80: -------------------------------------------------------------------------------- 1 | uint32tostr_dec: 2 | ;Inputs: 3 | ; DEHL is the number to display 4 | ; IX points to the end of the output location 5 | ;Outputs: 6 | ; A, B, D, E is 0 7 | ; C is 10 8 | ; HL points to the base-10 string. 9 | ;NOTE: This does not put a 0 byte at the end 10 | ld c,10 11 | uint32tostr: 12 | ;Inputs: 13 | ; C is the base 14 | ; DEHL is the number to display 15 | ; IX points to the end of the output location 16 | ; NOTE: If you want the string to be null-terminated, you'll have to 17 | ; write a 0 to IX yourself. 18 | ;Outputs: 19 | ; A, B, D, E is 0 20 | ; C is not changed 21 | ; HL points to the string 22 | ;NOTE: This does not put a 0 byte at the end 23 | ld b,32 24 | xor a 25 | _: 26 | add hl,hl 27 | rl e 28 | rl d 29 | rla 30 | cp c 31 | jr c,$+4 32 | inc l 33 | sub c 34 | djnz -_ 35 | add a,30h 36 | cp 3Ah 37 | jr c,+_ 38 | add a,7 39 | _: 40 | dec ix 41 | ld (ix),a 42 | ld a,h 43 | or l \ or d \ or e 44 | jr nz,uint32tostr 45 | push ix 46 | pop hl 47 | ret 48 | -------------------------------------------------------------------------------- /math/misc/pow2fixed_88.z80: -------------------------------------------------------------------------------- 1 | pow2: 2 | ;Inputs: 3 | ; HL is the 8.8 fixed point number 'x' for 2^x 4 | ;Outputs: 5 | ; DEHL is the 24.8 fixed point result. If there was overflow exceeding 2^24, then this value is set to the max. 6 | ld a,l 7 | or a 8 | push hl ;save H for later, H is the integer part of the power 9 | ld hl,1 10 | jr z,integerpow 11 | scf ;set the carry flag so that a bit is rotated into a. This will act as our counter. 12 | ;wait until we come across the lowest bit. Also note that we 13 | rra 14 | jr nc,$-1 15 | ld hl,2*256 16 | powloop: 17 | push af 18 | call FPSqrtHL ;returns in HL 19 | pop af 20 | srl a 21 | jr z,integerpow 22 | jr nc,powloop 23 | add hl,hl 24 | jp powloop 25 | integerpow: 26 | pop bc 27 | ;Now b is the integer part for 2^x that we need to multiply HL by. 28 | ld de,0 29 | ld a,b 30 | or a 31 | ret z 32 | 33 | add hl,hl 34 | rl e \ rl d \ jr c,wayoverflow 35 | djnz $-7 36 | ret 37 | wayoverflow: 38 | ld hl,-1 39 | ld d,h 40 | ld e,l 41 | ret 42 | -------------------------------------------------------------------------------- /ti8x/utility/getbatterylevel.z80: -------------------------------------------------------------------------------- 1 | ;NOTE: This routine may be under a different License. 2 | 3 | ;created by KermMartian, based off code by SirCmpwn (Drew DeVault) 4 | ;Optimized by Zeda 5 | ;Gets an accurate battery level on non-TI-83+ devices. 6 | 7 | ; Outputs: B: Value from 0-4 indicating battery level (0 is critical) 8 | ; Outputs: B: Value from 0-4 indicating battery level (0 is critical) 9 | GetBatteryLevel: 10 | push af 11 | in a, (2) 12 | rlca ;Roll bit 7 into carry. 13 | jr c, GetBatteryLevel_Not3Plus 14 | in a, (2) 15 | and 1 16 | ld b, a 17 | pop af 18 | ret 19 | GetBatteryLevel_Not3Plus: 20 | ld b,3 21 | GetBatteryLevelLoop: 22 | ld a,b 23 | rrca 24 | rrca 25 | and $C0 26 | push hl ; Wasting clock cycles 27 | inc hl ; Not sure if needed 28 | dec hl ; I didn't write the routine 29 | pop hl ; Just making it smaller. 30 | or %00000110 31 | out (6), a 32 | in a, (2) 33 | bit 0, a 34 | jr z, GetBatteryLevel_Done 35 | djnz GetBatteryLevelLoop 36 | ld b,4 37 | GetBatteryLevel_Done: 38 | ld a, %110 39 | out (6), a 40 | pop af 41 | ret 42 | -------------------------------------------------------------------------------- /math/division/sdiv24_16.z80: -------------------------------------------------------------------------------- 1 | ;Signed division CHL/DE by Zeda, inspired by code from matrefeytontias. 2 | 3 | ;signed CHL/DE 4 | sdiv24_16: 5 | ;signed CHL/DE ==> CHL, |remainder| is DE 6 | 7 | ;Get the sign of the result 8 | ld a,c 9 | xor d 10 | push af 11 | 12 | ;Make BHL positive 13 | xor d 14 | jp p,+_ 15 | xor a 16 | sub l 17 | ld l,a 18 | ld a,0 19 | sbc a,h 20 | ld h,a 21 | sbc a,a 22 | sub c 23 | ld c,a 24 | _: 25 | 26 | ;make DE negative 27 | bit 7,d 28 | jr z,+_ ;setting DE negative 29 | xor a 30 | sub e 31 | ld e,a 32 | sbc a,a 33 | sub d 34 | ld d,a 35 | ld a,c 36 | _: 37 | 38 | ld b,24 39 | push hl 40 | pop ix 41 | ld hl,0 42 | 43 | div2416loop: 44 | add ix,ix 45 | rla 46 | adc hl,hl 47 | add hl,de 48 | jr c,+_ 49 | sbc hl,de 50 | .db $DA ;start or `jp c,**` 51 | _: 52 | inc ixl 53 | djnz div2416loop 54 | ld c,a 55 | ex de,hl ;DE is remainder 56 | 57 | push ix 58 | pop hl 59 | 60 | ;restore sign 61 | pop af 62 | ret p 63 | xor a 64 | sub l 65 | ld l,a 66 | ld a,b 67 | sbc a,h 68 | ld h,a 69 | sbc a,a 70 | sub c 71 | ld c,a 72 | ret 73 | -------------------------------------------------------------------------------- /ti8x/gfx/bigsprite_OR.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/bigsprite_subroutine.z80" 2 | bigsprite_OR: 3 | ;Inputs: 4 | ; B is the X-coordinate 5 | ; C is the Y-Coordinate 6 | ; DE points to the sprite 7 | ; H is the height 8 | ; L is the width 9 | ;68 bytes 10 | 11 | ;Set up the clipping 12 | call bigsprite_subroutine 13 | ret nc 14 | 15 | bigsprite_OR_loop: 16 | push bc ;height,width 17 | push de ;gbuf ptr 18 | push hl ;sprite data pointer 19 | ld a,(sprite_x) 20 | ld c,a 21 | add a,8 22 | ld (sprite_x),a 23 | 24 | spriteloop_OR: 25 | push bc 26 | push hl 27 | ld h,(hl) 28 | xor a 29 | call call_ix 30 | ld a,c 31 | cp 96 32 | jr nc,+_ 33 | ld a,(hl) 34 | or d 35 | ld (hl),a 36 | ld a,c 37 | _: 38 | inc hl 39 | add a,8 40 | cp 96 41 | jr nc,+_ 42 | ld a,(sprite_mask1) 43 | ld a,(hl) 44 | or e 45 | ld (hl),a 46 | _: 47 | ld bc,11 48 | add hl,bc 49 | ex de,hl 50 | pop hl 51 | ld a,(sprite_width) 52 | ld c,a 53 | add hl,bc 54 | pop bc 55 | djnz spriteloop_OR 56 | 57 | 58 | pop hl 59 | inc hl 60 | pop de 61 | inc de 62 | pop bc 63 | dec c 64 | jr nz,bigsprite_OR_loop 65 | ret 66 | -------------------------------------------------------------------------------- /math/division/BC_Div_DE.z80: -------------------------------------------------------------------------------- 1 | BC_Div_DE: 2 | ld hl,0 3 | inc d 4 | dec d 5 | jr z,smalldiv 6 | ld l,b 7 | ld b,h 8 | nextpart: 9 | ld a,c 10 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 11 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 12 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 13 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 14 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 15 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 16 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 17 | rla \ adc hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de 18 | cpl 19 | ld c,a 20 | ret 21 | smalldiv: 22 | xor a 23 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 24 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 25 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 26 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 27 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 28 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 29 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 30 | rl b \ rla \ sub e \ jr nc,$+3 \ add a,e 31 | ld l,a 32 | ld a,b 33 | cpl 34 | ld b,a 35 | jp nextpart 36 | -------------------------------------------------------------------------------- /ti8x/gfx/bigsprite_Erase.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/bigsprite_subroutine.z80" 2 | bigsprite_Erase: 3 | ;Inputs: 4 | ; B is the X-coordinate 5 | ; C is the Y-Coordinate 6 | ; DE points to the sprite 7 | ; H is the height 8 | ; L is the width 9 | ;82 bytes 10 | 11 | ;Set up the clipping 12 | call bigsprite_subroutine 13 | ret nc 14 | 15 | bigsprite_Erase_loop: 16 | push bc ;height,width 17 | push de ;gbuf ptr 18 | push hl ;sprite data pointer 19 | ld a,(sprite_x) 20 | ld c,a 21 | add a,8 22 | ld (sprite_x),a 23 | 24 | spriteloop_Erase: 25 | push bc 26 | push hl 27 | ld h,(hl) 28 | xor a 29 | call call_ix 30 | ld a,c 31 | cp 96 32 | jr nc,+_ 33 | ld a,d 34 | cpl 35 | and (hl) 36 | ld (hl),a 37 | ld a,c 38 | _: 39 | inc hl 40 | add a,8 41 | cp 96 42 | jr nc,+_ 43 | ld a,e 44 | cpl 45 | and (hl) 46 | ld (hl),a 47 | _: 48 | ld bc,11 49 | add hl,bc 50 | ex de,hl 51 | pop hl 52 | ld a,(sprite_width) 53 | ld c,a 54 | add hl,bc 55 | pop bc 56 | djnz spriteloop_Erase 57 | 58 | pop hl 59 | inc hl 60 | pop de 61 | inc de 62 | pop bc 63 | dec c 64 | jr nz,bigsprite_Erase_loop 65 | ret 66 | -------------------------------------------------------------------------------- /ti8x/gfx/bigsprite_XOR.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/bigsprite_subroutine.z80" 2 | bigsprite_XOR: 3 | ;Inputs: 4 | ; B is the X-coordinate 5 | ; C is the Y-Coordinate 6 | ; DE points to the sprite 7 | ; H is the height 8 | ; L is the width 9 | ;83 bytes 10 | 11 | ;Set up the clipping 12 | call bigsprite_subroutine 13 | ret nc 14 | 15 | bigsprite_XOR_loop: 16 | push bc ;height,width 17 | push de ;gbuf ptr 18 | push hl ;sprite data pointer 19 | ld a,(sprite_x) 20 | ld c,a 21 | add a,8 22 | ld (sprite_x),a 23 | 24 | spriteloop_XOR: 25 | push bc 26 | push hl 27 | ld h,(hl) 28 | xor a 29 | call call_ix 30 | ld a,c 31 | cp 96 32 | jr nc,+_ 33 | ld a,(hl) 34 | xor d 35 | ld (hl),a 36 | ld a,c 37 | _: 38 | inc hl 39 | add a,8 40 | cp 96 41 | jr nc,+_ 42 | ld a,(sprite_mask1) 43 | ld a,(hl) 44 | xor e 45 | ld (hl),a 46 | _: 47 | ld bc,11 48 | add hl,bc 49 | ex de,hl 50 | pop hl 51 | ld a,(sprite_width) 52 | ld c,a 53 | add hl,bc 54 | pop bc 55 | djnz spriteloop_XOR 56 | 57 | 58 | pop hl 59 | inc hl 60 | pop de 61 | inc de 62 | pop bc 63 | dec c 64 | jr nz,bigsprite_XOR_loop 65 | ret 66 | -------------------------------------------------------------------------------- /conversion/string_to_uint16.z80: -------------------------------------------------------------------------------- 1 | ;Converts an ASCII string to an unsigned 16-bit integer 2 | ;Quits when it reaches a non-decimal digit 3 | 4 | string_to_uint16: 5 | atoui_16: 6 | ;Input: 7 | ; DE points to the string 8 | ;Outputs: 9 | ; HL is the result 10 | ; A is the 8-bit value of the number 11 | ; DE points to the byte after the number 12 | ;Destroys: 13 | ; BC 14 | ; if the string is non-empty, BC is HL/10 15 | ;Size: 24 bytes 16 | ;Speed: 42+d(104+{0,9}) 17 | ; d is the number of digits in the number 18 | ; max is 640 cycles for a 5 digit number 19 | ;Assuming no leading zeros: 20 | ;1 digit: 146cc 21 | ;2 digit: 250cc 22 | ;3 digit: 354cc or 363cc (avg: 354.126cc) 23 | ;4 digit: 458cc or 467cc (avg: 458.27cc) 24 | ;5 digit: 562cc or 571cc or 580cc (avg: 562.4104cc) 25 | ;avg: 544.81158447265625cc (544+13297/16384) 26 | ;=============================================================== 27 | ld hl,0 28 | _: 29 | ld a,(de) 30 | sub 30h 31 | cp 10 32 | ret nc 33 | inc de 34 | ld b,h 35 | ld c,l 36 | add hl,hl 37 | add hl,hl 38 | add hl,bc 39 | add hl,hl 40 | add a,l 41 | ld l,a 42 | jr nc,-_ 43 | inc h 44 | jp -_ 45 | -------------------------------------------------------------------------------- /ti8x/gfx/bigsprite_AND.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/bigsprite_subroutine.z80" 2 | bigsprite_AND: 3 | ;Inputs: 4 | ; B is the X-coordinate 5 | ; C is the Y-Coordinate 6 | ; DE points to the sprite 7 | ; H is the height 8 | ; L is the width 9 | ;78 bytes 10 | 11 | ;Set up the clipping 12 | call bigsprite_subroutine 13 | ret nc 14 | 15 | bigsprite_AND_loop: 16 | push bc ;height,width 17 | push de ;gbuf ptr 18 | push hl ;sprite data pointer 19 | ld a,(sprite_x) 20 | ld c,a 21 | add a,8 22 | ld (sprite_x),a 23 | 24 | spriteloop_AND: 25 | push bc 26 | push hl 27 | ld h,(hl) 28 | scf \ sbc a,a 29 | call call_ix 30 | ld a,c 31 | cp 96 32 | jr nc,+_ 33 | ld a,(hl) 34 | and d 35 | ld (hl),a 36 | ld a,c 37 | _: 38 | inc hl 39 | add a,8 40 | cp 96 41 | jr nc,+_ 42 | ld a,(sprite_mask1) 43 | ld a,(hl) 44 | and e 45 | ld (hl),a 46 | _: 47 | ld bc,11 48 | add hl,bc 49 | ex de,hl 50 | pop hl 51 | ld a,(sprite_width) 52 | ld c,a 53 | add hl,bc 54 | pop bc 55 | djnz spriteloop_AND 56 | 57 | 58 | pop hl 59 | inc hl 60 | pop de 61 | inc de 62 | pop bc 63 | dec c 64 | jr nz,bigsprite_AND_loop 65 | ret 66 | -------------------------------------------------------------------------------- /ti8x/gfx/putbigsprite.z80: -------------------------------------------------------------------------------- 1 | PutSpriteXxY: 2 | ;Inputs: 3 | ; a is the height 4 | ; b 5 | ; de points to the sprite data 6 | ; hl points to the output location on plotSScreen 7 | ;Outputs: 8 | ; a is 0 9 | ; b is unchanged 10 | ; c is 12-b 11 | ; hl is a*12 larger (next sprite down?) 12 | ; de points to data after sprite 13 | ;**As a note, the tenth byte or PutSpriteXxY+9 can be changed to some form of 14 | ;logic since my calls are usually in RAM, I usually give the option of sprite 15 | ;logic, so I change this byte instead of making the call 4 different times. 16 | ld (hl),a ;77 17 | ld a,12 ;3E0C 18 | sub b ;90 19 | ld c,a ;4F 20 | ld a,(hl) ;7E 21 | Loop1: 22 | push bc ;C5 23 | push af ;F5 24 | Loop2: 25 | ld a,(de) ;1A 26 | nop ;00 This byte gets changed to logic... read the note 27 | ld (hl),a ;77 28 | inc de ;13 29 | inc hl ;23 30 | djnz -7 ;10F9 31 | add hl,bc ;09 32 | pop af ;F1 33 | pop bc ;C1 34 | dec a ;3D 35 | jr nz,-15 ;20F1 36 | ret ;C9 37 | -------------------------------------------------------------------------------- /math/misc/log2fixed_88.z80: -------------------------------------------------------------------------------- 1 | Log_2_88_size: 2 | ;Inputs: 3 | ; HL is an unsigned 8.8 fixed point number. 4 | ;Outputs: 5 | ; HL is the signed 8.8 fixed point value of log base 2 of the input. 6 | ;Example: 7 | ; pass HL = 3.0, returns 1.58203125 (actual is ~1.584962501...) 8 | ;averages about 39 t-states slower than original 9 | ;62 bytes 10 | ex de,hl 11 | ld hl,0 12 | ld a,d 13 | ld c,8 14 | or a 15 | jr z,DE_lessthan_1 16 | srl d 17 | jr z,logloop-1 18 | inc l 19 | rr e 20 | jr $-7 21 | DE_lessthan_1: 22 | ld a,e 23 | dec hl 24 | or a 25 | ret z 26 | inc l 27 | dec l 28 | add a,a 29 | jr nc,$-2 30 | ld e,a 31 | 32 | inc d 33 | logloop: 34 | add hl,hl 35 | push hl 36 | ld h,d 37 | ld l,e 38 | ld a,e 39 | ld b,8 40 | 41 | add hl,hl 42 | rla 43 | jr nc,$+5 44 | add hl,de 45 | adc a,0 46 | djnz $-7 47 | 48 | ld e,h 49 | ld d,a 50 | pop hl 51 | rr a ;this is NOT supposed to be rra, we need the z flag affected 52 | jr z,$+7 53 | srl d 54 | rr e 55 | inc l 56 | dec c 57 | jr nz,logloop 58 | ret 59 | -------------------------------------------------------------------------------- /ti8x/gfx/bigsprite_Overwrite.z80: -------------------------------------------------------------------------------- 1 | #include "ti8x/gfx/bigsprite_subroutine.z80" 2 | bigsprite_Overwrite: 3 | ;Inputs: 4 | ; B is the X-coordinate 5 | ; C is the Y-Coordinate 6 | ; DE points to the sprite 7 | ; H is the height 8 | ; L is the width 9 | ;86 bytes 10 | 11 | ;Set up the clipping 12 | call bigsprite_subroutine 13 | ret nc 14 | 15 | bigsprite_Overwrite_loop: 16 | push bc ;height,width 17 | push de ;gbuf ptr 18 | push hl ;sprite data pointer 19 | ld a,(sprite_x) 20 | ld c,a 21 | add a,8 22 | ld (sprite_x),a 23 | 24 | spriteloop_Overwrite: 25 | push bc 26 | push hl 27 | ld h,(hl) 28 | xor a 29 | call call_ix 30 | ld a,c 31 | cp 96 32 | jr nc,+_ 33 | ld a,(sprite_mask0) 34 | and (hl) 35 | or d 36 | ld (hl),a 37 | ld a,c 38 | _: 39 | inc hl 40 | add a,8 41 | cp 96 42 | jr nc,+_ 43 | ld a,(sprite_mask1) 44 | and (hl) 45 | or e 46 | ld (hl),a 47 | _: 48 | ld bc,11 49 | add hl,bc 50 | ex de,hl 51 | pop hl 52 | ld a,(sprite_width) 53 | ld c,a 54 | add hl,bc 55 | pop bc 56 | djnz spriteloop_Overwrite 57 | 58 | pop hl 59 | inc hl 60 | pop de 61 | inc de 62 | pop bc 63 | dec c 64 | jr nz,bigsprite_Overwrite_loop 65 | ret 66 | -------------------------------------------------------------------------------- /math/squareroot/sqrtA_fastest.z80: -------------------------------------------------------------------------------- 1 | ;Written by Zeda 2 | 3 | sqrtA: 4 | ;Input: A 5 | ;Output: D is the squareroot, A is the remainder (input-D^2) 6 | ;Destroys: E 7 | ;speed: 118+{0,6}+{0,7}+{0,7}+{0,3} 8 | ;min: 118cc 9 | ;max: 141cc 10 | ;avg: 129.5cc 11 | ;38 bytes 12 | ld de,5040h ; 10 13 | sub e ; 4 14 | jr nc,sqrtA_skip1 ;\ 15 | add a,e ; | branch 1: 12cc 16 | ld d,10h ; | branch 2: 18cc 17 | sqrtA_skip1: ;/ 18 | 19 | ; ---------- 20 | cp d ; 4 21 | jr c,sqrtA_skip2 ;\ 22 | sub d ; | branch 1: 12cc 23 | set 5,d ; | branch 2: 19cc 24 | sqrtA_skip2: ;/ 25 | 26 | ; ---------- 27 | res 4,d ; 8 28 | srl d ; 8 29 | set 2,d ; 8 30 | cp d ; 4 31 | jr c,sqrtA_skip3 ;\ 32 | sub d ; | branch 1: 12cc 33 | set 3,d ; | branch 2: 19cc 34 | sqrtA_skip3: ;/ 35 | srl d ; 8 36 | 37 | ; ---------- 38 | inc a ; 4 39 | sub d ; 4 40 | jr nc,sqrtA_skip4 ;\ 41 | dec d ; | branch 1: 12cc 42 | add a,d ; | branch 2: 15cc 43 | sqrtA_skip4: ;/ 44 | srl d ; 8 45 | ret ; 10 46 | -------------------------------------------------------------------------------- /ti8x/gfx/gray4v.z80: -------------------------------------------------------------------------------- 1 | gray4v: 2 | ;Inputs: (buf0) is the secondary (lighter) buffer (vertically aligned) 3 | ; (buf1) is the primary (darker) buffer (vertically aligned) 4 | ;Destroys none 5 | ;62260cc 6 | ;Minimum time between writes is 69cc, so not suitable for 15MHz 7 | ;Expects y-increment mode and LCD_Y set to 0. 8 | ;Exits with LCD_Y preserved 9 | push hl 10 | push de 11 | push bc 12 | push af 13 | buf0=$+1 14 | ld hl,plotSScreen 15 | buf1=$+1 16 | ld de,saveSScreen 17 | ld a,20h 18 | graymask=$+1 19 | ld c,%11011011 20 | rowloop: 21 | ld b,64 22 | push af 23 | out (16),a 24 | colloop: 25 | ld a,c ;\ 26 | cp $C0 ; | 27 | rra ; |Rotate the graymask. 28 | ld c,a ;/ Can be efficiently done by rotating left while shifting in the XOR of the top two bits. 29 | ld a,(de) 30 | xor (hl) 31 | and c 32 | xor (hl) 33 | out (17),a 34 | inc hl 35 | inc de 36 | djnz colloop 37 | pop af 38 | inc a 39 | cp 2Ch 40 | jp nz,rowloop 41 | ld a,c ;\ 42 | cp $C0 ; | 43 | rra ; |Rotate the graymask again 44 | ld (graymask),a 45 | pop af 46 | pop bc 47 | pop de 48 | pop hl 49 | ret 50 | -------------------------------------------------------------------------------- /math/division/BC_Div_DE_faster.z80: -------------------------------------------------------------------------------- 1 | BC_Div_DE: 2 | ;BC/DE ==> BC, remainder in HL 3 | ;NOTE: BC/0 returns 0 as the quotient. 4 | ;min: 738cc 5 | ;max: 898cc 6 | ;avg: 818cc 7 | ;144 bytes 8 | xor a 9 | ld h,a 10 | ld l,a 11 | sub e 12 | ld e,a 13 | sbc a,a 14 | sub d 15 | ld d,a 16 | 17 | ld a,b 18 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 19 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 20 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 21 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 22 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 23 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 24 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 25 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 26 | rla 27 | ld b,a 28 | 29 | ld a,c 30 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 31 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 32 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 33 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 34 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 35 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 36 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 37 | rla \ adc hl,hl \ add hl,de \ jr c,$+4 \ sbc hl,de 38 | rla 39 | ld c,a 40 | 41 | ret 42 | -------------------------------------------------------------------------------- /math/multiplication/mulfixed_88.z80: -------------------------------------------------------------------------------- 1 | mulfixed_88: 2 | ;Multiplies H.L by D.E, stores the result in H.L 3 | ; First, find out if the output is positive or negative 4 | ld a,h 5 | xor d 6 | push af ;sign bit is the result sign bit 7 | 8 | ; Now make sure the inputs are positive 9 | xor d ;A now has the value of H, since I XORed it with D twice (cancelling) 10 | jp p,+_ ;if Positive, don't negate 11 | xor a 12 | sub l 13 | ld l,a 14 | sbc a,a 15 | sub h 16 | ld h,a 17 | _: 18 | bit 7,d 19 | jr z,+_ 20 | xor a 21 | sub e 22 | ld e,a 23 | sbc a,a 24 | sub d 25 | ld d,a 26 | _: 27 | 28 | ; Now we need to put HL in BC to use mul16 29 | ld b,h 30 | ld c,l 31 | call mul16 32 | 33 | ;Need to round, so get the top bit of L 34 | sla l 35 | 36 | ;Get the middle two bytes, EH, and put them in HL 37 | ld l,h 38 | ld h,e 39 | 40 | ld a,d 41 | ld de,0 42 | adc hl,de 43 | 44 | ;check for overflow! 45 | ;We should check for overflow. If A>0, we will set HL to 0x7FFF 46 | adc a,e 47 | jr c,$+4 48 | jr z,+_ 49 | ld hl,$7FFF 50 | _: 51 | 52 | ; Now we need to restore the sign 53 | pop af 54 | ret p ;don't need to do anything, result is already positive 55 | xor a 56 | sub l 57 | ld l,a 58 | sbc a,a 59 | sub h 60 | ld h,a 61 | ret 62 | -------------------------------------------------------------------------------- /ti8x/gfx/getpixelloc_v.z80: -------------------------------------------------------------------------------- 1 | ;Written by Zeda 2 | ;This code is for getting the address and mask for a pixel on a _vertical_ 3 | ;aligned buffer. (Stored in 12 columns of 64 bytes each.) 4 | 5 | getpixelloc: 6 | ;column-major order 7 | ;Input: bc = (x,y) 8 | ;Output: nc if out-of-bounds, HL is the offset into a column-major buffer, A is the pixel mask 9 | ld a,c 10 | cp 64 11 | ret nc 12 | ld a,b 13 | cp 96 14 | ret nc 15 | ; a = x 16 | ; compute (x/8)*64 17 | ; dividing by 8 is three right shifts. We then multiply by 64 (6 left shifts). Shifting right 3 times then left 3 times has a net effect of setting the lower three bits to 0. So instead, we just set the lower three bits to 0 and shift left three times. 18 | and %11111000 19 | ld h,0 20 | add a,a ;a is less than 128, so no information is lost here, and it is 7 cycles faster than add hl,hl 21 | ld l,a 22 | ld a,b ;we will need this for later 23 | ld b,h ;h = 0 at this point, so now BC =Y 24 | add hl,hl 25 | add hl,hl 26 | add hl,bc 27 | ; HL = (x/8)*64+y 28 | ; now a = x , HL is the offset into the buffer 29 | ; we need to compute the pixel mask 30 | and 7 31 | ld b,a 32 | ld a,$80 33 | ret z 34 | rrca 35 | djnz $-1 36 | scf 37 | ret 38 | -------------------------------------------------------------------------------- /conversion/uitoa_16.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_uitoa_16 2 | #define included_uitoa_16 3 | 4 | ;written by Zeda 5 | ;Converts a 16-bit unsigned integer to an ASCII string. 6 | 7 | uitoa_16: 8 | ;Input: 9 | ; DE is the number to convert 10 | ; HL points to where to write the ASCII string (up to 6 bytes needed). 11 | ;Output: 12 | ; HL points to the null-terminated ASCII string 13 | ; NOTE: This isn't necessarily the same as the input HL. 14 | push de 15 | push bc 16 | push af 17 | ex de,hl 18 | 19 | ld bc,-10000 20 | ld a,'0'-1 21 | inc a \ add hl,bc \ jr c,$-2 22 | ld (de),a 23 | inc de 24 | 25 | ld bc,1000 26 | ld a,'9'+1 27 | dec a \ add hl,bc \ jr nc,$-2 28 | ld (de),a 29 | inc de 30 | 31 | ld bc,-100 32 | ld a,'0'-1 33 | inc a \ add hl,bc \ jr c,$-2 34 | ld (de),a 35 | inc de 36 | 37 | ld a,l 38 | ld h,'9'+1 39 | dec h \ add a,10 \ jr nc,$-3 40 | add a,'0' 41 | ex de,hl 42 | ld (hl),d 43 | inc hl 44 | ld (hl),a 45 | inc hl 46 | ld (hl),0 47 | 48 | ;Now strip the leading zeros 49 | ld c,-6 50 | add hl,bc 51 | ld a,'0' 52 | inc hl \ cp (hl) \ jr z,$-2 53 | 54 | ;Make sure that the string is non-empty! 55 | ld a,(hl) 56 | or a 57 | jr nz,+_ 58 | dec hl 59 | _: 60 | 61 | pop af 62 | pop bc 63 | pop de 64 | ret 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /ti8x/utility/setXX.z80: -------------------------------------------------------------------------------- 1 | ;Works like the TI-OS setXXOP1 and setXXOP2 routine. 2 | setXXOP2: 3 | ld hl,OP2 4 | jr setXX 5 | setXXOP1: 6 | ld hl,OP1 7 | setXX: 8 | ;Inputs: A is the unsigned int 9 | ; HL is where to write the TI float 10 | ;Destroys:All 11 | ;291cc+38b (or 144cc if A=0) 12 | ;average: b=29/255 13 | ;295.3215686cc 14 | ;59 bytes 15 | ld c,0 16 | ld (hl),c \ inc hl 17 | ld (hl),81h 18 | inc hl \ ld (hl),c 19 | ld d,h \ ld e,l 20 | inc hl \ ld (hl),c 21 | inc hl \ ld (hl),c 22 | inc hl \ ld (hl),c 23 | inc hl \ ld (hl),c 24 | inc hl \ ld (hl),c 25 | inc hl \ ld (hl),c 26 | 27 | or a \ ret z ;If A is zero, exit early. +138cc 28 | ld l,a ;\ 29 | ld h,c ; | 30 | add hl,hl ; |Start converting A to BCD 31 | add hl,hl ; | 32 | add hl,hl ; | 33 | add hl,hl ; | 34 | ld a,h \ daa \ rl l ; |Finish converting A to BCD 35 | adc a,a \ daa \ rl l ; |Number is in LA 36 | adc a,a \ daa \ rl l ; | 37 | adc a,a \ daa \ rl l ; | 38 | adc a,a \ daa ;/ +124cc 39 | ex de,hl 40 | ld (hl),a 41 | and $F0 42 | ret nz ;+29cc 43 | rld ;\ Rotate up 1 digit 44 | dec hl ; | 45 | ld (hl),80h ; | 46 | ret ; / 47 | -------------------------------------------------------------------------------- /math/division/HL_Div_B_fast.z80: -------------------------------------------------------------------------------- 1 | HL_Div_B: 2 | ;I'm not postive on the timing. 3 | ;min: 203 4 | ;max: 308 5 | ;avg: 236.125 6 | add hl,hl 7 | ld a,h 8 | jr c,div16_8_2_0 9 | cp b \ jr c,$+4 \ sub b \ inc l 10 | sla l \ rla \ jr c,div16_8_2_1 11 | div16_8_1_1: 12 | cp b \ jr c,$+4 \ sub b \ inc l 13 | sla l \ rla \ jr c,div16_8_2_2 14 | div16_8_1_2: 15 | cp b \ jr c,$+4 \ sub b \ inc l 16 | sla l \ rla \ jr c,div16_8_2_3 17 | div16_8_1_3: 18 | cp b \ jr c,$+4 \ sub b \ inc l 19 | sla l \ rla \ jr c,div16_8_2_4 20 | div16_8_1_4: 21 | cp b \ jr c,$+4 \ sub b \ inc l 22 | sla l \ rla \ jr c,div16_8_2_5 23 | div16_8_1_5: 24 | cp b \ jr c,$+4 \ sub b \ inc l 25 | sla l \ rla \ jr c,div16_8_2_6 26 | div16_8_1_6: 27 | cp b \ jr c,$+4 \ sub b \ inc l 28 | sla l \ rla \ jr c,div16_8_2_7 29 | div16_8_1_7: 30 | cp b \ ret c \ sub b \ inc l 31 | ret 32 | 33 | div16_8_2_0: 34 | sub b \ rl l \ rla \ jr nc,div16_8_1_1 35 | div16_8_2_1: 36 | sub b \ rl l \ rla \ jr nc,div16_8_1_2 37 | div16_8_2_2: 38 | sub b \ rl l \ rla \ jr nc,div16_8_1_3 39 | div16_8_2_3: 40 | sub b \ rl l \ rla \ jr nc,div16_8_1_4 41 | div16_8_2_4: 42 | sub b \ rl l \ rla \ jr nc,div16_8_1_5 43 | div16_8_2_5: 44 | sub b \ rl l \ rla \ jr nc,div16_8_1_6 45 | div16_8_2_6: 46 | sub b \ rl l \ rla \ jr nc,div16_8_1_7 47 | div16_8_2_7: 48 | sub b \ inc l 49 | ret -------------------------------------------------------------------------------- /ti8x/utility/fastLDIR.z80: -------------------------------------------------------------------------------- 1 | ;This is a general-purpose faster-than-LDIR code to replace LDIR in speed- 2 | ;critical situations. 3 | fastLDIR: 4 | ;copy BC bytes from HL to DE 5 | ;Cost: 6 | ; 27cc for having to call 7 | ; 110cc for setting up the loop, worst case 8 | ; 10cc * ceiling(BC/n) ;n=2^k for some k, see the line below "ldirloop:" 9 | ; 16cc * BC 10 | ;costs roughly 152-BC*(5-10/n) more than a simple LDIR (worst case) 11 | ;for n=4, BC>=61 saves 12 | ;for n=8, BC>=41 saves 13 | ;for n=16, BC>=35 saves * default, see the "ldirloop" to change 14 | ;for n=32, BC>=33 saves 15 | ;for n=64, BC>=32 saves 16 | push hl 17 | push af 18 | xor a 19 | sub c 20 | and 15 ;change to n-1 21 | add a,a 22 | ld hl,ldirloop 23 | add a,l 24 | ld l,a 25 | jr nc,$+3 ;these aren't needed if the ldirloop doesn't cross a 256 byte boundary. Can save 12cc on the above timings and 3 bytes. 26 | inc h ; 27 | pop af 28 | ex (sp),hl 29 | ret 30 | ldirloop: 31 | ;n=16, (number of LDI instructions, use qty of 4,8,16,32,64) 32 | ldi 33 | ldi 34 | ldi 35 | ldi 36 | 37 | ldi 38 | ldi 39 | ldi 40 | ldi 41 | 42 | ldi 43 | ldi 44 | ldi 45 | ldi 46 | 47 | ldi 48 | ldi 49 | ldi 50 | _ldirloop_end: 51 | ldi 52 | jp pe,ldirloop 53 | ret 54 | -------------------------------------------------------------------------------- /ti8x/VAT/findsym.z80: -------------------------------------------------------------------------------- 1 | ;This routine has four useful entry points, especially findSymBC! 2 | 3 | #ifndef included_FindSym 4 | #define included_FindSym 5 | 6 | FindSym: 7 | ;Inputs: 8 | ; OP1+1 contains the name of a symbol var. No type byte needed. 9 | ;Outputs: 10 | ; Same as rFindSym 11 | ld de,OP1+1 12 | 13 | FindVarSymDE: 14 | ;Inputs: 15 | ; DE points to the name of a symbol var 16 | ;Outputs: 17 | ; Same as rFindSym 18 | ex de,hl 19 | 20 | FindVarSymHL: 21 | ;Inputs: 22 | ; HL points to the name of a symbol var 23 | ;Outputs: 24 | ; Same as rFindSym 25 | ld c,(hl) 26 | inc hl 27 | ld b,(hl) 28 | 29 | findSymBC: 30 | ;Inputs: 31 | ; BC contains the name of the var to search. 32 | ; For example, if BC was 00AAh, it would search for Str1. 33 | ;Outputs: 34 | ; Same as rFindSym 35 | 36 | ld hl,symtable-6 37 | SearchLoop: 38 | ld a,c 39 | cp (hl) 40 | dec hl 41 | jr nz,advance_VATsym_ptr 42 | ld a,b 43 | cp (hl) 44 | jr z,Sym_Entry_found 45 | advance_VATsym_ptr: 46 | ld de,-8 47 | add hl,de 48 | ex de,hl 49 | ld hl,(progPtr) 50 | sbc hl,de 51 | ex de,hl 52 | jr c,SearchLoop 53 | scf 54 | Sym_Entry_found: 55 | inc hl 56 | inc hl 57 | ld b,(hl) 58 | inc hl 59 | ld d,(hl) 60 | inc hl 61 | ld e,(hl) 62 | inc hl 63 | inc hl 64 | inc hl 65 | ld a,(hl) 66 | ld c,3 67 | ret 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /math/rng/xorshift16.z80: -------------------------------------------------------------------------------- 1 | ;You may use this routine, just be sure to credit John Metcalf! 2 | ;Written by John Metcalf 3 | ; http://www.retroprogramming.com/2017/07/xorshift-pseudorandom-numbers-in-z80.html 4 | ; 5 | ; Annotated by Zeda Thomas, fixed typo (86 cycles==> 82 cycles) 6 | 7 | ;Note: uses SMC 8 | 9 | ; 16-bit xorshift pseudorandom number generator 10 | ; 20 bytes, 82 cycles (excluding ret) 11 | 12 | ; returns hl = pseudorandom number 13 | ; corrupts a 14 | 15 | xrnd: 16 | ld hl,1 ; Init the seed, must not be 0 17 | ld a,h ;\ 18 | rra ; | Get the top bits of xs<<7 and xor with the top byte of HL 19 | ld a,l ; | abcdefgh ijklmnop 20 | rra ; | ^hijklmno 00000000 21 | xor h ; | Note that we still need to xor the 'p' with the top byte of l 22 | ld h,a ;/ 23 | ld a,l ;\ 24 | rra ; | we get 'p' in the carry flag, now shift that in when we do xs>>9 25 | ld a,h ; | abcdefgh ijklmnop (new value) 26 | rra ; | ^00000000 pabcdefg 27 | xor l ; | the 'p' is leftover from the first step, so now Step 1 and 2 are done 28 | ld l,a ;/ 29 | xor h ;\ Finally, xor the bottom byte with the top byte for step 3 30 | ld h,a ;/ 31 | ld (xrnd+1),hl ; write back the new value as the next seed 32 | ret 33 | -------------------------------------------------------------------------------- /math/misc/gcdHL_DE.z80: -------------------------------------------------------------------------------- 1 | gcdHL_DE: 2 | ;gcd(HL,DE)->HL 3 | ;Output: 4 | ; B=0 5 | ; HL is the GCD of the inputs 6 | ;Destroys: 7 | ; A,DE 8 | ; DE is guaranteed 0 unless the output is 0 (which only happens if one of the inputs is 0). 9 | ;Uses the binary GCD algorithm 10 | ;65 bytes 11 | 12 | ;B is our cofactor-of-2 counter 13 | ld b,0 14 | 15 | ;If HL=0, return 0 16 | ld a,h \ or l \ ret z 17 | 18 | ;If DE=0, return 0 19 | ex de,hl 20 | ld a,h \ or l \ jr nz,gcd_test_cofactor_of_2 21 | ret 22 | 23 | gcd_cofactor_2_loop: 24 | inc b 25 | srl h \ rr l 26 | srl d \ rr e 27 | gcd_test_cofactor_of_2: 28 | inc b 29 | ld a,e 30 | or l 31 | rra 32 | jr nc,gcd_cofactor_2_loop 33 | 34 | gcd_remove_factors_of_2_op2: 35 | srl h \ rr l \ jr nc,gcd_remove_factors_of_2_op2 36 | adc hl,hl 37 | jr gcd_swap_ops 38 | 39 | gcd_swap_ops_negate: 40 | ;At this point, HL needs to be negated and swapped with DE 41 | xor a \ sub l \ ld l,a \ sbc a,a \ sub h \ ld h,a 42 | gcd_swap_ops: 43 | ex de,hl 44 | gcd_remove_factors_of_2_op1: 45 | srl h \ rr l \ jr nc,gcd_remove_factors_of_2_op1 46 | adc hl,hl 47 | sbc hl,de 48 | jr c,gcd_swap_ops_negate 49 | jp nz,gcd_remove_factors_of_2_op1 50 | 51 | ;DE is the GCD, need to shift it left B-1 times. 52 | ex de,hl 53 | dec b 54 | ret z 55 | add hl,hl \ djnz $-1 56 | ret 57 | -------------------------------------------------------------------------------- /ti8x/utility/flashtoRAM.z80: -------------------------------------------------------------------------------- 1 | ;RAM: 21+21n 2 | ;ARC, but no boundary: 118+21n 3 | ;Arc, on two pages: 21n+268 4 | ;Arc, on three pages: 21n+357 5 | or a 6 | jr z,ReadRAM ;different routine in the App, 7 | out (6),a 8 | add hl,bc 9 | ; jr c,read_from_Arc_blocks ;if you need this, you probably need a different routine. this will write on page 0. 10 | jp p,read_from_ARC_noboundary 11 | read_from_Arc_blocks: 12 | ;We will read in blocks to avoid checking page boundaries 13 | ;To do so, we first read 0x8000 - HL bytes 14 | xor a 15 | sbc hl,bc 16 | sub l \ ld l,a 17 | ld a,$80 \ sbc a,h \ ld h,a 18 | ;now we will subtract BC-HL -> BC 19 | ld a,c \ sub l \ ld c,a 20 | ld a,b \ sbc a,h \ ld b,a 21 | push bc 22 | ld b,h 23 | ld c,l 24 | sub l \ ld l,a 25 | ld a,$80 \ sbc a,h \ ld h,a 26 | ;now we read the first block 27 | block_loop: 28 | ldir 29 | ;now we increment the page and continue reading from $4000 30 | in a,(6) 31 | inc a 32 | out (6),a 33 | ld h,40h 34 | pop bc 35 | ;if BC<$4000, just LDIR the rest 36 | ld a,b 37 | sub 40h 38 | jr c,read_from_RAM 39 | ld b,a 40 | push bc 41 | ld b,h 42 | ld c,l 43 | jp block_loop 44 | read_from_ARC_noboundary: 45 | or a 46 | sbc hl,bc 47 | read_from_RAM: 48 | ldir 49 | in a,(6) 50 | ld b,a 51 | page_restore = $-ReadArcData+TSA+1 52 | ld a,0 53 | out (6),a 54 | ld a,b 55 | ld b,c 56 | ret 57 | -------------------------------------------------------------------------------- /ti8x/utility/setXXX_faster.z80: -------------------------------------------------------------------------------- 1 | setXXX: 2 | ;Inputs: A is the unsigned int 3 | ; HL is where to write the TI float 4 | ;Destroys:All 5 | ;334cc+13a+63b (or 144cc if A=0) 6 | ;average: a=99/255, b=29/255 7 | ;346.2117647cc average 8 | ;75 bytes 9 | ld c,0 10 | ld (hl),c 11 | inc hl 12 | ld (hl),83h 13 | ld d,h 14 | ld e,l 15 | inc hl \ ld (hl),c 16 | inc hl \ ld (hl),c 17 | inc hl \ ld (hl),c 18 | inc hl \ ld (hl),c 19 | inc hl \ ld (hl),c 20 | inc hl \ ld (hl),c 21 | inc hl \ ld (hl),c 22 | 23 | or a \ ret z ;If A is zero, exit early. +227cc 24 | ld l,a ;\ 25 | ld h,c ; | 26 | add hl,hl ; |Start converting A to BCD 27 | add hl,hl ; | 28 | add hl,hl ; | 29 | add hl,hl ; | 30 | ld a,h \ daa \ rl l ; |Finish converting A to BCD 31 | adc a,a \ daa \ rl l ; |Number is in LA 32 | adc a,a \ daa \ rl l ; | 33 | adc a,a \ daa \ rl l ; | 34 | adc a,a \ daa \ rl l ;/ +132cc 35 | ex de,hl 36 | jr nz,$+6 \ ld e,a \ xor a \ ld (hl),81h ;+(21+4/85)cc 37 | inc hl 38 | ld (hl),e 39 | inc hl 40 | ld (hl),a 41 | ld a,e 42 | and $F0 43 | ret nz ;+48cc 44 | rld ;\ Rotate up 1 digit 45 | dec hl ; | 46 | rld ; | 47 | dec hl ; | 48 | dec (hl) ; |Decrement exponent 49 | ret ; /+63(29/255)cc 50 | -------------------------------------------------------------------------------- /ti8x/utility/setXXX.z80: -------------------------------------------------------------------------------- 1 | ;Works like the TI-OS setXXOP1 and setXXOP2 routine, but more flexible (and faster). 2 | ;This can write 3-digit numbers :) 3 | 4 | setXXXOP1: 5 | ld hl,OP1 6 | setXXX: 7 | ;Inputs: A is the unsigned int 8 | ; HL is where to write the TI float 9 | ;Destroys:All 10 | ;423cc+13a+63b (or 233cc if A=0) 11 | ;average: a=99/255, b=29/255 12 | ;435.2117647cc average 13 | ;64 bytes 14 | ld bc,$0700 15 | ld (hl),c 16 | inc hl 17 | ld (hl),83h 18 | ld d,h 19 | ld e,l 20 | inc hl \ ld (hl),c \ djnz $-2 21 | or a \ ret z ;If A is zero, exit early. +227cc 22 | ld l,a ;\ 23 | ld h,c ; | 24 | add hl,hl ; |Start converting A to BCD 25 | add hl,hl ; | 26 | add hl,hl ; | 27 | add hl,hl ; | 28 | ld a,h \ daa \ rl l ; |Finish converting A to BCD 29 | adc a,a \ daa \ rl l ; |Number is in LA 30 | adc a,a \ daa \ rl l ; | 31 | adc a,a \ daa \ rl l ; | 32 | adc a,a \ daa \ rl l ;/ +132cc 33 | ex de,hl 34 | jr nz,$+6 \ ld e,a \ xor a \ ld (hl),81h ;+(21+4/85)cc 35 | inc hl 36 | ld (hl),e 37 | inc hl 38 | ld (hl),a 39 | ld a,e 40 | and $F0 41 | ret nz ;+48cc 42 | rld ;\ Rotate up 1 digit 43 | dec hl ; | 44 | rld ; | 45 | dec hl ; | 46 | dec (hl) ; |Decrement exponent 47 | ret ; /+63(29/255)cc 48 | -------------------------------------------------------------------------------- /ti8x/gfx/updatelcd_partial.z80: -------------------------------------------------------------------------------- 1 | updatelcd_partial: 2 | ;Inputs: 3 | ; H is the left column to start at (0 to 11) 4 | ; L is the upper row to start at (0 to 63) 5 | ; C is the width in columns (8 pixels per column) 6 | ; B is the height in rows (1 pixel per row) 7 | ;NOTES: 8 | ; Assumes that the lcd autoincrement is set to increment X (what we see as moving down) 9 | ; Assumes interrupts are either OFF or won't interfere with the LCD 10 | ; Does not do error checking on inputs! 11 | ; This should copy safely (directly polls the LCD port) 12 | ;60 bytes 13 | push bc 14 | 15 | ld d,h 16 | ld e,l 17 | 18 | ld a,h 19 | ld h,0 20 | ld b,h 21 | ld c,l 22 | add hl,hl 23 | add hl,bc 24 | add hl,hl 25 | add hl,hl 26 | ld c,a 27 | add hl,bc 28 | ld bc,plotSScreen 29 | add hl,bc 30 | 31 | set 7,e 32 | set 5,d 33 | pop bc 34 | ;B is height 35 | ;C is width 36 | ;HL points to the screen data 37 | ;D is the lcd col base 38 | ;E is the lcd row base 39 | 40 | UpdateLCD_partial_loop: 41 | ld a,d 42 | out (16),a 43 | in a,(16) \ rla \ jr c,$-3 44 | ld a,e 45 | out (16),a 46 | push hl 47 | push de 48 | push bc 49 | ld de,12 50 | UpdateLCD_partial_col: 51 | in a,(16) \ rla \ jr c,$-3 52 | ld a,(hl) 53 | add hl,de 54 | out (17),a 55 | djnz UpdateLCD_partial_col 56 | pop bc 57 | pop de 58 | pop hl 59 | inc hl 60 | inc d 61 | dec c 62 | jr nz,UpdateLCD_partial_loop 63 | ret 64 | -------------------------------------------------------------------------------- /ti8x/gfx/drawtile_v.z80: -------------------------------------------------------------------------------- 1 | ;Written by Zeda 2 | ;Draws an 8x8 tile to a vertically aligned graphics buffer. 3 | ;This uses a 12x8 grid. 4 | 5 | ;Uncomment this if you don't need to check coordinate bounds 6 | ;This will save 31cc (~10%) and 8 bytes 7 | ;#define drawtile_v_NO_BOUNDS 8 | 9 | 10 | ;if drawtile_v_FAST is defined, we'll unroll the ldir 11 | ;if FAST is defined, we'll assume you want this, but if not, you'll need to 12 | ;manually define it. 13 | ;This saves 45cc, adds 11 bytes 14 | #ifdef FAST 15 | #define drawtile_v_FAST 16 | #endif 17 | 18 | drawtile: 19 | ;Inputs : BC = (x,y), DE points to the sprite 20 | ;Output: DE points to the next sprite, HL points to the location of the next tile down. 21 | ; 303 clock cycles if in bounds. 22 | ;Returns DE pointing to the next sprite 23 | 24 | #ifdef drawtile_v_NO_BOUNDS 25 | ld a,c 26 | cp 8 27 | ret nc 28 | ld a,b 29 | cp 12 30 | ret nc 31 | or a 32 | ld l,0 33 | #else 34 | ;We need to reset the carry flag, set L = 0, A = B 35 | xor a 36 | ld l,a 37 | or b 38 | #endif 39 | 40 | rra \ rr l 41 | rra \ rr l 42 | ld h,a 43 | 44 | ld a,c 45 | add a,a 46 | add a,a 47 | add a,a 48 | add a,l 49 | ld l,a 50 | 51 | ld bc,gbuf ;change this as needed 52 | add hl,bc 53 | ex de,hl 54 | 55 | #ifdef drawtile_v_FAST 56 | ldi 57 | ldi 58 | ldi 59 | ldi 60 | ldi 61 | ldi 62 | ldi 63 | ldi 64 | #else 65 | ld bc,8 66 | ldir 67 | #endif 68 | ret 69 | -------------------------------------------------------------------------------- /math/misc/ncr_HL_DE.z80: -------------------------------------------------------------------------------- 1 | ;Written by Zeda 2 | 3 | ; Requires 4 | ; mul16 ;BC*DE ==> DEHL 5 | ; DEHL_Div_BC ;DEHL/BC ==> DEHL 6 | 7 | ncr_HL_DE: 8 | ;"n choose r", defined as n!/(r!(n-r)!) 9 | ;Computes "HL choose DE" 10 | ;Inputs: HL,DE 11 | ;Outputs: 12 | ; HL is the result 13 | ; "HL choose DE" 14 | ; carry flag reset means overflow 15 | ;Destroys: 16 | ; A,BC,DE,IX 17 | ;Notes: 18 | ; Overflow is returned as 0 19 | ; Overflow happens if HL choose DE exceeds 65535 20 | ; This algorithm is constructed in such a way that intermediate 21 | ; operations won't erroneously trigger overflow. 22 | ;66 bytes 23 | ld bc,1 24 | or a 25 | sbc hl,de 26 | jr c,ncr_oob 27 | jr z,ncr_exit 28 | sbc hl,de 29 | add hl,de 30 | jr c,$+3 31 | ex de,hl 32 | ld a,h 33 | or l 34 | push hl 35 | pop ix 36 | ncr_exit: 37 | ld h,b 38 | ld l,c 39 | scf 40 | ret z 41 | ncr_loop: 42 | push bc \ push de 43 | push hl \ push bc 44 | ld b,h 45 | ld c,l 46 | call mul16 ;BC*DE ==> DEHL 47 | pop bc 48 | call DEHL_Div_BC ;result in DEHL 49 | ld a,d 50 | or e 51 | pop bc 52 | pop de 53 | jr nz,ncr_overflow 54 | add hl,bc 55 | jr c,ncr_overflow 56 | pop bc 57 | inc bc 58 | ld a,b 59 | cp ixh 60 | jr c,ncr_loop 61 | ld a,ixl 62 | cp c 63 | jr nc,ncr_loop 64 | ret 65 | ncr_overflow: 66 | pop bc 67 | xor a 68 | ld b,a 69 | ncr_oob: 70 | ld h,b 71 | ld l,b 72 | ret 73 | -------------------------------------------------------------------------------- /ti8x/gfx/PutSprite16.z80: -------------------------------------------------------------------------------- 1 | ;Created by Fallen Ghost 2 | ;PutSprite16 3 | ; 4 | ;PutSprite8 I modified to PutSprite16. From what I've seen on Ticalc, it's the fastest. 5 | ; 6 | ;Input: 7 | ;L=Y coordinates 8 | ;A=X coordinates 9 | ;b=height of sprite 10 | ;ix=sprite location. IX+1 being the other 8 bits 11 | ; 12 | ;Output: 13 | ;IX=data after the sprite's data 14 | ; 15 | ;Destroyed: 16 | ;-AF, BC, DE, HL 17 | 18 | 19 | putSprite16: 20 | ;L=Y coordinates 21 | ;A=X coordinates 22 | ;b=height of sprite 23 | ;ix=sprite location. IX+1 being the other 8 bits 24 | ld e,l 25 | ld h,$00 26 | ld d,h 27 | add hl,de 28 | add hl,de 29 | add hl,hl 30 | add hl,hl 31 | ld e,a 32 | and $07 33 | ld c,a 34 | srl e 35 | srl e 36 | srl e 37 | add hl,de 38 | ld de,gbuf 39 | add hl,de 40 | putSprite16Loop1: 41 | ld a,(ix+0) 42 | ld d,(ix+1) 43 | ld e,$00 44 | dec c 45 | inc c 46 | jr z,putSprite16Skip1 47 | push bc 48 | putSprite16Loop2: 49 | srl a 50 | rr d 51 | rr e 52 | dec c 53 | jr nz,putSprite16Loop2 54 | pop bc 55 | putSprite16Skip1: 56 | xor (hl) 57 | ld (hl),a 58 | inc hl 59 | ld a,(hl) 60 | xor d 61 | ld (hl),a 62 | inc hl 63 | ld a,(hl) 64 | xor e 65 | ld (hl),a 66 | ld de,10 67 | add hl,de 68 | inc ix 69 | inc ix 70 | djnz putSprite16Loop1 71 | ret 72 | -------------------------------------------------------------------------------- /math/rng/xsp32.z80: -------------------------------------------------------------------------------- 1 | xsp32: 2 | ;Inputs: (seed1), (seed2), and (seed3) are 16-bit seeds. (seed1) and (seed2) can't both be 0. 3 | ;Outputs: HL is the pseudorandom number 4 | ;Destroys: A,DE,BC 5 | ;cycle: 281,474,976,645,120 6 | ;It would take about 185 years at 15MHz to repeat 7 | ;min: 258cc (236cc if using SMC) 8 | ;max: 288cc (266cc if using SMC) 9 | ;avg: 273cc (251cc if using SMC) 10 | ;63 bytes (62 bytes if using SMC) 11 | #ifdef SMC 12 | seed1 = $+1 13 | ld hl,12345 14 | seed2 = $+1 15 | ld de,6789 16 | #else 17 | ld hl,(seed1) 18 | ld de,(seed2) 19 | #endif 20 | 21 | 22 | ;first, XOR it with itself, shifted left 23 bits 23 | ;low bit of d needs to be shifted in 24 | ld a,h 25 | rra 26 | ld a,l 27 | rra 28 | jr nc,+_ 29 | rl e 30 | ccf 31 | rr e 32 | _: 33 | xor d 34 | ld d,a 35 | 36 | ;XOR it with itself, shifted right 15 bits 37 | ld a,h 38 | rla 39 | ld a,e 40 | rla 41 | xor l 42 | ld l,a 43 | 44 | ld a,e 45 | rla 46 | ld a,d 47 | rla 48 | jr nc,+_ 49 | rr e 50 | ccf 51 | rl e 52 | _: 53 | xor h 54 | ld h,a 55 | 56 | ;XOR it with itself, shifted left 17 bits 57 | ;HL<<1 58 | ld (seed1),hl 59 | add hl,hl 60 | ld a,h 61 | xor d 62 | ld h,a 63 | 64 | ld a,l 65 | xor e 66 | ld l,a 67 | ld (seed2),hl 68 | ex de,hl 69 | 70 | #ifdef SMC 71 | seed3 = $+1 72 | ld hl,33333 73 | #else 74 | ld hl,(seed3) 75 | #endif 76 | 77 | inc hl 78 | inc h 79 | ld (seed3),hl 80 | add hl,de 81 | ret 82 | -------------------------------------------------------------------------------- /conversion/fixed1616_to_str.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_fixed1616_to_str 2 | #define included_fixed1616_to_str 3 | 4 | fixed1616_to_str: 5 | ;Input: 6 | ; DE.BC is the float 7 | ; HL points to where to write the string (at least 14 bytes) 8 | ;Output: 9 | ; HL points to the string (not necessarily matching the input) 10 | bit 7,d 11 | jr z,+_ 12 | xor a 13 | sub c 14 | ld c,a 15 | ld a,0 16 | sbc a,b 17 | ld b,a 18 | ld a,0 19 | sbc a,e 20 | ld e,a 21 | sbc a,a 22 | sub d 23 | ld d,a 24 | inc hl 25 | _: 26 | push bc 27 | push af ;z flag set if no negative sign 28 | call itoa_16 29 | pop af 30 | jr z,+_ 31 | dec hl 32 | ld (hl),$1A 33 | _: 34 | pop de 35 | ld a,d 36 | or e 37 | ret z 38 | push hl 39 | 40 | ;find the end of the string 41 | xor a 42 | cpir 43 | 44 | dec hl 45 | ld (hl),'.' 46 | inc hl 47 | ex de,hl 48 | ;DE points to the output 49 | ;HL is the fractional part 50 | call fixed1616_to_str_sub 51 | call fixed1616_to_str_sub 52 | call fixed1616_to_str_sub 53 | call fixed1616_to_str_sub 54 | call fixed1616_to_str_sub 55 | call fixed1616_to_str_sub 56 | ex de,hl 57 | ld a,'0' 58 | _: 59 | dec hl 60 | cp (hl) 61 | jr z,-_ 62 | inc hl 63 | ld (hl),0 64 | pop hl 65 | ret 66 | 67 | fixed1616_to_str_sub: 68 | xor a 69 | ld b,h 70 | ld c,l 71 | add hl,hl \ rla 72 | add hl,hl \ rla 73 | add hl,bc \ adc a,$18 74 | add hl,hl \ rla 75 | ld (de),a 76 | inc de 77 | ret 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /math/multiplication/C_Times_BDE.z80: -------------------------------------------------------------------------------- 1 | C_times_BDE: 2 | ;C*BDE => CAHL 3 | ;C = 0 157 4 | ;C = 1 141 5 | ;141+ 6 | ;C>=128 135+6{0,33+{0,1}}+{0,20+{0,8}} 7 | ;C>=64 115+5{0,33+{0,1}}+{0,20+{0,8}} 8 | ;C>=32 95+4{0,33+{0,1}}+{0,20+{0,8}} 9 | ;C>=16 75+3{0,33+{0,1}}+{0,20+{0,8}} 10 | ;C>=8 55+2{0,33+{0,1}}+{0,20+{0,8}} 11 | ;C>=4 35+{0,33+{0,1}}+{0,20+{0,8}} 12 | ;C>=2 15+{0,20+{0,8}} 13 | ;min: 141cc 14 | ;max: 508cc 15 | ;avg: 349.21279907227cc 16 | 17 | ld a,b 18 | ld h,d 19 | ld l,e 20 | sla c \ jr c,mul8_24_1 21 | sla c \ jr c,mul8_24_2 22 | sla c \ jr c,mul8_24_3 23 | sla c \ jr c,mul8_24_4 24 | sla c \ jr c,mul8_24_5 25 | sla c \ jr c,mul8_24_6 26 | sla c \ jr c,mul8_24_7 27 | sla c \ ret c 28 | ld a,c 29 | ld h,c 30 | ld l,c 31 | ret 32 | mul8_24_1: 33 | add hl,hl \ rla \ rl c \ jr nc,$+7 \ add hl,de \ adc a,b \ jr nc,$+3 \ inc c 34 | mul8_24_2: 35 | add hl,hl \ rla \ rl c \ jr nc,$+7 \ add hl,de \ adc a,b \ jr nc,$+3 \ inc c 36 | mul8_24_3: 37 | add hl,hl \ rla \ rl c \ jr nc,$+7 \ add hl,de \ adc a,b \ jr nc,$+3 \ inc c 38 | mul8_24_4: 39 | add hl,hl \ rla \ rl c \ jr nc,$+7 \ add hl,de \ adc a,b \ jr nc,$+3 \ inc c 40 | mul8_24_5: 41 | add hl,hl \ rla \ rl c \ jr nc,$+7 \ add hl,de \ adc a,b \ jr nc,$+3 \ inc c 42 | mul8_24_6: 43 | add hl,hl \ rla \ rl c \ jr nc,$+7 \ add hl,de \ adc a,b \ jr nc,$+3 \ inc c 44 | mul8_24_7: 45 | add hl,hl \ rla \ rl c \ ret nc \ add hl,de \ adc a,b \ ret nc \ inc c \ ret 46 | -------------------------------------------------------------------------------- /math/division/HL_SDiv_BC.z80: -------------------------------------------------------------------------------- 1 | ;Written by calc84maniac, based on a routine from Zeda 2 | ;=============================================================== 3 | HL_SDiv_BC: 4 | ;=============================================================== 5 | ;Performs HL/BC 6 | ;Speed: 1168 to 1318 cycles depending on how many set bits in the result 7 | ; add 19 if HL is negative 8 | ; add 19 if BC is positive 9 | ; add another 28 if only one is negative 10 | ;Size: 54 bytes 11 | ; **31 bytes larger than the regular HL_Div_BC 12 | ;Inputs: 13 | ; HL is the numerator 14 | ; BC is the denominator 15 | ;Outputs: 16 | ; HL is the quotient 17 | ; DE is the remainder 18 | ; BC = -abs(BC) 19 | ;=============================================================== 20 | ld a,h 21 | xor b 22 | push af 23 | absHL: 24 | add hl,hl 25 | jr nc,negabsBC 26 | xor a \ sub l \ ld l,a 27 | sbc a,a \ sub h \ ld h,a 28 | negabsBC: 29 | bit 7,b 30 | jr nz,$+8 31 | xor a \ sub c \ ld c,a 32 | sbc a,a \ sub b \ ld b,a 33 | ex de,hl 34 | xor a 35 | ld h,a 36 | ld l,a 37 | ld a,15 38 | Div_Loop_1: 39 | rl e \ rl d 40 | adc hl,hl 41 | add hl,bc 42 | jr c,$+4 43 | sbc hl,bc 44 | dec a 45 | jr nz,Div_Loop_1 46 | ex de,hl 47 | adc hl,hl 48 | pop af \ ret p 49 | xor a \ sub l \ ld l,a 50 | sbc a,a \ sub h \ ld h,a 51 | ret 52 | -------------------------------------------------------------------------------- /conversion/uitoa_8.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_uitoa_8 2 | #define included_uitoa_8 3 | 4 | ;Written by Zeda 5 | ;Converts an 8-bit unsigned integer to a string 6 | 7 | uitoa_8: 8 | ;Input: 9 | ; A is a signed integer 10 | ; HL points to where the null-terminated ASCII string is stored (needs at most 5 bytes) 11 | ;Output: 12 | ; The number is converted to a null-terminated string at HL 13 | ;Destroys: 14 | ; Up to four bytes at HL 15 | ; All registers preserved. 16 | ;on 0 to 9: 238 D=0 17 | ;on 10 to 99: 244+20D D=0 to 9 18 | ;on 100 to 255: 257+2{0,6}+20D D=0 to 5 19 | ;min: 238cc 20 | ;max: 424cc 21 | ;avg: 317.453125cc = 81268/256 = (238*10 + 334*90+313*156)/256 22 | ;52 bytes 23 | 24 | push hl 25 | push de 26 | push bc 27 | push af 28 | ;A is on [0,255] 29 | ;calculate 100s place, plus 1 for a future calculation 30 | ld b,'0' 31 | cp 100 \ jr c,$+5 \ sub 100 \ inc b 32 | cp 100 \ jr c,$+5 \ sub 100 \ inc b 33 | 34 | ;calculate 10s place digit, +1 for future calculation 35 | ld de,$0A2F 36 | inc e \ sub d \ jr nc,$-2 37 | ld c,a 38 | 39 | ;Digits are now in D, C, A 40 | ; strip leading zeros! 41 | ld a,'0' 42 | cp b \ jr z,$+5 \ ld (hl),b \ inc hl \ .db $FE ; start of `cp *` to skip the next byte, turns into `cp $BB` which will always return nz and nc 43 | cp e \ jr z,$+4 \ ld (hl),e \ inc hl 44 | add a,c 45 | add a,d 46 | ld (hl),a 47 | inc hl 48 | ld (hl),0 49 | 50 | pop af 51 | pop bc 52 | pop de 53 | pop hl 54 | ret 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /math/multiplication/DE_Times_A_faster.z80: -------------------------------------------------------------------------------- 1 | DE_Times_A: 2 | ;Input: DE,A 3 | ;Output: A:HL is the product, C=0, B,DE unaffected, z flag set if result is zero, c flag set if A is input as 1, else nc. 4 | ;A:128~255 219+6{0,10}+{0,19} avg=258.5 *1/2 5 | ;A:64~127 203+5{0,10}+{0,19} avg=237.5 *1/4 6 | ;A:32~63 187+4{0,10}+{0,19} avg=216.5 *1/8 7 | ;A:16~31 171+3{0,10}+{0,19} avg=195.5 *1/16 8 | ;A:8~15 155+2{0,10}+{0,19} avg=174.5 *1/32 9 | ;A:4~7 139+{0,10}+{0,19} avg=153.5 *1/64 10 | ;A:2~3 123+{0,19} avg=132.5 *1/128 11 | ;A:1 107cc avg=107 *1/256 12 | ;A:0 119cc avg=119 *1/256 13 | ;overall avg: 237.671875cc 14 | ld c,0 15 | ld h,d 16 | ld l,e 17 | add a,a \ jr c,mul_07 18 | rla \ jr c,mul_06 19 | rla \ jr c,mul_05 20 | rla \ jr c,mul_04 21 | rla \ jr c,mul_03 22 | rla \ jr c,mul_02 23 | rla \ jr c,mul_01 24 | rla 25 | ret c 26 | ld h,a 27 | ld l,a 28 | ret 29 | mul_07: 30 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,c 31 | mul_06: 32 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,c 33 | mul_05: 34 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,c 35 | mul_04: 36 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,c 37 | mul_03: 38 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,c 39 | mul_02: 40 | add hl,hl \ rla \ jr nc,$+4 \ add hl,de \ adc a,c 41 | mul_01: 42 | add hl,hl \ rla \ ret nc \ add hl,de \ adc a,c 43 | ret 44 | -------------------------------------------------------------------------------- /math/rng/rand_TI_Float.z80: -------------------------------------------------------------------------------- 1 | rand_TI_Float: 2 | ;Generates a random TI float at HL 3 | push hl 4 | ; call rand_init 5 | ld de,$8000 ;D is exponent, E is type. E is used in rand_TI_Float_zero 6 | get_rand_exponent_loop: 7 | ;decrement exponent 8 | dec d 9 | 10 | ;if the exponent is -100, underflow to 0. 11 | ;I don't think this is possible with this RNG, or even likely to ever happen 12 | ;before the universe's heat death with a true RNG, but better to be safe? 13 | ld a,d 14 | cp 28 15 | jp z,rand_TI_Float_zero 16 | 17 | ;save the exponent 18 | push de 19 | 20 | ;Generate a uniform random digit on [0,9] as a candidate for our first digit. 21 | call rand10 22 | 23 | ;restore the exponent+type 24 | pop de 25 | or a 26 | ;if A is 0, we'll decrement the exponent and find a new candidate for the first 27 | ;digit. This is because we need our float to be "normalized" (top digit non-zero) 28 | ;This also preserves the uniform distribution for values. 29 | jr z,get_rand_exponent_loop 30 | 31 | pop hl 32 | ld (hl),e 33 | inc hl 34 | ld (hl),d 35 | inc hl 36 | 37 | ;write the first digit 38 | ld (hl),a 39 | ld b,13 40 | math_rand_loop: 41 | ;now generate subsequent digits 42 | push bc 43 | rr b 44 | jr c,$+3 45 | inc hl 46 | push hl 47 | 48 | ;generate the next digit 49 | call rand10 50 | pop hl 51 | rld 52 | pop bc 53 | djnz math_rand_loop 54 | ret 55 | 56 | rand_TI_Float_zero: 57 | pop hl 58 | ld b,9 59 | ld (hl),e ; E is 0 60 | inc hl 61 | djnz $-2 62 | ret 63 | -------------------------------------------------------------------------------- /ti8x/gfx/verticalline.z80: -------------------------------------------------------------------------------- 1 | verticalline_black: 2 | ;Input: 3 | ; A is y0 4 | ; D is the height 5 | ; C is x0 6 | ;Output: 7 | ; Black vertical line from (A,C) to (A,C+D-1) 8 | ;NOTE: This does not do any clipping. You can frick stuff up. 9 | call verticalline_sub 10 | ret z 11 | _: 12 | ld a,c 13 | or (hl) 14 | ld (hl),a 15 | add hl,de 16 | djnz -_ 17 | ret 18 | 19 | verticalline_white: 20 | ;Input: 21 | ; A is y0 22 | ; D is the height 23 | ; C is x0 24 | ;Output: 25 | ; White vertical line from (A,C) to (A,C+D-1) 26 | ;NOTE: This does not do any clipping. You can frick stuff up. 27 | call verticalline_sub 28 | ret z 29 | _: 30 | ld a,c 31 | cpl 32 | and (hl) 33 | ld (hl),a 34 | add hl,de 35 | djnz -_ 36 | ret 37 | 38 | verticalline_invert: 39 | ;Input: 40 | ; A is y0 41 | ; D is the height 42 | ; C is x0 43 | ;Output: 44 | ; Inverted vertical line from (A,C) to (A,C+D-1) 45 | ;NOTE: This does not do any clipping. You can frick stuff up. 46 | call verticalline_sub 47 | ret z 48 | _: 49 | ld a,c 50 | xor (hl) 51 | ld (hl),a 52 | add hl,de 53 | djnz -_ 54 | ret 55 | 56 | verticalline_sub: 57 | ld h,0 58 | ld b,h 59 | ld l,a 60 | add a,a 61 | add a,l 62 | ld l,a 63 | add hl,hl 64 | add hl,hl 65 | ld a,c 66 | srl c 67 | srl c 68 | srl c 69 | add hl,bc 70 | ld bc,plotSScreen 71 | add hl,bc 72 | 73 | and 7 74 | ld b,a 75 | ld a,$80 76 | jr z,+_ 77 | rrca 78 | djnz $-1 79 | _: 80 | ld b,d 81 | ld c,a 82 | inc b 83 | dec b 84 | ld de,12 85 | ret 86 | -------------------------------------------------------------------------------- /math/division/div32_16.z80: -------------------------------------------------------------------------------- 1 | div32_16: 2 | ;HLIX/BC -> HLIX remainder DE 3 | ;174+4*div32_16_sub8 4 | ;min: 2186cc 5 | ;max: 2794cc 6 | ;avg: 2466cc 7 | ;61 bytes 8 | ex de,hl ; 4 9 | 10 | ; Negate BC to allow add instead of sbc 11 | xor a ; 4 12 | ; Need to set HL to 0 anyways, so save 2cc and a byte 13 | ld h,a ; 4 14 | ld l,a ; 4 15 | sub c ; 4 16 | ld c,a ; 4 17 | sbc a,a ; 4 18 | sub b ; 4 19 | ld b,a ; 4 20 | 21 | 22 | ld a,d ; 4 23 | call div32_16_sub8 ; 17 24 | rla ; 4 25 | ld d,a ; 4 26 | 27 | ld a,e ; 4 28 | call div32_16_sub8 ; 17 29 | rla ; 4 30 | ld e,a ; 4 31 | 32 | ld a,ixh ; 8 33 | call div32_16_sub8 ; 17 34 | rla ; 4 35 | ld ixh,a ; 8 36 | 37 | ld a,ixl ; 8 38 | call div32_16_sub8 ; 17 39 | rla ; 4 40 | ld ixl,a ; 8 41 | 42 | ex de,hl ; 4 43 | ret ; 10 44 | 45 | div32_16_sub8: 46 | ;119+8*div32_16_sub 47 | ;min: 503cc 48 | ;max: 655cc 49 | ;avg: 573cc 50 | call +_ 51 | _: 52 | ;17+2(17+2(div32_16_sub))) 53 | call +_ 54 | _: 55 | ;17+2(div32_16_sub) 56 | call div32_16_sub 57 | div32_16_sub: 58 | ;48+{8,0+{0,19}} 59 | ;min: 48cc 60 | ;max: 67cc 61 | ;avg: 56.75cc 62 | rla ; 4 63 | adc hl,hl ; 15 64 | jr c,+_ ;12/7 65 | add hl,bc ; 11 66 | ret c ;11/5 67 | sbc hl,bc ; 15 68 | ret ; 10 69 | _: 70 | add hl,bc ; 11 71 | scf ; 4 72 | ret ; 10 73 | -------------------------------------------------------------------------------- /math/rng/lehmer16.z80: -------------------------------------------------------------------------------- 1 | lehmer: 2 | ;Input: 3 | ; (seed) has the seed value of the RNG 4 | ;Output: 5 | ; (seed) is updated, HL is the result 6 | ;Destroys: 7 | ; A,DE,BC 8 | ;Timing: 9 | ; if seed>0 231cc or 232cc, condition dependent 10 | ; if seed=0 91cc 11 | ; if SMC defined subtract 6cc 12 | ;Size: 44 bytes 13 | ;Notes: 14 | ; Uses the Lehmer RNG used by the Sinclair ZX81 15 | ; 75x mod 65537 -> x 16 | #ifndef SMC 17 | ld hl,(seed) 18 | #else 19 | seed = $+1 20 | ld hl,0 21 | #endif 22 | ;multiply by 75 23 | ld c,l 24 | ld b,h 25 | xor a 26 | adc hl,hl \ jr z,special \ ld d,a \ rla 27 | add hl,hl \ rla 28 | add hl,hl \ rla \ add hl,bc \ adc a,d 29 | add hl,hl \ rla 30 | add hl,hl \ rla \ add hl,bc \ adc a,d 31 | add hl,hl \ rla \ add hl,bc 32 | ;modulo 65537, see note below on how this works 33 | ld e,a 34 | sbc hl,de ;No need to reset the c flag since it is already 35 | jr nc,$+3 36 | inc hl 37 | ld (seed),hl 38 | ret 39 | special: 40 | ;In the case that HL=0, this should be interpreted as 65536 = -1 mod 65537, so return -75 mod 65537 = -74 mod 65536 in HL 41 | ld hl,-74 42 | ld (seed),hl 43 | ret 44 | 45 | ;mod by 2^16 + 1 (a prime) 46 | ;current form is A*2^16+HL 47 | ;need: 48 | ; (A*2^16+HL) mod (2^16+1) 49 | ;add 0 as +1-1 50 | ; (A*(2^16+1-1)+HL) mod (2^16+1) 51 | ;distribute 52 | ; (A*(2^16+1)-A+HL) mod (2^16+1) 53 | ;A*(2^16+1) mod 2^16+1 = 0, so remove 54 | ; (-A+HL) mod (2^16+1) 55 | ;Oh hey, that's easy! :P 56 | ;I use this trick everywhere, you should, too. 57 | -------------------------------------------------------------------------------- /conversion/u16toa_destructive.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_u16toa 2 | #define included_u16toa 3 | 4 | ; A related routine can be found at conversion/utoa_16.z80 which preserves 5 | ; registers. 6 | 7 | ;written by Zeda 8 | ;Converts a 16-bit unsigned integer to an ASCII string. 9 | ;Note that this version destroys registers. 10 | 11 | u16toa: 12 | ;Input: 13 | ; DE is the number to convert 14 | ; HL points to where to write the ASCII string (up to 6 bytes needed). 15 | ;Output: 16 | ; HL points to the null-terminated ASCII string 17 | ; NOTE: This isn't necessarily the same as the input HL. 18 | ;Destroys: 19 | ; BC, DE, AF 20 | ex de,hl 21 | 22 | ; First digit 23 | ld bc,-10000 24 | ld a,'0'-1 25 | inc a ;\ 26 | add hl,bc ; | Loop 27 | jr c,$-2 ;/ 28 | ld (de),a 29 | inc de 30 | 31 | ; Second digit 32 | ld bc,1000 33 | ld a,'9'+1 34 | dec a ;\ 35 | add hl,bc ; | Loop 36 | jr nc,$-2 ;/ 37 | ld (de),a 38 | inc de 39 | 40 | ; Third digit 41 | ld bc,-100 42 | ld a,'0'-1 43 | inc a ;\ 44 | add hl,bc ; | Loop 45 | jr c,$-2 ;/ 46 | ld (de),a 47 | inc de 48 | 49 | ; Fourth digit, remainder is fifth digit 50 | ld a,l 51 | ld h,'9'+1 52 | dec h ;\ 53 | add a,10 ; | Loop 54 | jr nc,$-3 ;/ 55 | ex de,hl 56 | ld (hl),d 57 | inc hl 58 | add a,'0' 59 | ld (hl),a 60 | inc hl 61 | ld (hl),0 62 | 63 | ;Now strip the leading zeros 64 | ld c,-6 65 | add hl,bc 66 | 67 | ld a,'0' 68 | inc hl ;\ 69 | cp (hl) ; | Loop 70 | jr z,$-2 ;/ 71 | 72 | ;Make sure that the string is non-empty! 73 | xor a 74 | cp (hl) 75 | ret z 76 | dec hl 77 | ret 78 | #endif 79 | -------------------------------------------------------------------------------- /math/rng/rand16_LCG_xorshift.z80: -------------------------------------------------------------------------------- 1 | ;You may use this routine, just be sure to credit John Metcalf for the 2 | ;xorshift16 part of this routine! 3 | 4 | ; This routine is a fast Pseudo Random Number Generator 5 | ;for the Z80. It combines a 16-bit LCG and 16-bit xorshift. 6 | ;The xorshift routine was written by John Metcalf 7 | ;and posted here: 8 | ; http://www.retroprogramming.com/2017/07/xorshift-pseudorandom-numbers-in-z80.html 9 | 10 | 11 | ;#define smc ;uncomment if you are using SMC 12 | 13 | rand16: 14 | ;174cc (or 186cc if not using SMC) 15 | ;34 bytes 16 | ;cycle length: 4,294,901,760 (almost 4.3 billion) 17 | 18 | ; For the first seed, we use an LCG, 1+5*seed1 ==> seed1 19 | #ifdef smc 20 | seed1=$+1 21 | ld hl,9999 22 | #else 23 | ld hl,(seed1) 24 | #endif 25 | ld b,h 26 | ld c,l 27 | add hl,hl 28 | add hl,hl 29 | inc l 30 | add hl,bc 31 | ld (seed1),hl 32 | 33 | ; For the second seed, we apply an xorshift 34 | ; seed2^(seed2<<7) ==> seed2 35 | ; seed2^(seed2>>9) ==> seed2 36 | ; seed2^(seed2<<8) ==> seed2 37 | ; This code was originally made by John Metcalf and posted here: 38 | ; http://www.retroprogramming.com/2017/07/xorshift-pseudorandom-numbers-in-z80.html 39 | ; (My modifications are only in naming and compiler directives.) 40 | 41 | #ifdef smc 42 | seed2=$+1 43 | ld hl,9999 44 | #else 45 | ld hl,(seed2) 46 | #endif 47 | ld a,h 48 | rra 49 | ld a,l 50 | rra 51 | xor h 52 | ld h,a 53 | ld a,l 54 | rra 55 | ld a,h 56 | rra 57 | xor l 58 | ld l,a 59 | xor h 60 | ld h,a 61 | ld (seed2),hl 62 | add hl,bc 63 | ret 64 | -------------------------------------------------------------------------------- /ti8x/gfx/iPutSpriteMask.z80: -------------------------------------------------------------------------------- 1 | ;NOTE: This routine may be under a different License. 2 | 3 | ;Masked Sprite Routine 4 | ;Created by KermMartian, modifed from IonPutSprite 5 | iPutSpriteMask: 6 | ;Inputs: 7 | ; ix = b-byte mask 8 | ; ix+8 = b-byte sprite 9 | ; a,l = x and y as with IonPutSprite 10 | ; b= height of sprite 11 | ;Outputs: 12 | ; Sprite masked to screen 13 | ;Destroyed: 14 | ; All 15 | ld e,l 16 | ld h,$00 17 | ld d,h 18 | add hl,de 19 | add hl,de 20 | add hl,hl 21 | add hl,hl 22 | ld e,a 23 | and $07 24 | ld c,a 25 | srl e 26 | srl e 27 | srl e 28 | add hl,de 29 | ld de,gbuf 30 | add hl,de 31 | iPutSpriteLoop1Mask: 32 | ld d,(ix) 33 | ld e,$FF 34 | ld a,c 35 | or a 36 | jr z,iPutSpriteSkip1Mask 37 | iPutSpriteLoop2Mask: 38 | srl d 39 | rr e 40 | set 7,d 41 | dec a 42 | jr nz,iPutSpriteLoop2Mask 43 | iPutSpriteSkip1Mask: 44 | ld a,(hl) 45 | and d 46 | ld (hl),a 47 | inc hl 48 | ld a,(hl) 49 | and e 50 | ld (hl),a 51 | push ix 52 | dec hl 53 | ld de,8 54 | add ix,de 55 | iPutSpriteLoop1AND: 56 | ld d,(ix) 57 | ld e,$00 58 | ld a,c 59 | or a 60 | jr z,iPutSpriteSkip1AND 61 | iPutSpriteLoop2AND: 62 | srl d 63 | rr e 64 | dec a 65 | jr nz,iPutSpriteLoop2AND 66 | iPutSpriteSkip1AND: 67 | ld a,(hl) 68 | xor d 69 | ld (hl),a 70 | inc hl 71 | ld a,(hl) 72 | xor e 73 | ld (hl),a 74 | 75 | pop ix 76 | ld de,$0B 77 | add hl,de 78 | inc ix 79 | djnz iPutSpriteLoop1Mask 80 | ret 81 | -------------------------------------------------------------------------------- /ti8x/gfx/filledcircle.z80: -------------------------------------------------------------------------------- 1 | ;This draws the fill of a circle centered at 8-bit coordinates and with radius 2 | ;up to 127. 3 | ;IX points to a `horizontal line` routine that takes E=x, A=y, D=width as input 4 | ;and does something with it, like plot a horizontal line. 5 | ; 6 | ; For example, on the ti-83+/84+/SE calculators, you might have: 7 | ; horizontal_line: 8 | ; ld b,e 9 | ; ld c,a 10 | ; ld e,1 11 | ; ld hl,gbuf 12 | ; jp rectOR 13 | 14 | ; Required subroutines: 15 | ; call_ix: 16 | ; jp (ix) 17 | 18 | filledcircle: 19 | ;Input: 20 | ; (B,C) is the center (x,y) 21 | ; D is the radius, unsigned, less than 128 (0 or greater than 128 just quits). 22 | ; IX points to a `plot` routine that takes (E,A,D)=(x,y,width) as input. 23 | ld a,d 24 | add a,a 25 | ret c 26 | ret z 27 | ld l,d 28 | dec a 29 | ld e,a 30 | xor a 31 | ld h,-1 32 | ld d,1 33 | filledcircleloop: 34 | ; call c,fillcircle_plot 35 | inc h 36 | sub d 37 | inc d 38 | inc d 39 | jr nc,filledcircleloop 40 | _: 41 | call fillcircle_plot 42 | dec l 43 | add a,e 44 | dec e 45 | ret z 46 | dec e 47 | jr nc,-_ 48 | jp filledcircleloop 49 | 50 | fillcircle_plot: 51 | inc h 52 | dec h 53 | ret z 54 | push hl 55 | push de 56 | push bc 57 | push af 58 | dec h 59 | ld a,b 60 | sub h 61 | ld e,a 62 | ld d,h 63 | sll d ;aka `slia`, undocumented 64 | 65 | ld a,l 66 | or a 67 | ld h,c 68 | jr z,+_ 69 | add a,h 70 | push de 71 | push hl 72 | call nz,call_ix 73 | pop hl 74 | pop de 75 | _: 76 | ld a,h 77 | sub l 78 | call call_ix 79 | pop af 80 | pop bc 81 | pop de 82 | pop hl 83 | ret 84 | -------------------------------------------------------------------------------- /conversion/itoa_8.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_itoa_8 2 | #define included_itoa_8 3 | 4 | ;Written by Zeda 5 | ;Converts an 8-bit signed integer to a string 6 | 7 | itoa_8: 8 | ;Input: 9 | ; A is a signed integer 10 | ; HL points to where the null-terminated ASCII string is stored (needs at most 5 bytes) 11 | ;Output: 12 | ; The number is converted to a null-terminated string at HL 13 | ;Destroys: 14 | ; Up to five bytes at HL 15 | ; All registers preserved. 16 | ;on 0 to 9: 252 D=0 17 | ;on 10 to 99: 258+20D D=0 to 9 18 | ;on 100 to 127: 277+20D D=0 to 2 19 | ;on -1 to -9: 276 D=0 20 | ;on -10 to -99: 282+20D D=0 to 9 21 | ;on -100 to -128: 301+20D D=0 to 2 22 | 23 | ;min: 252cc (+23cc over original) 24 | ;max: 462cc (-49cc over original) 25 | ;avg: 343.74609375cc = 87999/256 26 | ;54 bytes 27 | push hl 28 | push de 29 | push bc 30 | push af 31 | or a 32 | jp p,itoa_pos 33 | neg 34 | ld (hl),$1A ;start if neg char on TI-OS 35 | inc hl 36 | itoa_pos: 37 | ;A is on [0,128] 38 | ;calculate 100s place, plus 1 for a future calculation 39 | ld b,'0' 40 | cp 100 \ jr c,$+5 \ sub 100 \ inc b 41 | 42 | ;calculate 10s place digit, +1 for future calculation 43 | ld de,$0A2F 44 | inc e \ sub d \ jr nc,$-2 45 | ld c,a 46 | 47 | ;Digits are now in D, C, A 48 | ; strip leading zeros! 49 | ld a,'0' 50 | cp b \ jr z,$+5 \ ld (hl),b \ inc hl \ .db $FE ; start of `cp *` to skip the next byte, turns into `cp $BB` which will always return nz and nc 51 | cp e \ jr z,$+4 \ ld (hl),e \ inc hl 52 | add a,c 53 | add a,d 54 | ld (hl),a 55 | inc hl 56 | ld (hl),0 57 | 58 | pop af 59 | pop bc 60 | pop de 61 | pop hl 62 | ret 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /math/float/extendedprecision.md: -------------------------------------------------------------------------------- 1 | Extended precision (80-bit) routines can be found at [z80float](https://github.com/Zeda/z80float/tree/master/extended). As of this writing, these include: 2 | ``` 3 | xconst Locates constants 4 | xabs Absolute Value 5 | xneg Negate 6 | xcmp Compare 7 | xmod1 Discards the integer part (x-int(x)) 8 | xrand rand 9 | 10 | xadd Addition 11 | xsub Subtraction (x-y) 12 | xrsub Reverse Subtract (-x+y) 13 | xamean Arithmetic Mean 14 | 15 | xmul Multiplication 16 | xfma Fused Multiply-Add 17 | 18 | xdiv Division 19 | xinv 1/x 20 | 21 | xsqrt Square Root 22 | xgeomean Geometric Mean 23 | xbg Borchardt-Gauss mean 24 | 25 | xexp e^x 26 | xpow2 2^x 27 | xpow2_fma 2^x (Uses xfma) 28 | xpow10 10^x 29 | xpow y^x 30 | 31 | xlg Log2 (Log base 2) 32 | xln Log (Natural Logarithm) 33 | xlog LogY (Log base Y) 34 | xlog10 Log10 (Log base 10) 35 | 36 | xcos Cosine 37 | xsin Sine 38 | xtan Tangent 39 | xcis Cosine and Sine 40 | xcosh Hyperbolic Cosine 41 | xsinh Hyperbolic Sine 42 | xtanh Hyperbolic Tangent 43 | 44 | xacos Arccosine 45 | xasin Arcsine 46 | xatan Arctangent 47 | xacosh Hyperbolic Arccosine 48 | xasinh Hyperbolic Arcsine 49 | xatanh Hyperbolic Arctangent 50 | 51 | xtostr Extended --> String 52 | xtoTI Extended --> TI Float 53 | strtox String --> Extended 54 | TItox TI Float --> Extended 55 | 56 | 57 | float.inc Useful defines and equates 58 | constantsx Useful constants 59 | data Data 60 | tables Tables 61 | ``` 62 | -------------------------------------------------------------------------------- /ti8x/gfx/gbuf_to_lcd_6MHz.z80: -------------------------------------------------------------------------------- 1 | ;This routine uses a time-base delay, which should work with the newer (2019) 2 | ;calculator models whose LCD has a malfunctioning status bit. 3 | ; 4 | ;The TI-83+/84+ and similar calculators have a clock speed that varies based on 5 | ;a number of factors, so we'll assume it is up to 6.6MHz. According to TI's 6 | ;documentation, we'll need 10 microseconds beteen writes to the LCD, so that's 7 | ;66 clock cycles at 6.6MHz 8 | ;Since an out takes at least 11cc, we'll aim for 55cc between outs 9 | 10 | #ifndef included_gbuf_to_lcd_6MHZ 11 | #define included_gbuf_to_lcd_6MHZ 12 | 13 | gbuf_to_lcd_6MHz: 14 | ;This copies the contents of gbuf to the LCD. 15 | ;Preserves all registers. 16 | push hl ;11 11 17 | push de ;11 22 18 | push bc ;11 33 19 | push af ;11 44 20 | ld hl,gbuf ;10 54 21 | ld a,$80 ;7 61 22 | out (16),a ;11 0 23 | 24 | ld de,11 ;10 10 25 | ld a,$20 ;7 17 26 | ex (sp),hl ;19 36 \ waste clock cycles 27 | ex (sp),hl ;19 55 / 28 | col: 29 | out (10h),a ;11 0 30 | ld b,(hl) ;7 7 31 | xor b ;4 11 \ waste clock cycles 32 | xor b ;4 15 / 33 | ld bc,$8011 ;10 25 34 | nop ;4 29 35 | 36 | row: 37 | sbc hl,de ;15 44 \ waste clock cycles 38 | add hl,de ;11 55 / 39 | outi ;16 5 40 | add hl,de ;11 16 41 | djnz row ;13/8 29/24 42 | inc a ;4 28 43 | dec h ;4 32 44 | dec h ;4 36 45 | dec h ;4 40 46 | inc hl ;6 46 47 | cp $2C ;7 53 48 | jp nz,col ;10 63 49 | pop af ;10 50 | pop bc ;10 51 | pop de ;10 52 | pop hl ;10 53 | ret ;10 54 | #endif 55 | -------------------------------------------------------------------------------- /conversion/itoa_16.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_itoa_16 2 | #define included_itoa_16 3 | 4 | ;written by Zeda 5 | ;Converts a 16-bit signed integer to an ASCII string. 6 | 7 | itoa_16: 8 | ;Input: 9 | ; DE is the number to convert 10 | ; HL points to where to write the ASCII string (up to 7 bytes needed). 11 | ;Output: 12 | ; HL points to the null-terminated ASCII string 13 | ; NOTE: This isn't necessarily the same as the input HL. 14 | push de 15 | push bc 16 | push af 17 | push hl 18 | bit 7,d 19 | jr z,+_ 20 | xor a 21 | sub e 22 | ld e,a 23 | sbc a,a 24 | sub d 25 | ld d,a 26 | ld (hl),$1A ;negative char on TI-OS 27 | inc hl 28 | _: 29 | ex de,hl 30 | 31 | ld bc,-10000 32 | ld a,'0'-1 33 | inc a \ add hl,bc \ jr c,$-2 34 | ld (de),a 35 | inc de 36 | 37 | ld bc,1000 38 | ld a,'9'+1 39 | dec a \ add hl,bc \ jr nc,$-2 40 | ld (de),a 41 | inc de 42 | 43 | ld bc,-100 44 | ld a,'0'-1 45 | inc a \ add hl,bc \ jr c,$-2 46 | ld (de),a 47 | inc de 48 | 49 | ld a,l 50 | ld h,'9'+1 51 | dec h \ add a,10 \ jr nc,$-3 52 | add a,'0' 53 | ex de,hl 54 | ld (hl),d 55 | inc hl 56 | ld (hl),a 57 | inc hl 58 | ld (hl),0 59 | 60 | ;No strip the leading zeros 61 | pop hl 62 | 63 | ;If the first char is a negative sign, skip it 64 | ld a,(hl) 65 | cp $1A 66 | push af 67 | ld a,'0' 68 | jr nz,$+3 69 | inc hl 70 | cp (hl) 71 | jr z,$-2 72 | 73 | ;Make sure that the string is non-empty! 74 | ld a,(hl) 75 | or a 76 | jr nz,+_ 77 | dec hl 78 | _: 79 | 80 | ;Check if we need to re-write the negative sign 81 | pop af 82 | jr nz,+_ 83 | dec hl 84 | ld (hl),a 85 | _: 86 | 87 | pop af 88 | pop bc 89 | pop de 90 | ret 91 | 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /math/multiplication/mulfixed4_12.z80: -------------------------------------------------------------------------------- 1 | ;Requires: 2 | ; mul16 3 | ; Inputs: BC,DE 4 | ; Output: DEHL 5 | 6 | mulfixed4_12: 7 | ;Multiplies 4.12 fixed point numbers. 8 | ;Inputs: HL is the first fixed-point multiplicand 9 | ; DE is the second fixed-point multiplicand 10 | ;Output: HL is the fixed-point output 11 | ;Overflow is stored as 0x7.FFF or 0x8.001 depending on positive or negative 12 | ; First, find out if the output is positive or negative 13 | ld a,h 14 | xor d 15 | push af ;sign bit is the result sign bit 16 | 17 | ; Now make sure the inputs are positive 18 | xor d ;A now has the value of H, since I XORed it with D twice (cancelling) 19 | jp p,+_ ;if Positive, don't negate 20 | xor a 21 | sub l 22 | ld l,a 23 | sbc a,a 24 | sub h 25 | ld h,a 26 | _: 27 | bit 7,d 28 | jr z,+_ 29 | xor a 30 | sub e 31 | ld e,a 32 | sbc a,a 33 | sub d 34 | ld d,a 35 | _: 36 | 37 | ; Now we need to put DE in BC to use mul16 38 | ld b,h 39 | ld c,l 40 | call mul16 41 | 42 | ;The result doesn't need the top 4 bits or bottom 12 bits. 43 | ;We'll hold onto the top 4 bits to check overflow, though. 44 | ;Currently we need to shift DEH left by 4 bits and keep DE, or right by 12 bits and keep HL. 45 | ld a,h ;we'll actually be moving the discared bits into A 46 | and $F0 47 | ex de,hl 48 | rla \ adc hl,hl 49 | rla \ adc hl,hl 50 | rla \ adc hl,hl 51 | rla \ adc hl,hl 52 | adc a,a 53 | 54 | ;if A is non-zero, we have overflow 55 | jr z,+_ 56 | ld hl,$7FFF 57 | _: 58 | 59 | ; Now we need to restore the sign 60 | pop af 61 | ret p ;don't need to do anything, result is already positive 62 | xor a 63 | sub l 64 | ld l,a 65 | sbc a,a 66 | sub h 67 | ld h,a 68 | ret 69 | -------------------------------------------------------------------------------- /ti8x/gfx/putspritemasked_fasterer.z80: -------------------------------------------------------------------------------- 1 | ;Masked Sprite routine 2 | putsprite_masked: 3 | ;Inputs: 4 | ; (A,L) = (x,y) 5 | ; B is height 6 | ; IX points to the sprite data 7 | ; first byte is the data 8 | ; second byte is mask 9 | ; continues, alternating like this. 10 | ; 11 | ;Outputs: 12 | ; Mask is ANDed to the buffer, then data is ORed on top of that. 13 | ; 14 | ;Destroys: 15 | ; AF, BC, DE, HL, IX 16 | ; 17 | ;Notes: 18 | ; To set a pixel... 19 | ; black: mask is any, data is 1 20 | ; white: mask is 0, data is 0 21 | ; clear: mask is 1, data is 0 (keeps the data from the buffer) 22 | ; 23 | ;This routine is free to use :) 24 | ;65 bytes (or 66 bytes if gbuf is not located at 0x**40 25 | 26 | ld e,l 27 | ld h,0 28 | ld d,h 29 | add hl,hl 30 | add hl,de 31 | add hl,hl 32 | add hl,hl 33 | ld e,a 34 | and 7 35 | ld c,a 36 | xor e ;essentially gets E with the bottom 3 bits reset 37 | #if (plotSScreen&255) = 64 38 | inc a 39 | rra 40 | rra 41 | rra 42 | ld e,a 43 | ld d,plotSScreen>>8 44 | #else 45 | rra 46 | rra 47 | rra 48 | ld e,a 49 | add hl,de 50 | ld de,plotSScreen 51 | #endif 52 | add hl,de 53 | 54 | 55 | putsprite_masked_loop: 56 | push bc 57 | xor a 58 | ld d,(ix) 59 | ld e,a 60 | sub c 61 | ld b,c 62 | ld c,$FF 63 | inc ix 64 | ld a,(ix) 65 | jr z,putsprite_masked_rotdone 66 | putsprite_masked_rot: 67 | scf 68 | rra 69 | rr c 70 | srl d 71 | rr e 72 | djnz putsprite_masked_rot 73 | putsprite_masked_rotdone: 74 | and (hl) 75 | or d 76 | ld (hl),a 77 | inc hl 78 | ld a,(hl) 79 | and c 80 | or e 81 | ld (hl),a 82 | ld c,11 83 | add hl,bc 84 | inc ix 85 | pop bc 86 | djnz putsprite_masked_loop 87 | ret 88 | -------------------------------------------------------------------------------- /ti8x/utility/ConvOP_noerr.z80: -------------------------------------------------------------------------------- 1 | ;Converts a TI float in the way ConvOP1 does it. 2 | ;Offers a wider range, and reading floats from arbitrary locations, not just OP1. 3 | 4 | ConvOP1: 5 | ;Output: HL is the 16-bit result. 6 | ld de,OP1 7 | ConvFloat: 8 | ;Input: DE points to the float. 9 | ;Output: HL is the 16-bit result. 10 | ; Input is on: 11 | ; (0,1) => 57cc Average=57 12 | ; 0 or [1,10) => 117cc or 126cc =121.5 13 | ; [10,100) => 174cc or 175cc =174.5 14 | ; [100,1000) => 276cc, 277cc, 285cc, or 286cc. =281 15 | ; [1000,10000) => 374cc to 376cc =375 16 | ; [10000,65536) => 481cc to483cc, or 490cc to 492cc =486.5 17 | ;Average case: 467.88153076171875cc 18 | 19 | ld hl,0 20 | ld a,(de) 21 | or a 22 | ret z 23 | inc de 24 | ld a,(de) 25 | inc de 26 | sub 80h 27 | ret c 28 | jr z,final 29 | cp 5 30 | jp c,enterloop 31 | ret 32 | loop: 33 | ld a,b 34 | ld b,h 35 | ld c,l 36 | add hl,hl 37 | add hl,bc 38 | add hl,hl 39 | add hl,hl 40 | add hl,hl 41 | add hl,bc 42 | add hl,hl 43 | add hl,hl 44 | enterloop: 45 | ld b,a 46 | ex de,hl 47 | ld a,(hl) \ and $F0 \ rra \ ld c,a \ rra \ rra \ sub c \ add a,(hl) 48 | inc hl 49 | ex de,hl 50 | add a,l 51 | ld l,a 52 | jr nc,$+3 53 | inc h 54 | dec b 55 | ret z 56 | djnz loop 57 | ld b,h 58 | ld c,l 59 | add hl,hl 60 | add hl,hl 61 | add hl,bc 62 | add hl,hl 63 | final: 64 | ld a,(de) 65 | rrca 66 | rrca 67 | rrca 68 | rrca 69 | and 15 70 | add a,l 71 | ld l,a 72 | ret nc 73 | inc h 74 | ret 75 | -------------------------------------------------------------------------------- /math/multiplication/mulfixed1616.z80: -------------------------------------------------------------------------------- 1 | ;This multiplies two 64-bit integers and returns a 128-bit result. 2 | ;This requires the following routines: 3 | ; mul32 4 | ; Inputs: DEHL, BCIX 5 | ; Output: stored at z32_0, little-endian 6 | 7 | mulfixed16_16: 8 | ;Multiplies DE.HL by BC.IX, stores the result in DE.HL 9 | ; First, find out if the output is positive or negative 10 | ld a,d 11 | xor b 12 | push af ;sign bit is the result sign bit 13 | 14 | ; Now make sure the inputs are positive 15 | xor b ;A now has the value of D, since I XORed it with B twice (cancelling) 16 | jp p,+_ ;if Positive, don't negate 17 | xor a 18 | sub l 19 | ld l,a 20 | ld a,0 21 | sbc a,h 22 | ld h,a 23 | ld a,0 24 | sbc a,e 25 | ld e,a 26 | sbc a,a 27 | sub d 28 | ld d,a 29 | _: 30 | bit 7,b 31 | jr z,+_ 32 | xor a 33 | sub ixl 34 | ld ixl,a 35 | ld a,0 36 | sbc a,ixh 37 | ld ixh,a 38 | ld a,0 39 | sbc a,c 40 | ld c,a 41 | sbc a,a 42 | sub b 43 | ld b,a 44 | _: 45 | 46 | ; Now we multiply 47 | call mul32 48 | 49 | ;We should check for overflow. If the upper two bytes are non-zero, we will set the result to 0x7FFFFFFF 50 | ld hl,(z32_0+6) 51 | ld a,h 52 | or l 53 | 54 | ;Get the middle four bytes and put them in DEHL 55 | ld hl,(z32_0+2) 56 | ld de,(z32_0+4) 57 | 58 | ;Maybe we need to set the result to 0x7FFFFFFF 59 | jr z,+_ 60 | ld de,$7FFF 61 | ld h,e 62 | ld l,e 63 | _: 64 | 65 | ; Now we need to restore the sign 66 | pop af 67 | ret p ;don't need to do anything, result is already positive 68 | xor a 69 | ld b,a 70 | sub l 71 | ld l,a 72 | ld a,b 73 | sbc a,h 74 | ld h,a 75 | ld a,b 76 | sbc a,e 77 | ld e,a 78 | sbc a,a 79 | sub d 80 | ld d,a 81 | ret 82 | -------------------------------------------------------------------------------- /ti8x/gfx/putsprite10.z80: -------------------------------------------------------------------------------- 1 | ;PutSprite10 2 | ;Created by Fallen Ghost 3 | ;PutSprite8 I modified to PutSprite10. Might be useless for you, but if you have some slightly larger than 8 sprites, then you can use PutSprite10. As it is faster than PutSprite16 and allows you not to destroy shadow registers too, and run interrupts during, and smaller. So if you have unconventional sprite size... 4 | 5 | 6 | putsprite10: 7 | putsprite_10_bits: 8 | ;Input: 9 | ; L=Y coordinates 10 | ; A=X coordinates 11 | ; b=height of sprite 12 | ; ix=sprite location. IX+1 being the other 2 bits 13 | ;Output: 14 | ; IX=data after the sprite's data 15 | ;Destroyed 16 | ; b 17 | ld e,l 18 | ld h,00h 19 | ld d,h 20 | add hl,de 21 | add hl,de 22 | add hl,hl 23 | add hl,hl 24 | ld e,a 25 | and 07h 26 | ld c,a 27 | srl e 28 | srl e 29 | srl e 30 | add hl,de 31 | ld de,plotSScreen 32 | add hl,de 33 | putSprite10Loop1: 34 | ld d,(ix) 35 | ld e,(ix+1) ;modified this 36 | ld a,c 37 | or a 38 | jr z,putSprite10Skip1 39 | putSprite10Loop2: 40 | srl d 41 | rr e 42 | dec a 43 | jr nz,putSprite10Loop2 44 | putSprite10Skip1: 45 | push af ;save carry. Will be 0 if bit 46 | ;was not destroyed or 47 | ;if you skipped loop2 48 | ld a,(hl) 49 | xor d 50 | ld (hl),a 51 | inc hl 52 | ld a,(hl) 53 | xor e 54 | ld (hl),a 55 | pop af 56 | jr nc,putSprite10skip3 57 | ld a,(hl) 58 | xor %10000000 59 | ld (hl),a 60 | putSprite10skip3: 61 | ld de,0Bh 62 | add hl,de 63 | inc ix 64 | inc ix ;added this 65 | djnz putSprite10Loop1 66 | ret 67 | -------------------------------------------------------------------------------- /gfx/filledcircle.z80: -------------------------------------------------------------------------------- 1 | ;Written by Zeda Thomas, free to use. 2 | 3 | ;This draws the fill of a circle centered at 8-bit coordinates and with radius 4 | ;up to 127. 5 | ;IX points to a `horizontal line` routine that takes E=x, A=y, D=width as input 6 | ;and does something with it, like plot a horizontal line. 7 | ; 8 | ; For example, on the ti-83+/84+/SE calculators, you might have: 9 | ; horizontal_line: 10 | ; ld b,e 11 | ; ld c,a 12 | ; ld e,1 13 | ; ld hl,gbuf 14 | ; jp rectOR 15 | 16 | ; Required subroutines: 17 | ; call_ix: 18 | ; jp (ix) 19 | 20 | filledcircle: 21 | ;Input: 22 | ; (B,C) is the center (x,y) 23 | ; D is the radius, unsigned, less than 128 (0 or greater than 128 just quits). 24 | ; IX points to a `plot` routine that takes (E,A,D)=(x,y,width) as input. 25 | ld a,d 26 | add a,a 27 | ret c 28 | ret z 29 | ld l,d 30 | dec a 31 | ld e,a 32 | xor a 33 | ld h,-1 34 | ld d,1 35 | filledcircleloop: 36 | ; call c,fillcircle_plot 37 | inc h 38 | sub d 39 | inc d 40 | inc d 41 | jr nc,filledcircleloop 42 | _: 43 | dec l 44 | call fillcircle_plot 45 | add a,e 46 | dec e 47 | ret z 48 | dec e 49 | jr nc,-_ 50 | jp filledcircleloop 51 | 52 | fillcircle_plot: 53 | inc h 54 | dec h 55 | ret z 56 | push hl 57 | push de 58 | push bc 59 | push af 60 | dec h 61 | ld a,b 62 | sub h 63 | ld e,a 64 | ld d,h 65 | #ifdef ALLOW_UNDOCUMENTED 66 | sll d ;aka `slia`, undocumented 67 | #else 68 | scf 69 | rl d 70 | #endif 71 | 72 | ld a,l 73 | or a 74 | ld h,c 75 | jr z,+_ 76 | add a,h 77 | push de 78 | push hl 79 | call nz,call_ix 80 | pop hl 81 | pop de 82 | _: 83 | ld a,h 84 | sub l 85 | call call_ix 86 | pop af 87 | pop bc 88 | pop de 89 | pop hl 90 | ret 91 | -------------------------------------------------------------------------------- /gfx/line.z80: -------------------------------------------------------------------------------- 1 | ;This draws a line from (x0,y0) to (x1,y1), signed coordinates. 2 | ; 3 | ; Required subroutines: 4 | ; call_ix: 5 | ; jp (ix) 6 | 7 | line: 8 | ;Inputs: 9 | ; (H,L) is (x0,y0) 10 | ; (D,E) is (x1,y1) 11 | ; IX points to the pixel plotting routine 12 | ; Takes coordinates, (D,E) = (x,y) and plots the point. 13 | ; preserves HL,DE,BC,A,IX 14 | 15 | ;Destroys: 16 | ; AF,BC,DE,HL 17 | ; LICENSING NOTE: 18 | ; This code is (heavily) modified from Axe's open source code. 19 | ; There are structural similarities, but the majority of it is rewritten 20 | ; to be platform independent. 21 | ;71 bytes 22 | 23 | ld a,d 24 | sub h 25 | jp p,+_ 26 | ex de,hl 27 | neg 28 | _: 29 | 30 | push hl ;Save the coordinates 31 | 32 | ld c,a 33 | ld a,l 34 | ld l,c 35 | sub e 36 | 37 | ld c,0 38 | jp p,+_ 39 | dec c 40 | neg 41 | _: 42 | 43 | ld h,a ; H=DY, L=DX 44 | cp l 45 | jr nc,+_ 46 | ld a,l 47 | _: 48 | 49 | pop de ;restore coordinates 50 | ld b,a ; Pixel counter 51 | inc b 52 | cp h 53 | 54 | ;want to preserve Z 55 | 56 | jr nz,__LineH ; Line is rather horizontal than vertical 57 | ;divide A by 2, given carry is reset 58 | rra 59 | __LineVLoop: 60 | call call_ix ;plot 61 | rlc c 62 | jr nc,+_ 63 | inc e 64 | .db $FE 65 | _: 66 | dec e 67 | sub l ; Handling gradient 68 | jr nc,+_ 69 | inc d 70 | add a,h 71 | _: 72 | djnz __LineVLoop 73 | ret 74 | 75 | __LineH: 76 | ;divide A by 2, given carry is set 77 | or a 78 | rra 79 | 80 | __LineHLoop: 81 | call call_ix ;plot 82 | inc d 83 | sub h ; Handling gradient 84 | jr nc,__LineHNext 85 | rlc c 86 | jr nc,+_ 87 | inc e 88 | .db $FE 89 | _: 90 | dec e 91 | add a,l 92 | __LineHNext: 93 | djnz __LineHLoop 94 | ret 95 | -------------------------------------------------------------------------------- /ti8x/gfx/putspritemasked_fastest.z80: -------------------------------------------------------------------------------- 1 | ;Masked Sprite routine 2 | putsprite_masked: 3 | ;Inputs: 4 | ; (A,L) = (x,y) 5 | ; B is height 6 | ; IX points to the sprite data 7 | ; first byte is the data 8 | ; second byte is mask 9 | ; continues, alternating like this. 10 | ; 11 | ;Outputs: 12 | ; Mask is ORed to the buffer, then data is XORed on top of that. 13 | ; 14 | ;Destroys: 15 | ; AF, BC, DE, HL, IX 16 | ; 17 | ;Notes: 18 | ; To set a pixel... 19 | ; black: mask is 1, data is 0 20 | ; white: mask is 1, data is 1 21 | ; clear: mask is 0, data is 0 (keeps the data from the buffer) 22 | ; invert: mask is 0, data is 1 (inverts the data from the buffer) 23 | ; 24 | ;This routine is free to use :) 25 | ;63 bytes (or 64 bytes if gbuf is not located at 0x**40 26 | 27 | ld e,l 28 | ld h,0 29 | ld d,h 30 | add hl,hl 31 | add hl,de 32 | add hl,hl 33 | add hl,hl 34 | ld e,a 35 | and 7 36 | ld c,a 37 | xor e ;essentially gets E with the bottom 3 bits reset 38 | #if (plotSScreen&255) = 64 39 | inc a 40 | rra 41 | rra 42 | rra 43 | ld e,a 44 | ld d,plotSScreen>>8 45 | #else 46 | rra 47 | rra 48 | rra 49 | ld e,a 50 | add hl,de 51 | ld de,plotSScreen 52 | #endif 53 | add hl,de 54 | 55 | putsprite_masked_loop: 56 | push bc 57 | xor a 58 | ld d,(ix) 59 | ld e,a 60 | or c 61 | ld b,c 62 | ld c,e 63 | inc ix 64 | ld a,(ix) 65 | jr z,putsprite_masked_rotdone 66 | putsprite_masked_rot: 67 | rra 68 | rr c 69 | srl d 70 | rr e 71 | djnz putsprite_masked_rot 72 | putsprite_masked_rotdone: 73 | or (hl) 74 | xor d 75 | ld (hl),a 76 | inc hl 77 | ld a,(hl) 78 | or c 79 | xor e 80 | ld (hl),a 81 | ld c,11 82 | add hl,bc 83 | inc ix 84 | pop bc 85 | djnz putsprite_masked_loop 86 | ret 87 | -------------------------------------------------------------------------------- /conversion/fixed88_to_str.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_fixed88_to_str 2 | #define included_fixed88_to_str 3 | 4 | #include "subroutines/itoa_8.z80" 5 | 6 | 7 | ;Written by Zeda. 8 | ;This converts a fixed-point number to a string. 9 | ;It displays up to 3 digits after the decimal. 10 | 11 | fixed88_to_str: 12 | ;Inputs: 13 | ; D.E is the fixed-point number 14 | ; HL points to where the string gets output. 15 | ; Needs at most 9 bytes. 16 | ;Outputs: 17 | ; HL is preserved 18 | ;Destroys: 19 | ; AF,DE,BC 20 | 21 | ;First check if the input is negative. 22 | ;If so, write a negative sign and negate 23 | push hl 24 | ld a,d 25 | or a 26 | jp p,+_ 27 | ld (hl),$1A ;negative sign on TI-OS 28 | inc hl 29 | xor a 30 | sub e 31 | ld e,a 32 | sbc a,a 33 | sub d 34 | _: 35 | 36 | ;Our adjusted number is in A.E 37 | ;Now we can print the integer part 38 | call itoa_8 39 | 40 | ;Check if we need to print the fractional part 41 | xor a 42 | cp e 43 | jr z,fixed88_to_str_end 44 | 45 | ;We need to write the fractional part, so seek the end of the string 46 | ;Search for the null byte. A is already 0 47 | cpir 48 | 49 | ;Write a decimal 50 | dec hl 51 | ld (hl),'.' 52 | 53 | ld b,3 54 | _: 55 | ;Multiply E by 10, converting overflow to an ASCII digit 56 | call fixed88_to_str_e_times_10 57 | inc hl 58 | ld (hl),a 59 | djnz -_ 60 | 61 | ;Strip the ending zeros 62 | ld a,'0' 63 | _: 64 | cp (hl) 65 | dec hl 66 | jr z,-_ 67 | 68 | ;write a null byte 69 | inc hl 70 | inc hl 71 | ld (hl),0 72 | 73 | fixed88_to_str_end: 74 | ;restore HL 75 | pop hl 76 | ret 77 | 78 | fixed88_to_str_e_times_10: 79 | ld a,e 80 | ld d,0 81 | add a,a \ rl d 82 | add a,a \ rl d 83 | add a,e \ jr nc,$+3 \ inc d 84 | add a,a 85 | ld e,a 86 | ld a,d 87 | rla 88 | add a,'0' 89 | ret 90 | #endif 91 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Z80 Optimized (and/or Useful) Routines 2 | 3 | This is a repository of routines for the Z80! 4 | As of its inception, it will likely be expanded with the Z80 TI8x series of calculators in mind, but most routines should be general enough for other devices. 5 | 6 | Got an idea for how to make this resource better? Please let me know! 7 | Found an optimization? Please share! 8 | Got a useful routine or variation of a routine not yet here? Please add it! 9 | If you want to use a different license from the [default for this repository](LICENSE.md), 10 | then be sure to include it at the start of your file! 11 | 12 | If you share a routine that you didn't write, credit the author as best as you can (unless the author doesn't want to be credited). 13 | 14 | Thanks! 15 | 16 | # How To Use 17 | The way that I am using this repository is by adding it to my Include path with my favorite assembler ([spasm-ng](https://github.com/alberthdev/spasm-ng)). For example: 18 | 19 | ``` 20 | spasm foo.z80 bar.8xp -I ~/asm/z80/Z80-Optimized-Routines 21 | ``` 22 | Then I can `#include`, say, `mul32.z80` with: 23 | ``` 24 | #include "math/multiplication/mul32.z80" 25 | ``` 26 | 27 | # Other Resources 28 | * [Omnimaga's "ASM Optimized Routines"](https://www.omnimaga.org/asm-language/asm-optimized-routines/) 29 | * [Cemetech's Useful Routines](https://www.cemetech.net/forum/viewtopic.php?t=1449) 30 | * [United TI's Useful Routines](https://www.cemetech.net/projects/uti/viewtopic.php?t=1279) 31 | * [Z80 Heaven](http://z80-heaven.wikidot.com/) has optmization tricks and useful routines. 32 | * [wikiti Generic optimizations](https://wikiti.brandonw.net/index.php?title=Z80_Optimization) 33 | * [32-bit xorshift](https://gist.github.com/raxoft/c074743ea3f926db0037) 34 | * [cmwc rng](https://gist.github.com/raxoft/2275716fea577b48f7f) Complementary-Multiply-With-Carry RNG, very cool. 35 | -------------------------------------------------------------------------------- /math/squareroot/sqrt32.z80: -------------------------------------------------------------------------------- 1 | sqrt32: 2 | ;Input: HLDE 3 | ;Output: DE is the sqrt, AHL is the remainder 4 | ;speed: 238+{0,1}+{0,44}+sqrtHL+3*sqrt32sub_2+sqrt32_iter15 5 | ;min: 1260 6 | ;max: 1506 7 | ;avg: 1377.75 8 | 9 | push de 10 | call sqrtHL 11 | pop bc 12 | add a,a 13 | ld e,a 14 | jr nc,+_ 15 | inc d 16 | _: 17 | 18 | ld a,b 19 | call sqrt32sub_2 20 | call sqrt32sub_2 21 | ;Now we have four more iterations 22 | ;The first two are no problem 23 | ld a,c 24 | call sqrt32sub_2 25 | 26 | ;On the next iteration, HL might temporarily overflow by 1 bit 27 | call sqrt32_iter15 28 | 29 | ;On the next iteration, HL is allowed to overflow, DE could overflow with our current routine, but it needs to be shifted right at the end, anyways 30 | sqrt32_iter16: 31 | add a,a 32 | ld b,a ;either 0x00 or 0x80 33 | adc hl,hl 34 | rla 35 | adc hl,hl 36 | rla 37 | ;AHL - (DE+DE+1) 38 | sbc hl,de \ sbc a,b 39 | inc e 40 | or a 41 | sbc hl,de \ sbc a,b 42 | ret p 43 | add hl,de 44 | adc a,b 45 | dec e 46 | add hl,de 47 | adc a,b 48 | ret 49 | 50 | sqrt32sub_2: 51 | ;min: 185cc 52 | ;max: 231cc 53 | ;avg: 208cc 54 | call +_ 55 | 56 | _: 57 | ;min: 84cc 58 | ;max: 107cc 59 | ;avg: 95.5cc 60 | 61 | sll e \ rl d 62 | add a,a \ adc hl,hl 63 | add a,a \ adc hl,hl 64 | 65 | sbc hl,de 66 | inc e 67 | ret nc 68 | dec e 69 | add hl,de 70 | dec e 71 | ret 72 | 73 | sqrt32_iter15: 74 | ;91+{8,0+{0,23}} 75 | ;min: 91cc 76 | ;max: 114cc 77 | ;avg: 100.75cc 78 | 79 | sll e \ rl d ;sla e \ rl d \ inc e 80 | add a,a 81 | adc hl,hl 82 | add a,a 83 | adc hl,hl ;This might overflow! 84 | jr c,sqrt32_iter15_br0 85 | ; 86 | sbc hl,de 87 | inc e 88 | ret nc 89 | dec e 90 | add hl,de 91 | dec e 92 | ret 93 | sqrt32_iter15_br0: 94 | or a 95 | sbc hl,de 96 | inc e 97 | ret 98 | -------------------------------------------------------------------------------- /math/division/DEHL_Div_10.z80: -------------------------------------------------------------------------------- 1 | DEHL_Div_10: 2 | ;Inputs: 3 | ; DEHL 4 | ;Outputs: 5 | ; DEHL is the quotient 6 | ; A is the remainder 7 | ; B is the remainder 8 | ; C is 10 9 | ;912cc~941cc 10 | 11 | xor a 12 | ld c,10 13 | rl d \ rla 14 | rl d \ rla 15 | rl d \ rla 16 | rl d \ rla \ sub c \ jr nc,$+3 \ add a,c 17 | rl d \ rla \ sub c \ jr nc,$+3 \ add a,c 18 | rl d \ rla \ sub c \ jr nc,$+3 \ add a,c 19 | rl d \ rla \ sub c \ jr nc,$+3 \ add a,c 20 | rl d \ rla \ sub c \ jr nc,$+3 \ add a,c 21 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 22 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 23 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 24 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 25 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 26 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 27 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 28 | rl e \ rla \ sub c \ jr nc,$+3 \ add a,c 29 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 30 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 31 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 32 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 33 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 34 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 35 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 36 | rl h \ rla \ sub c \ jr nc,$+3 \ add a,c 37 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 38 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 39 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 40 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 41 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 42 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 43 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 44 | rl l \ rla \ sub c \ jr nc,$+3 \ add a,c 45 | ld b,a 46 | ld a,l \ rra \ ccf \ ld l,a 47 | ld a,h \ rra \ ccf \ ld h,a 48 | ld a,e \ rra \ ccf \ ld e,a 49 | ld a,d \ rra \ ccf \ ld d,a 50 | ld a,b 51 | ret 52 | -------------------------------------------------------------------------------- /math/rng/rng8_very_very_fast.z80: -------------------------------------------------------------------------------- 1 | ;This code snippet is 9 bytes and 43cc 2 | ;Inputs: 3 | ; HL is the input seed and must be non-zero 4 | ;Outputs: 5 | ; A is the 8-bit pseudo-random number 6 | ; HL is the new seed value (will be non-zero) 7 | ;opcode cc 8 | add hl,hl ; 29 11 9 | sbc a,a ; 9F 4 10 | and %00101101 ; E62D 7 11 | xor l ; AD 4 12 | ld l,a ; 6F 4 13 | ld a,r ; ED5F 9 14 | add a,h ; 84 4 15 | 16 | ;------------------------------------------------------------------------------- 17 | ;Technical details: 18 | ; The concept behind this routine is to combine an LFSR (poor RNG) with a 19 | ; counter. The counter improves the RNG quality, while also extending the period 20 | ; length. 21 | ; For this routine, I took advantage of the Z80's built-in counter, the `r` 22 | ; register. This means that we don't need to store the counter anywhere, and it 23 | ; is pretty fast to access! 24 | ; Some caveats: 25 | ; * r is a 7-bit counter 26 | ; * r will increment some number of times between runs of the RNG. In most 27 | ; cases, this will be constant, but if it increments an even number each 28 | ; time, then the bottom bit is always the same, weakening the effect of 29 | ; the counter. In the worst case, it increments a multiple of 128 times, 30 | ; effectively making your RNG just as good/bad as the LFSR. Ideally, you 31 | ; want `r` to increment an odd number of times between runs. 32 | ; * In the best case, the bottom 7 bits have 50/50 chance of being 0 or 1. 33 | ; The top bit is 1 with probability 1/2 + 1/(2^17-2) ~ .5000076295 34 | ; * In the event that your main loop waits for user input between calls, 35 | ; then congatulations, you might have a True RNG :) 36 | ;------------------------------------------------------------------------------- 37 | -------------------------------------------------------------------------------- /math/division/div_32_32.z80: -------------------------------------------------------------------------------- 1 | ;Made by Zeda Thomas, use it for whatever, and please optimize this! 2 | ;Slight Warning: This passed a handful of tests, but if you find a bug, 3 | ;please report it. I still actively maintain these (as of January 2020). 4 | 5 | div_32_32: 6 | ;Inputs: 7 | ; HLIX/BCDE 8 | ;Outputs: 9 | ; HLIX is the quotient 10 | ; BCDE is the remainder 11 | ;RAM: 12 | ; uses 8 bytes of RAM: 13 | ; 4 bytes at temp32_0 14 | ; 4 bytes at temp32_1 15 | ; 16 | ;min: 5240cc 17 | ;max: 6264cc 18 | ;avg: 5752cc 19 | ;113 bytes 20 | 21 | ; Back up HLIX 22 | ld (temp32_0),ix 23 | ld (temp32_0+2),hl 24 | 25 | 26 | ;negate BCDE 27 | xor a 28 | ld l,a \ sbc a,e \ ld e,a 29 | ld a,l \ sbc a,d \ ld d,a 30 | ld a,l \ sbc a,c \ ld c,a 31 | ld a,l \ sbc a,b \ ld b,a 32 | 33 | ld a,h 34 | ;set HLIX to 0 35 | ld h,l 36 | ld ix,0 37 | call div_32_by_32_sub 38 | ld (temp32_0+3),a 39 | 40 | ld a,(temp32_0+2) 41 | call div_32_by_32_sub 42 | ld (temp32_0+2),a 43 | 44 | ld a,(temp32_0+1) 45 | call div_32_by_32_sub 46 | ld (temp32_0+1),a 47 | 48 | ld a,(temp32_0+0) 49 | call div_32_by_32_sub 50 | ld (temp32_0),a 51 | 52 | push ix 53 | pop de 54 | ld b,h 55 | ld c,l 56 | ld ix,(temp32_0) 57 | ld hl,(temp32_0+2) 58 | ret 59 | 60 | 61 | 62 | div_32_by_32_sub: 63 | ;min: 1223cc 64 | ;max: 1479cc 65 | ;avg: 1351cc 66 | 67 | call +_ 68 | _: 69 | call +_ 70 | _: 71 | call +_ 72 | _: 73 | ;min: 138cc 74 | ;max: 170cc 75 | ;avg: 154cc 76 | ;HLIX*2 77 | add ix,ix 78 | adc hl,hl 79 | 80 | ;rotate in the bit 81 | add a,a 82 | jr nc,+_ 83 | inc ix 84 | _: 85 | 86 | ;save HLIX in case we need to restore 87 | ld (temp32_1),ix 88 | ld (temp32_1+2),hl 89 | 90 | ;check if HLIX>=-BCDE 91 | ; ==> HLIX+BCDE >= 0 92 | add ix,de 93 | adc hl,bc 94 | jr c,+_ 95 | 96 | ;we need to restore 97 | ld ix,(temp32_1) 98 | ld hl,(temp32_1+2) 99 | ret 100 | _: 101 | inc a 102 | ret 103 | -------------------------------------------------------------------------------- /ti8x/gfx/putspritemasked_faster.z80: -------------------------------------------------------------------------------- 1 | ;NOTE: This routine may be under a different License. 2 | 3 | ;Masked Sprite routine 4 | ;This is optimized by Zeda from a routine by Fallen Ghost, as a response to Kerm's routine. 5 | ;NOTE: Uses shadow registers! 6 | 7 | PutMask: 8 | ;Inputs: 9 | ; a = X coordinate 10 | ; l = Y coordinate 11 | ; b= height of sprite 12 | ; ix = sprite address 13 | ; ix+b = mask address (same length as sprite, please) 14 | ; 15 | ;Outputs: 16 | ; Mask and then sprite displayed at specified location on the graph buffer 17 | ; 18 | ;Destroys: 19 | ; AF, BC, DE, HL, IX, DE', HL' (shadow registers) 20 | ; 21 | ;Improvements from Kerm's DCS version: 22 | ; -Permits any height sprite 23 | ; -8 bytes less 24 | ; -Faster 25 | ld e,l 26 | ld h,0 27 | ld d,h 28 | add hl,hl 29 | add hl,de 30 | add hl,hl 31 | add hl,hl 32 | ld e,a 33 | and 7 34 | ld c,a 35 | xor e ;essentially gets E with the bottom 3 bits reset 36 | #if (plotSScreen&255) = 64 37 | inc a 38 | rra 39 | rra 40 | rra 41 | ld e,a 42 | ld d,plotSScreen>>8 43 | #else 44 | rra 45 | rra 46 | rra 47 | ld e,a 48 | add hl,de 49 | ld de,plotSScreen 50 | #endif 51 | add hl,de 52 | 53 | ld a,b 54 | exx 55 | add a,ixl 56 | ld l,a 57 | ld a,ixh 58 | adc a,0 59 | ld h,a 60 | exx 61 | putMaskLoop1: 62 | exx 63 | ld d,0FFh 64 | ld e,(hl) 65 | inc hl 66 | exx 67 | xor a 68 | ld d,(ix) 69 | ld e,a 70 | sub c 71 | jr z,putMaskSkip1 72 | putMaskLoop2: 73 | exx 74 | rr e 75 | rr d 76 | exx 77 | srl d 78 | rr e 79 | sub -1 80 | jr nz,putMaskLoop2 81 | putMaskSkip1: 82 | ld a,(hl) 83 | exx 84 | and e 85 | exx 86 | or d 87 | ld (hl),a 88 | inc hl 89 | ld a,(hl) 90 | exx 91 | and d 92 | exx 93 | or e 94 | ld (hl),a 95 | ld de,00Bh 96 | add hl,de 97 | inc ix 98 | djnz putMaskLoop1 99 | ret 100 | -------------------------------------------------------------------------------- /conversion/fixed_4_12_to_str.z80: -------------------------------------------------------------------------------- 1 | #ifndef included_fixed_4_12_to_str 2 | #define included_fixed_4_12_to_str 3 | 4 | ;Written by Zeda, free to use. 5 | ;This converts a 4.12 fixed-point number to a string. 6 | ;It displays up to 4 digits after the decimal. 7 | 8 | fixed_4_12_to_str: 9 | ;Inputs: 10 | ; D.E is the fixed-point number 11 | ; HL points to where the string gets output. 12 | ; Needs at most 8 bytes. 13 | ;Outputs: 14 | ; HL is preserved 15 | ;Destroys: 16 | ; AF,DE,BC 17 | 18 | ;First check if the input is negative. 19 | ;If so, write a negative sign and negate 20 | push hl 21 | ld a,d 22 | or a 23 | jp p,+_ 24 | ld (hl),$1A ;negative sign on TI-OS 25 | inc hl 26 | xor a 27 | sub e 28 | ld e,a 29 | sbc a,a 30 | sub d 31 | _: 32 | 33 | ;Get the first digit (between 0 and 7) 34 | ld d,a 35 | rrca 36 | rrca 37 | rrca 38 | rrca 39 | and 15 40 | add a,'0' 41 | ld (hl),a 42 | inc hl 43 | 44 | ; Check if we have a fractional part 45 | ld a,d 46 | and $0F 47 | ld d,a 48 | or e 49 | jr nz,$+5 50 | ld (hl),a 51 | pop hl 52 | ret 53 | 54 | ;Write a decimal 55 | ld (hl),'.' 56 | 57 | ; DE is the 12 fractional bits. Shift left 4 and add 3 (for rouding) 58 | ex de,hl 59 | add hl,hl 60 | add hl,hl 61 | add hl,hl 62 | inc l 63 | add hl,hl 64 | inc l 65 | ex de,hl 66 | 67 | 68 | ld b,4 69 | _: 70 | ;Multiply DE by 10, converting overflow to an ASCII digit 71 | call fixed_4_12_to_str_de_times_10 72 | inc hl 73 | ld (hl),a 74 | djnz -_ 75 | 76 | ;Strip the ending zeros 77 | ld a,'0' 78 | _: 79 | cp (hl) 80 | dec hl 81 | jr z,-_ 82 | 83 | ;write a null byte 84 | inc hl 85 | inc hl 86 | ld (hl),0 87 | 88 | ;restore HL 89 | pop hl 90 | ret 91 | 92 | fixed_4_12_to_str_de_times_10: 93 | push hl 94 | xor a 95 | ld h,d 96 | ld l,e 97 | add hl,hl \ rla 98 | add hl,hl \ rla 99 | add hl,de \ adc a,$18 ; half of '0' 100 | add hl,hl \ rla 101 | ex de,hl 102 | pop hl 103 | ret 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /ti8x/gfx/sprite8.z80: -------------------------------------------------------------------------------- 1 | sprite8: 2 | ;Input: H is method, DE points to sprite, (B,C)=(x,y) 3 | ; H=0 Erase 4 | ; H=1 OR 5 | ; H=2 XOR 6 | ; H=3 Overwrite 7 | push hl 8 | push de 9 | push bc 10 | push af 11 | call +_ 12 | pop af 13 | pop bc 14 | pop de 15 | pop hl 16 | ret 17 | _: 18 | ld a,b 19 | ld (sprite_x),a 20 | add a,7 21 | cp 96+7 22 | ret nc 23 | ld a,c 24 | add a,7 25 | cp 64+7 26 | ret nc 27 | sub 7 28 | push af 29 | ld a,h 30 | and 3 31 | ld h,a 32 | sub 1 33 | sbc a,a 34 | ld (mask),a 35 | and $2F ;$2F == CPL 36 | ld (invert),a 37 | ld a,h 38 | add a,a 39 | add a,a 40 | add a,a 41 | add a,$A6 42 | ld (logic1),a 43 | ld (logic2),a 44 | 45 | ld a,b 46 | ld b,0 47 | bit 7,c 48 | jr z,$+3 49 | dec b 50 | ld h,b 51 | ld l,c 52 | add hl,hl 53 | add hl,bc 54 | add hl,hl 55 | add hl,hl 56 | ld c,a 57 | sra c 58 | sra c 59 | sra c 60 | ld b,0 61 | bit 7,c 62 | jr z,$+3 63 | dec b 64 | add hl,bc 65 | ld bc,gbuf 66 | add hl,bc 67 | and 7 68 | ld (rotate),a 69 | ld b,8 70 | pop af 71 | sprite8loop: 72 | cp 64 73 | jr nc,endsprite8loop 74 | push bc 75 | push af 76 | mask=$+1 77 | ld c,0 78 | ld a,(de) 79 | invert: 80 | nop 81 | rrc c 82 | rotate=$+1 83 | ld b,0 84 | inc b 85 | dec b 86 | jr z,$+7 87 | rra 88 | rr c 89 | djnz $-3 90 | ld b,a 91 | call writeSprite 92 | pop af 93 | pop bc 94 | endsprite8loop: 95 | inc a 96 | inc de 97 | djnz sprite8loop 98 | ret 99 | writeSprite: 100 | sprite_x=$+1 101 | ld a,0 102 | cp 96 103 | jr nc,$+8 104 | ld a,b 105 | logic1: 106 | nop 107 | ld (hl),a 108 | ld a,(sprite_x) 109 | inc hl 110 | add a,8 111 | cp 96 112 | jr nc,$+5 113 | ld a,c 114 | logic2: 115 | nop 116 | ld (hl),a 117 | ld bc,11 118 | add hl,bc 119 | ret 120 | -------------------------------------------------------------------------------- /ti8x/utility/ConvOP.z80: -------------------------------------------------------------------------------- 1 | ;Converts a TI float in the way ConvOP1 does it. 2 | ;Offers a wider range, and reading floats from arbitrary locations, not just OP1. 3 | 4 | ConvOP1: 5 | ;Output: HL is the 16-bit result. 6 | ld de,OP1 7 | ConvFloat: 8 | ;Input: DE points to the float. 9 | ;Output: HL is the 16-bit result. 10 | ;Errors: DataType if the float is negative or complex 11 | ; Domain if the integer exceeds 16 bits. 12 | ;Timings: Assume no errors were called. 13 | ; Input is on: 14 | ; (0,1) => 57cc Average=59 15 | ; 0 or [1,10) => 118cc or 127cc =124.5 16 | ; [10,100) => 174cc or 175cc =176.5 17 | ; [100,1000) => 307cc, 308cc, 316cc, or 317cc. =312 18 | ; [1000,10000) => 374cc to 376cc =375 19 | ; [10000,65536) => 512cc to 514cc, or 521cc to 523cc =517.5 20 | ;Average case: 494.577178955078125cc 21 | ;vs 959.656982421875cc 22 | ;86 bytes 23 | 24 | ld a,(de) 25 | or a 26 | jr nz,ErrDataType 27 | inc de 28 | ld h,a 29 | ld l,a 30 | ld a,(de) 31 | inc de 32 | sub 80h 33 | ret c 34 | jr z,final 35 | cp 5 36 | jp c,enterloop 37 | ErrDomain: 38 | ;Throws a domain error. 39 | bcall(_ErrDomain) 40 | ErrDataType: 41 | ;Throws a data type error. 42 | bcall(_ErrDataType) 43 | loop: 44 | ld a,b 45 | ld b,h 46 | ld c,l 47 | add hl,hl 48 | add hl,bc 49 | add hl,hl 50 | add hl,hl 51 | add hl,hl 52 | add hl,bc 53 | add hl,hl 54 | add hl,hl 55 | enterloop: 56 | ld b,a 57 | ex de,hl 58 | ld a,(hl) \ and $F0 \ rra \ ld c,a \ rra \ rra \ sub c \ add a,(hl) 59 | inc hl 60 | ex de,hl 61 | add a,l 62 | ld l,a 63 | jr nc,$+3 64 | inc h 65 | dec b 66 | ret z 67 | djnz loop 68 | ld b,h 69 | ld c,l 70 | xor a 71 | ;check overflow in this mul by 10! 72 | add hl,hl \ adc a,a 73 | add hl,hl \ adc a,a 74 | add hl,bc \ adc a,0 75 | add hl,hl \ adc a,a 76 | jr nz,ErrDomain 77 | final: 78 | ld a,(de) 79 | rrca 80 | rrca 81 | rrca 82 | rrca 83 | and 15 84 | add a,l 85 | ld l,a 86 | ret nc 87 | inc h 88 | ret nz 89 | jr ErrDomain 90 | -------------------------------------------------------------------------------- /math/multiplication/mul32.z80: -------------------------------------------------------------------------------- 1 | ;Requires: 2 | ; mul16 3 | ; Inputs: BC,DE 4 | ; Output: DEHL 5 | ; 8 bytes at z32_0 (you must define this) 6 | 7 | 8 | mul32: 9 | ;max: 703cc + 3*mul16 10 | ; 2704cc 11 | ;min: 655cc + 3*mul16 12 | ; 1297cc 13 | ;avg: 673.25cc+3*mul16 14 | ; 2307.911cc 15 | ;DEHL * BCIX ==> z32_0 16 | z32_2 = z32_0+4 17 | 18 | push de 19 | push bc 20 | push hl 21 | push ix 22 | call mul16 ;DEHL 23 | ld (z32_2),hl 24 | ld (z32_2+2),de 25 | 26 | pop de 27 | pop bc 28 | ; push bc 29 | push de 30 | call mul16 ;DEHL 31 | ld (z32_0),hl 32 | ld (z32_0+2),de 33 | 34 | pop de ;low word 35 | ; pop bc ;low word 36 | pop hl 37 | xor a 38 | sbc hl,de 39 | jr nc,+_ 40 | sub l 41 | ld l,a 42 | sbc a,a 43 | sub h 44 | ld h,a 45 | xor a 46 | inc a 47 | _: 48 | ex de,hl 49 | pop hl 50 | sbc hl,bc 51 | jr nc,+_ 52 | ld b,a 53 | xor a 54 | sub l 55 | ld l,a 56 | sbc a,a 57 | sub h 58 | ld h,a 59 | ld a,b 60 | inc a 61 | _: 62 | ld b,h 63 | ld c,l 64 | push af 65 | call mul16 66 | pop af ;holds the sign in the low bit 67 | rra 68 | jr c,mul32_add 69 | ;need to perform z0+z2-result 70 | push de 71 | push hl 72 | xor a 73 | ld hl,(z32_0) 74 | ld bc,(z32_2) 75 | add hl,bc 76 | ex de,hl 77 | ld hl,(z32_0+2) 78 | ld bc,(z32_2+2) 79 | adc hl,bc 80 | rla 81 | ;now need to subtract 82 | ex de,hl 83 | pop bc 84 | sbc hl,bc 85 | ex de,hl 86 | pop bc 87 | sbc hl,bc 88 | sbc a,0 89 | ;A:HL:DE is the result, need to add to z32_0+2 90 | mul32_final: 91 | ld bc,(z32_0+2) 92 | ex de,hl 93 | add hl,bc 94 | ld (z32_0+2),hl 95 | ld hl,(z32_2) 96 | adc hl,de 97 | ld (z32_2),hl 98 | ld hl,z32_2+2 99 | adc a,(hl) 100 | ld (hl),a 101 | ret nc 102 | inc hl 103 | inc (hl) 104 | ret 105 | mul32_add: 106 | ;add to the current result 107 | xor a 108 | ld bc,(z32_0) 109 | add hl,bc 110 | ex de,hl 111 | ld bc,(z32_0+2) 112 | adc hl,bc 113 | rla 114 | ex de,hl 115 | ld bc,(z32_2) 116 | add hl,bc 117 | ex de,hl 118 | ld bc,(z32_2+2) 119 | adc hl,bc 120 | adc a,0 121 | jp mul32_final 122 | -------------------------------------------------------------------------------- /math/rng/rand5.z80: -------------------------------------------------------------------------------- 1 | rand5: 2 | ;Returns A on [0,4] 3 | ;Destroys: All 4 | ;Notes: 5 | ; This is a non-standard approach to generating random integers on [0,4]. 6 | ; If you have a truly random number generator that generates bits (0 or 1) 7 | ; with equal probability, then standard approaches will still cause a slight 8 | ; bias. ("Standard": "rand mod 5" or int(5*rand)). For example, suppose we 9 | ; generate a 4-bit number. Then "rand mod 5" will cause 0 to be chosen 10 | ; 4/16 times, while 1, 2, 3, and 4 will be chosen 3/16 times (on average). 11 | ; A similar problem exists with int(5*rand). One way to mitigate this issue 12 | ; is just generating infintely many bits, but apparently that is impractical, 13 | ; so I came up with a compromise. 14 | ; 15 | ; My approach basically looks at the binary expansion of 1/5, 2/5, 3/5, and 4/5. 16 | ; 1/5 = .0011001100110011... 17 | ; 2/5 = .0110011001100110... 18 | ; 3/5 = .1001100110011001... 19 | ; 4/5 = .1100110011001100... 20 | ; 21 | ; So if I generate random bits and I get .001100, then a 0, then I know 22 | ; that no matter what all of the rest of the bits are, the number is less than 23 | ; 1/5, and so int(5*rand) is 0. 24 | ; 25 | ; By applying similar logic to the rest of the values, I can guarantee a uniform 26 | ; distribution on [0,4]. But there are four cases where this process might 27 | ; continue forever, specifically the cases that are like ...00110011...., but 28 | ; lucky for us, this happens 4/inf= 0% of the time. In fact, on average it 29 | ; takes 3 to 4 bits before the algorithm can assert which value to return. 30 | ; 31 | ; The one caveat is that on the Z80, we generally don't have truly random 32 | ; numbers :| On the otherhand, it is easy enough to generate pseudo-random 33 | ; bits with equal probability :) 34 | 35 | call rand 36 | ld a,h 37 | and $C0 38 | push af ;save the original value 39 | ld c,a 40 | rand5_start: 41 | push bc 42 | call rand 43 | pop bc 44 | ld b,15 ;I set this to 15 because I like to guarantee a bit is available for rand10. 45 | rand5_loop: 46 | ld a,h 47 | xor c 48 | jp p,rand5_end 49 | add hl,hl 50 | sla c 51 | jr c,$+4 52 | set 6,c 53 | djnz rand5_loop 54 | jr rand5_start 55 | 56 | rand5_end: 57 | pop af 58 | rlca 59 | rlca 60 | sla h 61 | adc a,0 62 | ret 63 | -------------------------------------------------------------------------------- /ti8x/gfx/gbuf_to_lcd_15MHz.z80: -------------------------------------------------------------------------------- 1 | ;This routine uses a time-base delay, which should work with the newer (2019) 2 | ;calculator models whose LCD has a malfunctioning status bit. 3 | ; 4 | ;The TI-83+/84+ and similar calculators have a clock speed that varies based on 5 | ;a number of factors, so we'll assume it is up to 16.5MHz. According to TI's 6 | ;documentation, we'll need 10 microseconds beteen writes to the LCD, so that's 7 | ;165 clock cycles at 16.5MHz 8 | ;Since an out takes at least 11cc, we'll aim for 154cc between outs 9 | 10 | #ifndef included_gbuf_to_lcd_15MHz 11 | #define included_gbuf_to_lcd_15MHz 12 | 13 | gbuf_to_lcd_15MHz: 14 | ;This copies the contents of gbuf to the LCD. 15 | ;Preserves all registers. 16 | push hl ;11 11 17 | push de ;11 22 18 | push bc ;11 33 19 | push af ;11 44 20 | ex (sp),hl ;19 63 \ 21 | ex (sp),hl ;19 82 | 22 | ex (sp),hl ;19 101 | 23 | ex (sp),hl ;19 120 | waste clock cycles 24 | inc hl ;6 126 | 25 | ld a,(hl) ;7 133 | 26 | ld a,(hl) ;7 140 | 27 | ld a,(hl) ;7 147 / 28 | ld a,$80 ;7 154 29 | out (16),a ;11 0 30 | 31 | 32 | ld a,r ;9 9 | waste clock cycles 33 | ld a,$20 ;7 16 34 | ld hl,gbuf ;10 26 35 | ex (sp),hl ;19 45 \ 36 | ex (sp),hl ;19 64 | 37 | col: 38 | ex (sp),hl ;19 83 | 39 | ex (sp),hl ;19 102 | waste clock cycles 40 | ex (sp),hl ;19 121 | 41 | ex (sp),hl ;19 140 | 42 | nop ;4 144 / 43 | ld de,11 ;10 154 44 | out (10h),a ;11 0 45 | ld b,(hl) ;7 7 46 | xor b ;4 11 \ waste clock cycles 47 | xor b ;4 15 / 48 | ld bc,$8011 ;10 25 49 | nop ;4 29 50 | 51 | row: 52 | ex (sp),hl ;19 48 \ 53 | ex (sp),hl ;19 67 | 54 | ex (sp),hl ;19 86 | 55 | ex (sp),hl ;19 105 | waste clock cycles 56 | ex (sp),hl ;19 124 | 57 | ex (sp),hl ;19 143 | 58 | ld c,17 ;7 150 | 59 | nop ;4 154 / 60 | outi ;16 5 61 | add hl,de ;11 16 62 | djnz row ;13/8 29/24 63 | inc a ;4 28 64 | dec h ;4 32 65 | dec h ;4 36 66 | dec h ;4 40 67 | inc hl ;6 46 68 | cp $2C ;7 53 69 | jr nz,col ;12/7 65 70 | pop af ;10 71 | pop bc ;10 72 | pop de ;10 73 | pop hl ;10 74 | ret ;10 75 | #endif 76 | -------------------------------------------------------------------------------- /math/float/singleprecision.md: -------------------------------------------------------------------------------- 1 | Single precision routines can be found at [z80float](https://github.com/Zeda/z80float/tree/master/single). As of this writing, these include: 2 | ``` 3 | absSingle Absolute Value 4 | cmpSingle Compare two floats 5 | negSingle Negate 6 | intfrac Gets the integer part of a float 7 | mod1Single Gets the fractional part of a number (x-int(x)) 8 | randSingle rand 9 | 10 | addSingle Addition 11 | rsubSingle reverse subtract (y-x instead of x-y) 12 | subSingle Subtraction 13 | ameanSingle Arithmetic mean 14 | 15 | mulSingle Multiplication 16 | mul10Single Multiplication by 10 17 | mulSingle_p375 Multiplication by .375 18 | mulSingle_p34375 Multiplication by .34375 19 | mulSingle_p041015625 Multiplication by .041015625 20 | 21 | divSingle Division 22 | invSingle 1/x 23 | divSingle_special Special-purpose divisions 24 | 25 | sqrtSingle Square Root 26 | geomeanSingle Geometric Mean 27 | 28 | 29 | bg2iSingle Computes the Borchardt-Gauss mean to limited precision 30 | bgiSingle Computes the Borchardt-Gauss mean 31 | 32 | expSingle Exponential Function 33 | pow2Single 2^x 34 | pow10Single 10^x 35 | powSingle x^y 36 | 37 | lnSingle Log (Natural logarithm) 38 | lgSingle Log2 (Log base 2) 39 | log10Single Log10 (Log base 10) 40 | logSingle LogY (Log base Y) 41 | 42 | single2char Converts a float to an unsigned 8-bit integer 43 | singleTo_int16 Converts a single to a signed 16-bit integer 44 | single2str Single --> Str 45 | str2single String --> Single 46 | single2TI Single --> TI Float 47 | ti2single TI Float --> Single 48 | 49 | 50 | cosSingle Cosine 51 | sinSingle Sine 52 | tanSingle Tangent 53 | cisSingle Cosine and Sine (faster than individually computing both) 54 | coshSingle Hyperbolic Cosine 55 | sinhSingle Hyperbolic Sine 56 | tanhSingle Hyperbolic Tangent 57 | 58 | acosSingle Arccosine 59 | asinSingle Arcsine 60 | atanSingle Arctangent 61 | acoshSingle Hyperbolic Arccosine 62 | asinhSingle Hyperbolic Arcsine 63 | atanhSingle Hyperbolic Arctangent 64 | 65 | single.inc Useful equates 66 | lut Look-up Tables 67 | constants Contains useful constants 68 | data Data 69 | 70 | ``` 71 | -------------------------------------------------------------------------------- /math/division/divfixed_88.z80: -------------------------------------------------------------------------------- 1 | BC_Div_DE_88: 2 | ;Inputs: 3 | ; DE,BC are 8.8 Fixed Point numbers 4 | ;Outputs: 5 | ; HL is the 8.8 Fixed Point result (rounded to the least significant bit) 6 | ;if DE is 0 : 122cc or 136cc if BC is negative 7 | ;if |BC|>=128*|DE| : 152cc or 166cc if BC is negative 8 | ;Otherwise: 9 | ;min: 1164cc 10 | ;max: 1377cc 11 | ;avg: 1258.5cc 12 | ; First, find out if the output is positive or negative 13 | ld a,b 14 | xor d 15 | push af ;sign bit is the result sign bit 16 | 17 | ; Now make sure the inputs are positive 18 | xor d ;A now has the value of B, since I XORed it with D twice (cancelling) 19 | jp p,+_ ;if Positive, don't negate 20 | xor a 21 | sub c 22 | ld c,a 23 | sbc a,a 24 | sub b 25 | ld b,a 26 | _: 27 | 28 | ;now make DE negative to optimize the remainder comparison 29 | ld a,d 30 | or d 31 | jp m,+_ 32 | xor a 33 | sub e 34 | ld e,a 35 | sbc a,a 36 | sub d 37 | ld d,a 38 | _: 39 | 40 | ;if DE is 0, we can call it an overflow 41 | ;A is the current value of D 42 | or e 43 | jr z,div_fixed88_overflow 44 | 45 | ;The accumulator gets set to B if no overflow. 46 | ;We can use H=0 to save a few cc in the meantime 47 | ld h,0 48 | 49 | ;if B+DE>=0, then we'll have overflow 50 | ld a,b 51 | add a,e 52 | ld a,d 53 | adc a,h 54 | jr c,div_fixed88_overflow 55 | 56 | ;Now we can load the accumulator/remainder with B 57 | ;H is already 0 58 | ld l,b 59 | 60 | ld a,c 61 | call div_fixed88_sub 62 | ld c,a 63 | 64 | ld a,b ;A is now 0 65 | call div_fixed88_sub 66 | 67 | ; if 2HL+DE>=0, increment result to round. 68 | add hl,hl 69 | add hl,de 70 | ld h,c 71 | ld l,a 72 | jr nc,$+3 73 | inc hl 74 | 75 | ;Now check if H is overflowed 76 | bit 7,h 77 | jr nz,div_fixed88_overflow 78 | 79 | 80 | pop af 81 | ret p 82 | xor a 83 | sub l 84 | ld l,a 85 | sbc a,a 86 | sub h 87 | ld h,a 88 | ret 89 | 90 | div_fixed88_overflow: 91 | ld hl,$7FFF 92 | pop af 93 | ret p 94 | inc hl 95 | inc l 96 | ret 97 | 98 | div_fixed88_sub: 99 | ;min: 456cc 100 | ;max: 536cc 101 | ;avg: 496cc 102 | ld b,8 103 | _: 104 | rla 105 | adc hl,hl 106 | add hl,de 107 | jr c,$+4 108 | sbc hl,de 109 | djnz -_ 110 | adc a,a 111 | ret 112 | -------------------------------------------------------------------------------- /math/squareroot/sqrtfixed_88_fast.z80: -------------------------------------------------------------------------------- 1 | ;Written by Zeda 2 | 3 | sqrtfixed_88: 4 | ;Input: A.E ==> D.E 5 | ;Output: DE is the sqrt, AHL is the remainder 6 | ;Speed: 690+6{0,13}+{0,3+{0,18}}+{0,38}+sqrtA 7 | ;min: 855cc 8 | ;max: 1003cc 9 | ;avg: 924.5cc 10 | ;152 bytes 11 | 12 | call sqrtA 13 | ld l,a 14 | ld a,e 15 | ld h,0 16 | ld e,d 17 | ld d,h 18 | 19 | sla e 20 | rl d 21 | 22 | sll e \ rl d 23 | add a,a \ adc hl,hl 24 | add a,a \ adc hl,hl 25 | sbc hl,de 26 | jr nc,+_ 27 | add hl,de 28 | dec e 29 | .db $FE ;start of `cp *` 30 | _: 31 | inc e 32 | 33 | sll e \ rl d 34 | add a,a \ adc hl,hl 35 | add a,a \ adc hl,hl 36 | sbc hl,de 37 | jr nc,+_ 38 | add hl,de 39 | dec e 40 | .db $FE ;start of `cp *` 41 | _: 42 | inc e 43 | 44 | sll e \ rl d 45 | add a,a \ adc hl,hl 46 | add a,a \ adc hl,hl 47 | sbc hl,de 48 | jr nc,+_ 49 | add hl,de 50 | dec e 51 | .db $FE ;start of `cp *` 52 | _: 53 | inc e 54 | 55 | sll e \ rl d 56 | add a,a \ adc hl,hl 57 | add a,a \ adc hl,hl 58 | sbc hl,de 59 | jr nc,+_ 60 | add hl,de 61 | dec e 62 | .db $FE ;start of `cp *` 63 | _: 64 | inc e 65 | 66 | ;Now we have four more iterations 67 | ;The first two are no problem 68 | sll e \ rl d 69 | add hl,hl 70 | add hl,hl 71 | sbc hl,de 72 | jr nc,+_ 73 | add hl,de 74 | dec e 75 | .db $FE ;start of `cp *` 76 | _: 77 | inc e 78 | 79 | sll e \ rl d 80 | add hl,hl 81 | add hl,hl 82 | sbc hl,de 83 | jr nc,+_ 84 | add hl,de 85 | dec e 86 | .db $FE ;start of `cp *` 87 | _: 88 | inc e 89 | 90 | sqrtfixed_88_iter11: 91 | ;On the next iteration, HL might temporarily overflow by 1 bit 92 | sll e \ rl d ;sla e \ rl d \ inc e 93 | add hl,hl 94 | add hl,hl 95 | jr c,sqrtfixed_88_iter11_br0 96 | ; 97 | sbc hl,de 98 | jr nc,+_ 99 | add hl,de 100 | dec e 101 | jr sqrtfixed_88_iter12 102 | sqrtfixed_88_iter11_br0: 103 | or a 104 | sbc hl,de 105 | _: 106 | inc e 107 | 108 | ;On the next iteration, HL is allowed to overflow, DE could overflow with our current routine, but it needs to be shifted right at the end, anyways 109 | sqrtfixed_88_iter12: 110 | ld b,a ;A is 0, so B is 0 111 | add hl,hl 112 | add hl,hl 113 | rla 114 | ;AHL - (DE+DE+1) 115 | sbc hl,de \ sbc a,b 116 | inc e 117 | or a 118 | sbc hl,de \ sbc a,b 119 | ret p 120 | add hl,de 121 | adc a,b 122 | dec e 123 | add hl,de 124 | adc a,b 125 | ret 126 | -------------------------------------------------------------------------------- /math/misc/natlog_fixed88.z80: -------------------------------------------------------------------------------- 1 | lognat: 2 | ;Input: H.L needs to be on (0,128.0) 3 | ;Output: H.L if c flag set 4 | ; returns nc if input is negative (HL not modified) 5 | ;Error: 6 | ; The error on the outputs is as follows: 7 | ; 20592 inputs are exact 8 | ; 12075 inputs are off by 1/256 9 | ; 100 inputs are off by 2/256 10 | ; So all 32767 inputs are within 2/256, with average error being <1/683 which is smaller than 1/256. 11 | ;Size: 177 bytes 12 | ;Speed: average speed is less than 1250 t-states 13 | 14 | ld a,h \ or l \ jr nz,$+5 15 | ld h,80h \ ret 16 | dec h 17 | dec h 18 | jr nz,$+9 19 | inc l \ dec l 20 | jr nz,normalizeln-1 21 | ld l,177 22 | ret 23 | inc h 24 | jr nz,normalizeln 25 | ld b,h 26 | ld c,l 27 | ld e,l 28 | ld d,8 29 | add hl,hl 30 | add hl,hl 31 | add hl,de 32 | ex de,hl 33 | call HL_Div_DE 34 | ld h,a \ ld l,b 35 | sla h \ jr c,$+3 \ ld l,c 36 | add hl,hl \ jr c,$+3 \ add hl,bc 37 | add hl,hl \ jr c,$+3 \ add hl,bc 38 | add hl,hl \ jr c,$+3 \ add hl,bc 39 | add hl,hl \ jr c,$+3 \ add hl,bc 40 | add hl,hl \ jr c,$+3 \ add hl,bc 41 | add hl,hl \ jr c,$+3 \ add hl,bc 42 | add hl,hl \ jr c,$+3 \ add hl,bc 43 | rl l 44 | ld a,h 45 | adc a,b 46 | ld h,b 47 | ld l,a 48 | scf 49 | ret 50 | HL_Div_DE: 51 | add hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de \ adc a,a 52 | add hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de \ adc a,a 53 | add hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de \ adc a,a 54 | add hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de \ adc a,a 55 | add hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de \ adc a,a 56 | add hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de \ adc a,a 57 | add hl,hl \ sbc hl,de \ jr nc,$+3 \ add hl,de \ adc a,a 58 | add hl,hl \ sbc hl,de \ adc a,a \ ret 59 | 60 | inc h 61 | normalizeln: 62 | xor a 63 | inc h \ ret m 64 | ld d,a \ ld e,a 65 | ld a,l 66 | jr z,toosmall 67 | inc e \ srl h \ rra \ jr nz,$-4 68 | rla \ rl h 69 | dec e 70 | stepin: 71 | ld l,a 72 | push de 73 | call lognat 74 | pop de 75 | ;now multiply DE by 355, then divide by 2 (rounding) 76 | ld b,d \ ld c,e \ ld a,d 77 | ex de,hl 78 | add hl,hl 79 | add hl,hl ;4 80 | add hl,bc ;5 81 | add hl,hl ;10 82 | add hl,bc ;11 83 | add hl,hl ;22 84 | add hl,hl 85 | add hl,hl 86 | add hl,hl 87 | add hl,bc 88 | add hl,hl 89 | add hl,bc 90 | sra h \ rr l 91 | adc hl,de 92 | scf 93 | ret 94 | toosmall: 95 | dec d 96 | dec e \ add a,a \ jr nc,$-2 97 | inc h 98 | jp stepin 99 | -------------------------------------------------------------------------------- /math/misc/log2fixed_88_table.z80: -------------------------------------------------------------------------------- 1 | lg_88: 2 | ;Input: HL is a fixed point number 3 | ;Output: lg(H.L)->H.L 4 | ;Speed: Avg: 340 5 | ld de,lgLUT 6 | ld b,0 7 | ld a,h 8 | or a 9 | ret m 10 | ld a,l 11 | jr z,$+8 12 | inc b \ srl h \ rra \ jr nz,$-4 13 | or a \ jr nz,$+6 14 | ld hl,8000h \ ret 15 | rra \ inc b \ jr nc,$-2 16 | ;A is the element to look up in the LUT 17 | ld l,a 18 | ld c,h 19 | dec b 20 | add hl,hl 21 | add hl,de 22 | ld e,(hl) 23 | inc hl 24 | ld d,(hl) 25 | ex de,hl 26 | add hl,bc 27 | ret 28 | lglut: 29 | .dw $F800 30 | .dw $F996 31 | .dw $FA52 32 | .dw $FACF 33 | .dw $FB2C 34 | .dw $FB76 35 | .dw $FBB3 36 | .dw $FBE8 37 | .dw $FC16 38 | .dw $FC3F 39 | .dw $FC64 40 | .dw $FC86 41 | .dw $FCA5 42 | .dw $FCC1 43 | .dw $FCDC 44 | .dw $FCF4 45 | .dw $FD0B 46 | .dw $FD21 47 | .dw $FD36 48 | .dw $FD49 49 | .dw $FD5C 50 | .dw $FD6D 51 | .dw $FD7E 52 | .dw $FD8E 53 | .dw $FD9D 54 | .dw $FDAC 55 | .dw $FDBA 56 | .dw $FDC8 57 | .dw $FDD5 58 | .dw $FDE2 59 | .dw $FDEE 60 | .dw $FDFA 61 | .dw $FE06 62 | .dw $FE11 63 | .dw $FE1C 64 | .dw $FE26 65 | .dw $FE31 66 | .dw $FE3B 67 | .dw $FE44 68 | .dw $FE4E 69 | .dw $FE57 70 | .dw $FE60 71 | .dw $FE69 72 | .dw $FE71 73 | .dw $FE7A 74 | .dw $FE82 75 | .dw $FE8A 76 | .dw $FE92 77 | .dw $FE9A 78 | .dw $FEA1 79 | .dw $FEA9 80 | .dw $FEB0 81 | .dw $FEB7 82 | .dw $FEBE 83 | .dw $FEC5 84 | .dw $FECB 85 | .dw $FED2 86 | .dw $FED8 87 | .dw $FEDF 88 | .dw $FEE5 89 | .dw $FEEB 90 | .dw $FEF1 91 | .dw $FEF7 92 | .dw $FEFD 93 | .dw $FF03 94 | .dw $FF09 95 | .dw $FF0E 96 | .dw $FF14 97 | .dw $FF19 98 | .dw $FF1E 99 | .dw $FF24 100 | .dw $FF29 101 | .dw $FF2E 102 | .dw $FF33 103 | .dw $FF38 104 | .dw $FF3D 105 | .dw $FF42 106 | .dw $FF47 107 | .dw $FF4B 108 | .dw $FF50 109 | .dw $FF55 110 | .dw $FF59 111 | .dw $FF5E 112 | .dw $FF62 113 | .dw $FF67 114 | .dw $FF6B 115 | .dw $FF6F 116 | .dw $FF74 117 | .dw $FF78 118 | .dw $FF7C 119 | .dw $FF80 120 | .dw $FF84 121 | .dw $FF88 122 | .dw $FF8C 123 | .dw $FF90 124 | .dw $FF94 125 | .dw $FF98 126 | .dw $FF9B 127 | .dw $FF9F 128 | .dw $FFA3 129 | .dw $FFA7 130 | .dw $FFAA 131 | .dw $FFAE 132 | .dw $FFB2 133 | .dw $FFB5 134 | .dw $FFB9 135 | .dw $FFBC 136 | .dw $FFC0 137 | .dw $FFC3 138 | .dw $FFC6 139 | .dw $FFCA 140 | .dw $FFCD 141 | .dw $FFD0 142 | .dw $FFD4 143 | .dw $FFD7 144 | .dw $FFDA 145 | .dw $FFDD 146 | .dw $FFE0 147 | .dw $FFE4 148 | .dw $FFE7 149 | .dw $FFEA 150 | .dw $FFED 151 | .dw $FFF0 152 | .dw $FFF3 153 | .dw $FFF6 154 | .dw $FFF9 155 | .dw $FFFC 156 | .dw $FFFF 157 | -------------------------------------------------------------------------------- /gfx/circle.z80: -------------------------------------------------------------------------------- 1 | ;Written by Zeda Thomas, free to use. 2 | 3 | ;This draws a circle centered at 8-bit coordinates and with radius up to 127. 4 | ;IX points to a `plot` routine that takes (B,C)=(x,y) as input and does something 5 | ;with it, like plot the pixel a certain color, or plot a "big" pixel, or whatever. 6 | ; plot 7 | ; Takes coordinates, (B,C) = (x,y) and plots the point. 8 | ; 9 | ;For example, on the TI-83+/84+/SE the plot routine might look like: 10 | ; plot: 11 | ; call getpixelloc 12 | ; ret nc ;Exit if the coordinates are out-of-bounds 13 | ; or (hl) 14 | ; ld (hl),a 15 | ; ret 16 | ; 17 | ; 18 | ; Required subroutines: 19 | ; call_ix: 20 | ; jp (ix) 21 | 22 | circle: 23 | ;Input: 24 | ; (B,C) is the center (x,y) 25 | ; D is the radius, unsigned, less than 128 (0 or greater than 128 just quits). 26 | ; IX points to a `plot` routine that takes (B,C)=(x,y) as input. 27 | ld a,d 28 | add a,a 29 | ret c 30 | ret z 31 | ld l,d 32 | dec a 33 | ld e,a 34 | dec a ;if the pixel is only 1 wide, just plot the point 35 | jp z,call_ix ;Jump to the plot routine 36 | xor a 37 | ld h,-1 38 | ld d,1 39 | scf ;skip the first plot 40 | circleloop: 41 | call nc,plot4 42 | inc h 43 | sub d 44 | inc d 45 | inc d 46 | jr nc,circleloop 47 | _: 48 | dec l 49 | call plot4 50 | add a,e 51 | dec e 52 | ret z 53 | dec e 54 | jr nc,-_ 55 | jp circleloop 56 | 57 | 58 | plot4: 59 | ;BC is center 60 | ;HL is x,y 61 | 62 | push de 63 | push af 64 | push hl 65 | push bc 66 | 67 | ;If H is 0, or L is 0, we need to draw only half 68 | push hl 69 | 70 | ld a,b 71 | sub h 72 | ld b,a 73 | add a,h 74 | add a,h 75 | ld h,a 76 | 77 | ld a,c 78 | sub l 79 | ld c,a 80 | add a,l 81 | add a,l 82 | ld l,a 83 | 84 | ;B is x0-x 85 | ;C is y0-y 86 | ;H is x0+x 87 | ;L is y0+y 88 | 89 | 90 | ;plot(x0-x,y0-y) 91 | ;plot(x0+x,y0+y) 92 | push bc 93 | push hl 94 | call call_ix ;call the plot routine 95 | pop bc 96 | push bc 97 | call call_ix ;call the plot routine 98 | 99 | ;now swap the y coords 100 | pop hl 101 | pop bc 102 | ld a,l 103 | ld l,c 104 | ld c,a 105 | pop de 106 | xor a 107 | cp d 108 | jr z,+_ 109 | cp e 110 | jr z,+_ 111 | 112 | 113 | ;plot(x0-x,y0+y) 114 | ;plot(x0+x,y0-y) 115 | push hl 116 | call call_ix ;call the plot routine 117 | pop bc 118 | call call_ix ;call the plot routine 119 | _: 120 | 121 | pop bc 122 | pop hl 123 | pop af 124 | pop de 125 | ret 126 | --------------------------------------------------------------------------------