; See the end of this source for the original author's comments ; Right - straight in with a multipass source. ; This does two multipasses, one to generate the compressed tape data and ; another one to generate the uncompressed tape data. multipass 2 ; Do two multipasses... (0 and 1) ; Some idiot is bound to look at "multipass 2" and think "Oh. Zeus is a two pass assembler"... don't be that idiot. ; Multipasses are in addition to all the normal passes that Zeus does as required when assembling. ; Other assemblers don't have the facility to do multipass operation at all. ; Now, let's use it... let's assemble this source twice, once with compressed data for tape and once without. bCompressForTape equ multipass = 0 ; Generate a compressed file on the first multipass ; Is that clear? "bCompressForTape" will be true on the first multipass because the multipass pseudo-op will return a value of zero. ; On any subsequent multipass it will be false. We then use this boolean value at the end to decide what to do. ; Anyway, on with the test code - I have decided to run all the test code above $8000 in uncontested memory org $8000 ; Faster up here Entry jp Start ; Don't remove this jump ; Machine state before test (needs to be located at address $8003) ; If you move this you'll have to change several of the CRC values to suit the new results. ; Why do they change? Because moving this changes the register values in instructions that ; point at this workspace, and the CRC values are calculated from those register values. msbt: dw 0 ; memop dw 0 ; IY dw 0 ; IX dw 0 ; HL dw 0 ; DE dw 0 ; BC db 0 ; Flags db 0 ; A spbt: dw 0 ; SP before inst ; These bytes are referenced (urgh) because the original code is buggy. See CPDR. db $2A,$06,$00,$F9 ; Part of the original CP/M code. ; We start here. Start ld sp,$0000 ; Somewhere safe di ; Stop the damned ROM screwing us about ld a,cCls ; Clear the screen call Print ; ld a,cWhite ; Show the first in white call Print ; ld hl,tests ; first test case TstLp ld a,(hl) ; end of list ? inc hl ; or (hl) ; jp z,done ; Yep, done dec hl ; Not at the end, rewind call stt ; Test using this definition jp TstLp ; Loop done ld de,szDone ; End message call PrintSZ_DE ; ; Just sit here doing nothing. stop jp stop ; wait for reset ; The table of test vectors. tests dw inca ; dw incb ; dw incbc ; dw incc ; dw incd ; dw incde ; dw ince ; dw inch ; dw inchl ; dw incix ; dw inciy ; dw incl ; dw incm ; dw incsp ; dw incx ; dw incxh ; dw incxl ; dw incyh ; dw incyl ; dw ld161 ; dw ld162 ; dw ld163 ; dw ld164 ; dw ld165 ; dw ld166 ; dw ld167 ; dw ld168 ; dw ld16im ; dw ld16ix ; dw ld8bd ; dw ld8im ; dw ld8imx ; dw ld8ix1 ; dw ld8ix2 ; dw ld8ix3 ; dw ld8ixy ; dw ld8rr ; dw ld8rrx ; dw lda ; dw ldd1 ; dw ldd2 ; dw ldi1 ; dw ldi2 ; dw negop ; dw rldop ; dw rot8080 ; dw rotxy ; dw rotz80 ; dw srz80 ; dw srzx ; dw st8ix1 ; dw st8ix2 ; dw st8ix3 ; dw stabd ; dw adc16 ; dw add16 ; dw add16x ; dw add16y ; ; This set get slow dw alu8i ; dw alu8r ; dw alu8rx ; dw alu8x ; dw bitx ; dw cpd1 ; dw cpi1 ; dw daaop ; dw bitz80 ; dw 0 ; A macro for defining the test table format. mTest macro(insn1,insn2,insn3,insn4,memop,riy,rix,rhl,rde,rbc,flags,acc,rsp) db insn1,insn2,insn3,insn4 dw memop,riy,rix,rhl,rde,rbc db flags db acc dw rsp mend ; I really should get rid of this hideously formatted hex numbers - the syntax highlighter hates them (they look like duff floating point decimals) ; hl, (38,912 cycles) adc16: db 0ffh ; flag mask mTest( 0edh,042h,0,0,0832ch,04f88h,0f22bh,0b339h,07e1fh,01563h,0d3h,089h,0465eh) mTest( 0,038h,0,0,0,0,0,0f821h,0,0,0,0,0) ; (1024 cycles) mTest( 0,0,0,0,0,0,0,-1,-1,-1,0d7h,0,-1) ; (38 cycles) db 0d4h,08ah,0d5h,019h ; expected crc db " hl,",0 ; add hl, (19,456 cycles) add16: db 0ffh ; flag mask mTest( 9,0,0,0,0c4a5h,0c4c7h,0d226h,0a050h,058eah,08566h,0c6h,0deh,09bc9h) mTest( 030h,0,0,0,0,0,0,0f821h,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,-1,-1,-1,0d7h,0,-1) ; (38 cycles) db 0d9h,0a4h,0cah,005h ; expected crc db "add hl,",0 ; add ix, (19,456 cycles) add16x: db 0ffh ; flag mask mTest( 0ddh,9,0,0,0ddach,0c294h,0635bh,033d3h,06a76h,0fa20h,094h,068h,036f5h) mTest( 0,030h,0,0,0,0,0f821h,0,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,-1,0,-1,-1,0d7h,0,-1) ; (38 cycles) db 0b1h,0dfh,08eh,0c0h ; expected crc db "add ix,",0 ; add iy, (19,456 cycles) add16y: db 0ffh ; flag mask mTest( 0fdh,9,0,0,0c7c2h,0f407h,051c1h,03e96h,00bf4h,0510fh,092h,01eh,071eah) mTest( 0,030h,0,0,0,0f821h,0,0,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,-1,0,0,-1,-1,0d7h,0,-1) ; (38 cycles) db 039h,0c8h,058h,09bh ; expected crc db "add iy,",0 ; aluop a,nn (28,672 cycles) alu8i: db 0ffh ; flag mask mTest( 0c6h,0,0,0,009140h,07e3ch,07a67h,0df6dh,05b61h,00b29h,010h,066h,085b2h) mTest( 038h,0,0 ,0,0,0,0,0,0,0,0,-1,0) ; (2048 cycles) mTest( 0,-1,0,0,0,0,0,0,0,0,0d7h,0,0) ; (14 cycles) db 051h,0c1h,09ch,02eh ; expected crc db "aluop a,nn",0 ; aluop a, (753,664 cycles) alu8r: db 0ffh ; flag mask mTest( 080h,0,0,0,0c53eh,0573ah,04c4dh,msbt,0e309h,0a666h,0d0h,03bh,0adbbh) mTest( 03fh,0,0,0,0,0,0,0,0,0,0,-1,0) ; (16,384 cycles) mTest( 0,0,0,0,0ffh,0,0,0,-1,-1,0d7h,0,0) ; (46 cycles) ; db 006h,0c7h,0aah,08eh ; expected crc running at $0100 db $1D,$FD,$78,$64 ; expected crc running at $8000 db "aluop a,",0 ; aluop a, (376,832 cycles) alu8rx: db 0ffh ; flag mask mTest( 0ddh,084h,0,0,0d6f7h,0c76eh,0accfh,02847h,022ddh,0c035h,0c5h,038h,0234bh) mTest( 020h,039h,0,0,0,0,0,0,0,0,0,-1,0) ; (8,192 cycles) mTest( 0,0,0,0,0ffh,0,0,0,-1,-1,0d7h,0,0) ; (46 cycles) db 0a8h,086h,0cch,044h ; expected crc db "aluop a,",0 ; aluop a,(+1) (229,376 cycles) alu8x: db 0ffh ; flag mask mTest( 0ddh,086h,1,0,090b7h,msbt-1,msbt-1,032fdh,0406eh,0c1dch,045h,06eh,0e5fah) mTest( 020h,038h,0,0,0,1,1,0,0,0,0,-1,0) ; (16,384 cycles) mTest( 0,0,0,0,0ffh,0,0,0,0,0,0d7h,0,0) ; (14 cycles) ; db 0d3h,0f2h,0d7h,04ah ; expected crc running at $0100 db $52,$18,$5E,$A5 ; expected crc running at $8000 db "aluop a,(+1)",0 ; bit n,(+1) (2048 cycles) bitx: db 0ffh ; flag mask mTest( 0ddh,0cbh,1,046h,02075h,msbt-1,msbt-1,03cfch,0a79ah,03d74h,051h,027h,0ca14h) mTest( 020h,0,0,038h,0,0,0,0,0,0,053h,0,0) ; (256 cycles) mTest( 0,0,0,0,0ffh,0,0,0,0,0,0,0,0) ; (8 cycles) ; db 083h,053h,04eh,0e1h ; expected crc running at $0100 db $E1,$D4,$A8,$96 ; expected crc running at $8000 db "bit n,(+1)",0 ; bit n, (49,152 cycles) bitz80: db 0FFh ; flag mask mTest( 0cbh,040h,0,0,03ef1h,09dfch,07acch,msbt,0be61h,07a86h,050h,024h,01998h) mTest( 0,03Fh,0,0,0,0,0,0,0,0,053h,0,0) ; (1024 cycles) mTest( 0,0,0,0,0ffh,0,0,0,-1,-1,0,-1,0) ; (48 cycles) ; db 05eh,002h,00eh,098h ; expected crc running at $0100 db $F5,$54,$D7,$42 ; expected crc running at $8000 [Spectaculator value] db "bit n,",0 ; cpd (1) (6144 cycles) - NOTE this has a bug, the "msbt+17" refers to byte outside the test code cpd1: db 0ffh ; flag mask mTest( 0edh,0a9h,0,0, 0c7b6h,072b4h,018f6h,msbt+17,08dbdh, 1,0c0h,030h,094a3h) mTest( 0, 010h,0,0, 0, 0, 0, 0, 0, 8, 0, -1, 0) ; (1024 cycles) mTest( 0,0,0,0, 0, 0, 0, 0, 0, 0,0d7h, 0, 0) ; (6 cycles) ; db 013h,04bh,062h,02dh ; expected crc running at $0100 db $7A,$8E,$6C,$E1 ; expected crc running at $8000 db "cpd",0 ; cpi (1) (6144 cycles) cpi1: db 0ffh ; flag mask mTest( 0edh,0a1h,0,0,04d48h,0af4ah,0906bh,msbt,04e71h,1,093h,06ah,0907ch) mTest( 0,010h,0,0,0,0,0,0,0,8,0,-1,0) ; (1024 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) ; db 02dh,0a4h,02dh,019h ; expected crc running at $0100 db $C2,$71,$47,$40 ; expected crc running at $8000 db "cpi",0 ; daaop: db 0ffh ; flag mask mTest( 027h,0,0,0,02141h,009fah,01d60h,0a559h,08d5bh,09079h,004h,08eh,0299dh) mTest( 018h,0,0,0,0,0,0,0,0,0,0d7h,-1,0) ; (65,536 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0,0,0) ; (1 cycle) db 06dh,02dh,0d2h,013h ; expected crc db "",0 ; a (3072 cycles) inca: db 0ffh ; flag mask mTest( 03ch,0,0,0,04adfh,0d5d8h,0e598h,08a2bh,0a7b0h,0431bh,044h,05ah,0d030h) mTest( 001h,0,0,0,0,0,0,0,0,0,0,-1,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 081h,0fah,081h,000h ; expected crc db " a",0 ; b (3072 cycles) incb: db 0ffh ; flag mask mTest( 004h,0,0,0,0d623h,0432dh,07a61h,08180h,05a86h,01e85h,086h,058h,09bbbh) mTest( 001h,0,0,0,0,0,0,0,0,0ff00h,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 077h,0f3h,05ah,073h ; expected crc db " b",0 ; bc (1536 cycles) incbc: db 0ffh ; flag mask mTest( 003h,0,0,0,0cd97h,044abh,08dc9h,0e3e3h,011cch,0e8a4h,002h,049h,02a4dh) mTest( 008h,0,0,0,0,0,0,0,0,0f821h,0,0,0) ; (256 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 0d2h,0aeh,03bh,0ech ; expected crc db " bc",0 ; c (3072 cycles) incc: db 0ffh ; flag mask mTest( 00ch,0,0,0,0d789h,00935h,0055bh,09f85h,08b27h,0d208h,095h,005h,00660h) mTest( 001h,0,0,0,0,0,0,0,0,0ffh,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 01ah,0f6h,012h,0a7h ; expected crc db " c",0 ; d (3072 cycles) incd: db 0ffh ; flag mask mTest( 014h,0,0,0,0a0eah,05fbah,065fbh,0981ch,038cch,0debch,043h,05ch,003bdh) mTest( 001h,0,0,0,0,0,0,0,0ff00h,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 0d1h,046h,0bfh,051h ; expected crc db " d",0 ; de (1536 cycles) incde: db 0ffh ; flag mask mTest( 013h,0,0,0,0342eh,0131dh,028c9h,00acah,09967h,03a2eh,092h,0f6h,09d54h) mTest( 008h,0,0,0,0,0,0,0,0f821h,0,0,0,0) ; (256 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 0aeh,0c6h,0d4h,02ch ; expected crc db " de",0 ; e (3072 cycles) ince: db 0ffh ; flag mask mTest( 01ch,0,0,0,0602fh,04c0dh,02402h,0e2f5h,0a0f4h,0a10ah,013h,032h,05925h) mTest( 001h,0,0,0,0,0,0,0,0ffh,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 0cah,08ch,06ah,0c2h ; expected crc db " e",0 ; h (3072 cycles) inch: db 0ffh ; flag mask mTest( 024h,0,0,0,01506h,0f2ebh,0e8ddh,0262bh,011a6h,0bc1ah,017h,006h,02818h) mTest( 001h,0,0,0,0,0,0,0ff00h,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 056h,00fh,095h,05eh ; expected crc db " h",0 ; hl (1536 cycles) inchl: db 0ffh ; flag mask mTest( 023h,0,0,0,0c3f4h,007a5h,01b6dh,04f04h,0e2c2h,0822ah,057h,0e0h,0c3e1h) mTest( 008h,0,0,0,0,0,0,0f821h,0,0,0,0,0) ; (256 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 0fch,00dh,06dh,04ah ; expected crc db " hl",0 ; ix (1536 cycles) incix: db 0ffh ; flag mask mTest( 0ddh,023h,0,0,0bc3ch,00d9bh,0e081h,0adfdh,09a7fh,096e5h,013h,085h,00be2h) mTest( 0,8,0,0,0,0,0f821h,0,0,0,0,0,0) ; (256 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 0a5h,04dh,0beh,031h ; expected crc db " ix",0 ; iy (1536 cycles) inciy: db 0ffh ; flag mask mTest( 0fdh,023h,0,0,09402h,0637ah,03182h,0c65ah,0b2e9h,0abb4h,016h,0f2h,06d05h) mTest( 0,8,0,0,0,0f821h,0,0,0,0,0,0,0) ; (256 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 050h,05dh,051h,0a3h ; expected crc db " iy",0 ; l (3072 cycles) incl: db 0ffh ; flag mask mTest( 02ch,0,0,0,08031h,0a520h,04356h,0b409h,0f4c1h,0dfa2h,0d1h,03ch,03ea2h) mTest( 001h,0,0,0,0,0,0,0ffh,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 0a0h,0a1h,0b4h,09fh ; expected crc db " l",0 ; (hl) (3072 cycles) incm: db 0ffh ; flag mask mTest( 034h,0,0,0,0b856h,00c7ch,0e53eh,msbt,0877eh,0da58h,015h,05ch,01f37h) mTest( 001h,0,0,0, 0ffh, 0, 0, 0, 0, 0, 0, 0, 0) ; (512 cycles) mTest( 0, 0,0,0, 0, 0, 0, 0, 0, 0, 0d7h, 0, 0) ; (6 cycles) ; db 028h,029h,05eh,0ceh ; expected crc running at $0100 db $1C,$A0,$EC,$E9 ; expected crc running at $8000 db " (hl)",0 ; sp (1536 cycles) incsp: db 0ffh ; flag mask mTest( 033h,0,0,0,0346fh,0d482h,0d169h,0deb6h,0a494h,0f476h,053h,002h,0855bh) mTest( 008h,0,0,0,0,0,0,0,0,0,0,0,0f821h) ; (256 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 05dh,0ach,0d5h,027h ; expected crc db " sp",0 ; (+1) (6144 cycles) incx: db 0ffh ; flag mask mTest( 0ddh,034h,1,0,0fa6eh,msbt-1,msbt-1,02c28h,08894h,05057h,016h,033h,0286fh) mTest( 020h,1,0,0,0ffh,0,0,0,0,0,0,0,0) ; (1024 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) ; db 00bh,095h,0a8h,0eah ; expected crc running at $0100 db $FF,$60,$16,$65 ; expected crc running at $8000 db " (+1)",0 ; ixh (3072 cycles) incxh: db 0ffh ; flag mask mTest( 0ddh,024h,0,0,0b838h,0316ch,0c6d4h,03e01h,08358h,015b4h,081h,0deh,04259h) mTest( 0,1,0,0,0,0ff00h,0,0,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 06fh,046h,036h,062h ; expected crc db " ixh",0 ; ixl (3072 cycles) incxl: db 0ffh ; flag mask mTest( 0ddh,02ch,0,0,04d14h,07460h,076d4h,006e7h,032a2h,0213ch,0d6h,0d7h,099a5h) mTest( 0,1,0,0,0,0ffh,0,0,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 002h,07bh,0efh,02ch ; expected crc db " ixl",0 ; iyh (3072 cycles) incyh: db 0ffh ; flag mask mTest( 0ddh,024h,0,0,02836h,09f6fh,09116h,061b9h,082cbh,0e219h,092h,073h,0a98ch) mTest( 0,1,0,0,0ff00h,0,0,0,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 02dh,096h,06ch,0f3h ; expected crc db " iyh",0 ; iyl (3072 cycles) incyl: db 0ffh ; flag mask mTest( 0ddh,02ch,0,0,0d7c6h,062d5h,0a09eh,07039h,03e7eh,09f12h,090h,0d9h,0220fh) mTest( 0,1,0,0,0ffh,0,0,0,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 036h,0c1h,01eh,075h ; expected crc db " iyl",0 ; ld ,(nnnn) (32 cycles) ld161: db 0ffh ; flag mask mTest( 0edh,04bh,low msbt,high msbt,0f9a8h,0f559h,093a4h,0f5edh,06f96h,0d968h,086h,0e6h,04bd8h) mTest( 0,010h,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0,0,0) ; (16 cycles) db 04dh,045h,0a9h,0ach ; expected crc db "ld ,(nnnn)",0 ; ld hl,(nnnn) (16 cycles) ld162: db 0ffh ; flag mask mTest( 02ah,low msbt,high msbt,0,09863h,07830h,02077h,0b1feh,0b9fah,0abb8h,004h,006h,06015h) mTest( 0,0,0,0,0,0,0,0,0,0,0,0,0) ; (1 cycle) mTest( 0,0,0,0,-1,0,0,0,0,0,0,0,0) ; (16 cycles) db 05fh,097h,024h,087h ; expected crc db "ld hl,(nnnn)",0 ; ld sp,(nnnn) (16 cycles) ld163: db 0ffh ; flag mask mTest( 0edh,07bh,low msbt,high msbt,08dfch,057d7h,02161h,0ca18h,0c185h,027dah,083h,01eh,0f460h) mTest( 0,0,0,0,0,0,0,0,0,0,0,0,0) ; (1 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0,0,0) ; (16 cycles) db 07ah,0ceh,0a1h,01bh ; expected crc db "ld sp,(nnnn)",0 ; ld ,(nnnn) (32 cycles) ld164: db 0ffh ; flag mask mTest( 0ddh,02ah,low msbt,high msbt,0ded7h,0a6fah,0f780h,0244ch,087deh,0bcc2h,016h,063h,04c96h) mTest( 020h,0,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0,0,0) ; (16 cycles) db 085h,08bh,0f1h,06dh ; expected crc db "ld ,(nnnn)",0 ; ld (nnnn), (64 cycles) ld165: db 0ffh ; flag mask mTest( 0edh,043h,low msbt,high msbt,01f98h,0844dh,0e8ach,0c9edh,0c95dh,08f61h,080h,03fh,0c7bfh) mTest( 0,010h,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,0,0,0,0,-1,-1,0,0,0) ; (32 cycles) db 064h,01eh,087h,015h ; expected crc db "ld (nnnn),",0 ; ld (nnnn),hl (16 cycles) ld166: db 0ffh ; flag mask mTest( 022h,low msbt,high msbt,0,0d003h,07772h,07f53h,03f72h,064eah,0e180h,010h,02dh,035e9h) mTest( 0,0,0,0,0,0,0,0,0,0,0,0,0) ; (1 cycle) mTest( 0,0,0,0,0,0,0,-1,0,0,0,0,0) ; (16 cycles) db 0a3h,060h,08bh,047h ; expected crc db "ld (nnnn),hl",0 ; ld (nnnn),sp (16 cycles) ld167: db 0ffh ; flag mask mTest( 0edh,073h,low msbt,high msbt,0c0dch,0d1d6h,0ed5ah,0f356h,0afdah,06ca7h,044h,09fh,03f0ah) mTest( 0,0,0,0,0,0,0,0,0,0,0,0,0) ; (1 cycle) mTest( 0,0,0,0,0,0,0,0,0,0,0,0,-1) ; (16 cycles) db 016h,058h,05fh,0d7h ; expected crc db "ld (nnnn),sp",0 ; ld (nnnn), (64 cycles) %%%% ld168: db 0ffh ; flag mask mTest( 0ddh,022h,low msbt,high msbt,06cc3h,00d91h,06900h,08ef8h,0e3d6h,0c3f7h,0c6h,0d9h,0c2dfh) mTest( 020h, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ; (2 cycles) mTest( 0, 0, 0, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0) ; (32 cycles) db 0bah,010h,02ah,06bh ; expected crc db "ld (nnnn),",0 ; ld ,nnnn (64 cycles) ld16im: db 0ffh ; flag mask mTest( 1,0,0,0,05c1ch,02d46h,08eb9h,06078h,074b1h,0b30eh,046h,0d1h,030cch) mTest( 030h,0,0,0,0,0,0,0,0,0,0,0,0) ; (4 cycles) mTest( 0,0ffh,0ffh,0,0,0,0,0,0,0,0,0,0) ; (16 cycles) db 0deh,039h,019h,069h ; expected crc db "ld ,nnnn",0 ; ld ,nnnn (32 cycles) ld16ix: db 0ffh ; flag mask mTest( 0ddh,021h,0,0,087e8h,02006h,0bd12h,0b69bh,07253h,0a1e5h,051h,013h,0f1bdh) mTest( 020h,0,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0ffh,0ffh,0,0,0,0,0,0,0,0,0) ; (16 cycles) db 022h,07dh,0d5h,025h ; expected crc db "ld ,nnnn",0 ; ld a,<(bc),(de)> (44 cycles) ld8bd: db 0ffh ; flag mask mTest( 00ah,0,0,0,0b3a8h,01d2ah,07f8eh,042ach,msbt,msbt,0c6h,0b1h,0ef8eh) mTest( 010h,0,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,0ffh,0,0,0,0,0,0d7h,-1,0) ; (22 cycles) ; db 0b0h,081h,089h,035h ; expected crc running at $0100 db $3B,$C6,$6A,$71 ; expected crc running at $8000 db "ld a,<(bc),(de)>",0 ; ld ,nn (64 cycles) ld8im: db 0ffh ; flag mask mTest( 6,0,0,0,0c407h,0f49dh,0d13dh,00339h,0de89h,07455h,053h,0c0h,05509h) mTest( 038h,0,0,0,0,0,0,0,0,0,0,0,0) ; (8 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0,-1,0) ; (8 cycles) db 0f1h,0dah,0b5h,056h ; expected crc db "ld ,nn",0 ; ld (+1),nn (32 cycles) ld8imx: db 0ffh ; flag mask mTest( 0ddh,036h,1,0,01b45h,msbt-1,msbt-1,0d5c1h,061c7h,0bdc4h,0c0h,085h,0cd16h) mTest( 020h,0,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,-1,0,0,0,0,0,0,0,-1,0) ; (16 cycles) ; db 026h,0dbh,047h,07eh ; expected crc running at $0100 db $E8,$0C,$FF,$11 ; expected crc running at $8000 db "ld (+1),nn",0 ; ld ,(+1) (512 cycles) ld8ix1: db 0ffh ; flag mask mTest( 0ddh,046h,1,0,0d016h,msbt-1,msbt-1,04260h,07f39h,00404h,097h,04ah,0d085h) mTest( 020h,018h,0,0,0,1,1,0,0,0,0,0,0) ; (32 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0,0,0) ; (16 cycles) ; db 0cch,011h,006h,0a8h ; expected crc running at $0100 db $36,$0F,$01,$82 ; expected crc running at $8000 db "ld ,(+1)",0 ; ld ,(+1) (256 cycles) ld8ix2: db 0ffh ; flag mask mTest( 0ddh,066h,1,0,084e0h,msbt-1,msbt-1,09c52h,0a799h,049b6h,093h,000h,0eeadh) mTest( 020h,008h,0,0,0,1,1,0,0,0,0,0,0) ; (16 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0,0,0) ; (16 cycles) ; db 0fah,02ah,04dh,003h ; expected crc running at $0100 db $B7,$BA,$0C,$9C ; expected crc running at $8000 db "ld ,(+1)",0 ; ld a,(+1) (128 cycles) ld8ix3: db 0ffh ; flag mask mTest( 0ddh,07eh,1,0,0d8b6h,msbt-1,msbt-1,0c612h,0df07h,09cd0h,043h,0a6h,0a0e5h) mTest( 020h,0,0,0,0,1,1,0,0,0,0,0,0) ; (8 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0,0,0) ; (16 cycles) ; db 0a5h,0e9h,0ach,064h ; expected crc running at $0100 db $E7,$5A,$1E,$63 ; expected crc running at $8000 db "ld a,(+1)",0 ; ld ,nn (32 cycles) ld8ixy: db 0ffh ; flag mask mTest( 0ddh,026h,0,0,03c53h,04640h,0e179h,07711h,0c107h,01afah,081h,0adh,05d9bh) mTest( 020h,8,0,0,0,0,0,0,0,0,0,0,0) ; (4 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0,-1,0) ; (8 cycles) db 024h,0e8h,082h,08bh ; expected crc db "ld ,nn",0 ; ld , (3456 cycles) ld8rr: db 0ffh ; flag mask iy ix hl de bc f a sp mTest( 040h,0,0,0,072a4h,0a024h,061ach,msbt,082c7h,0718fh,097h,08fh,0ef8eh) mTest( 03fh,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ; (64 cycles) mTest( 0,0,0,0, 0ffh, 0, 0, 0, -1, -1, 0d7h, -1, 0) ; (54 cycles) ; db 074h,04bh,001h,018h ; expected crc running at $0100 db $43,$75,$89,$BE ; expected crc running at $8000 db "ld ,",0 ; ld , (6912 cycles) ld8rrx: db 0ffh ; flag mask mTest( 0ddh,040h,0,0,0bcc5h,msbt,msbt,msbt,02fc2h,098c0h,083h,01fh,03bcdh) mTest( 020h,03fh,0,0,0,0,0,0,0,0,0,0,0) ; (128 cycles) mTest( 0,0,0,0,0ffh,0,0,0,-1,-1,0d7h,-1,0) ; (54 cycles) ; db 047h,08bh,0a3h,06bh ; expected crc running at $0100 db $F1,$63,$AE,$1A ; expected crc running at $8000 db "ld ,",0 ; ld a,(nnnn) / ld (nnnn),a (44 cycles) lda: db 0ffh ; flag mask mTest( 032h,low msbt,high msbt,0,0fd68h,0f4ech,044a0h,0b543h,00653h,0cdbah,0d2h,04fh,01fd8h) mTest( 008h,0,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycle) mTest( 0,0,0,0,0ffh,0,0,0,0,0,0d7h,-1,0) ; (22 cycles) db 0c9h,026h,02dh,0e5h ; expected crc db "ld a,(nnnn) / ld (nnnn),a",0 ; ldd (1) (44 cycles) ldd1: db 0ffh ; flag mask mTest( 0edh,0a8h,0,0,09852h,068fah,066a1h,msbt+3,msbt+1,1,0c1h,068h,020b7h) mTest( 0,010h,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0d7h,0,0) ; (22 cycles) ; db 094h,0f4h,027h,069h ; expected crc running at $0100 db $39,$E2,$95,$ED ; expected crc running at $8000 db "ldd (1)",0 ; ldd (2) (44 cycles) ldd2: db 0ffh ; flag mask mTest( 0edh,0a8h,0,0,0f12eh,0eb2ah,0d5bah,msbt+3,msbt+1,2,047h,0ffh,0fbe4h) mTest( 0,010h,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0d7h,0,0) ; (22 cycles) ; db 039h,0ddh,03dh,0e1h ; expected crc running at $0100 db $94,$CB,$8F,$65 ; expected crc running at $8000 db "ldd (2)",0 ; ldi (1) (44 cycles) ldi1: db 0ffh ; flag mask mTest( 0edh,0a0h,0,0,0fe30h,003cdh,06058h,msbt+2,msbt,1,004h,060h,02688h) mTest( 0,010h,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0d7h,0,0) ; (22 cycles) ; db 0f7h,082h,0b0h,0d1h ; expected crc running at $0100 db $5A,$94,$02,$55 ; expected crc running at $8000 db "ldi (1)",0 ; ldi (2) (44 cycles) ldi2: db 0ffh ; flag mask mTest( 0edh,0a0h,0,0,04aceh,0c26eh,0b188h,msbt+2,msbt,2,014h,02dh,0a39fh) mTest( 0,010h,0,0,0,0,0,0,0,0,0,0,0) ; (2 cycles) mTest( 0,0,0,0,-1,0,0,0,0,0,0d7h,0,0) ; (22 cycles) ; db 0e9h,0eah,0d0h,0aeh ; expected crc running at $0100 db $44,$FC,$62,$2A ; expected crc running at $8000 db "ldi (2)",0 ; neg (16,384 cycles) negop: db 0ffh ; flag mask mTest( 0edh,044h,0,0,038a2h,05f6bh,0d934h,057e4h,0d2d6h,04642h,043h,05ah,009cch) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,-1,0) ; (16,384 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0,0,0) ; (1 cycle) db 0d6h,038h,0ddh,06ah ; expected crc db "neg",0 ; (7168 cycles) rldop: db 0ffh ; flag mask mTest( 0edh,067h,0,0,091cbh,0c48bh,0fa62h,msbt,0e720h,0b479h,040h,006h,08ae2h) mTest( 0,8,0,0,0ffh,0,0,0,0,0,0,0,0) ; (512 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,-1,0) ; (14 cycles) ; db 0ffh,082h,03eh,077h ; expected crc running at $0100 db $1B,$BC,$05,$51 ; expected crc running at $8000 db "",0 ; (6144 cycles) rot8080: db 0ffh ; flag mask mTest( 7,0,0,0,0cb92h,06d43h,00a90h,0c284h,00c53h,0f50eh,091h,0ebh,040fch) mTest( 018h,0,0,0,0,0,0,0,0,0,0,-1,0) ; (1024 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0d7h,0,0) ; (6 cycles) db 09bh,0a3h,080h,07ch ; expected crc db "",0 ; shift/rotate (+1) (416 cycles) rotxy: db 0ffh ; flag mask mTest( 0ddh,0cbh,1,6,0ddafh,msbt-1,msbt-1,0ff3ch,0dbf6h,094f4h,082h,080h,061d9h) mTest( 020h,0,0,038h,0,0,0,0,0,0,080h,0,0) ; (32 cycles) mTest( 0,0,0,0,0ffh,0,0,0,0,0,057h,0,0) ; (13 cycles) ; db 071h,000h,034h,0cbh ; expected crc running at $0100 db $4C,$06,$53,$F1 ; expected crc running at $8000 db "shf/rot (+1)",0 ; shift/rotate (6784 cycles) rotz80: db 0ffh ; flag mask mTest( 0cbh,0,0,0,0ccebh,05d4ah,0e007h,msbt,01395h,030eeh,043h,078h,03dadh) mTest( 0,03fh,0,0,0,0,0,0,0,0,080h,0,0) ; (128 cycles) mTest( 0,0,0,0,0ffh,0,0,0,-1,-1,057h,-1,0) ; (53 cycles) ; db 0a4h,025h,058h,033h ; expected crc running at $0100 db $36,$BC,$1F,$C3 ; expected crc running at $8000 db "shf/rot ",0 ; n, (7936 cycles) srz80: db 0ffh ; flag mask mTest( 0cbh,080h,0,0,02cd5h,097abh,039ffh,msbt,0d14bh,06ab2h,053h,027h,0b538h) mTest( 0,07fh,0,0,0,0,0,0,0,0,0,0,0) ; (128 cycles) mTest( 0,0,0,0,0ffh,0,0,0,-1,-1,0d7h,-1,0) ; (62 cycles) ; db 08bh,057h,0f0h,008h ; expected crc running at $0100 db $77,$5E,$89,$75 ; expected crc running at $8000 db " n,",0 ; n,(+1) (1792 cycles) srzx: db 0ffh ; flag mask mTest( 0ddh,0cbh,1,086h,0fb44h,msbt-1,msbt-1,0ba09h,068beh,032d8h,010h,05eh,0a867h) mTest( 020h,0,0,078h,0,0,0,0,0,0,0,0,0) ; (128 cycles) mTest( 0,0,0,0,0ffh,0,0,0,0,0,0d7h,0,0) ;(14 cycles) ; db 0cch,063h,0f9h,08ah ; expected crc running at $0100 db $FA,$9F,$51,$D4 ; expected crc running at $8000 db " n,(+1)",0 ; ld (+1), (1024 cycles) st8ix1: db 0ffh ; flag mask mTest( 0ddh,070h,1,0,0270dh,msbt-1,msbt-1,0b73ah,0887bh,099eeh,086h,070h,0ca07h) mTest( 020h,003h,0,0,0,1,1,0,0,0,0,0,0) ; (32 cycles) mTest( 0,0,0,0,0,0,0,0,-1,-1,0,0,0) ; (32 cycles) ; db 004h,062h,06ah,0bfh ; expected crc running at $0100 db $DC,$96,$20,$25 ; expected crc running at $8000 db "ld (+1),",0 ; ld (+1), (256 cycles) st8ix2: db 0ffh ; flag mask mTest( 0ddh,074h,1,0,0b664h,msbt-1,msbt-1,0e8ach,0b5f5h,0aafeh,012h,010h,09566h) mTest( 020h,001h,0,0,0,1,1,0,0,0,0,0,0) ; (16 cycles) mTest( 0,0,0,0,0,0,0,-1,0,0,0,0,0) ; (32 cycles) ; db 06ah,01ah,088h,031h ; expected crc db $27,$8A,$C9,$AE ; expected crc running at $8000 db "ld (+1),",0 ; ld (+1),a (64 cycles) st8ix3: db 0ffh ; flag mask mTest( 0ddh,077h,1,0,067afh,msbt-1,msbt-1,04f13h,00644h,0bcd7h,050h,0ach,05fafh) mTest( 020h,0,0,0,0,1,1,0,0,0,0,0,0) ; (8 cycles) mTest( 0,0,0,0,0,0,0,0,0,0,0,-1,0) ; (8 cycles) ; db 0cch,0beh,05ah,096h ; expected crc running at $0100 db $D1,$02,$2A,$13 ; expected crc running at $8000 db "ld (+1),a",0 ; ld (),a (96 cycles) stabd: db 0ffh ; flag mask mTest( 2, 0,0,0, 00c3bh,0b592h,06cffh,0959eh,msbt,msbt+1,0c1h,021h,0bde7h) mTest( 018h,0,0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ; (4 cycles) mTest( 0,0,0,0, -1, 0, 0, 0, 0, 0, 0, -1, 0) ; (24 cycles) ; db 07ah,04ch,011h,04fh ; expected crc running at $0100 db $19,$CA,$ED,$2F ; expected crc running at $8000 db "ld (),a",0 ; Start test pointed to by (hl) stt push hl ld a,(hl) ; get pointer to test inc hl ld h,(hl) ld l,a ld a,(hl) ; flag mask ld (flgmsk+1),a inc hl push hl ld de,20 add hl,de ; point to incmask ld de,counter call initmask pop hl push hl ld de,20+20 add hl,de ; point to scanmask ld de,shifter call initmask ld hl,shifter ld (hl),1 ; first bit pop hl push hl ld de,iut ; copy initial instruction under test loop 4 ldi lend ld de,msbt ; copy initial machine state ld bc,16 ldir ld de,20+20+4 ; skip incmask, scanmask and expcrc add hl,de ex de,hl call PrintSZ_DE ; show test name call initcrc ; initialise crc ; test loop tlp: ld a,(iut) ; First instruction cp 076h ; pragmatically avoid halt intructions jp z,tlp2 ; Halt, ignore it and 0dfh ; IX or IY prefix? cp 0ddh ; jp nz,tlp1 ; No, skip and do it ld a,(iut+1) ; Second instruction halt? cp 076h ; tlp1: call nz,test ; execute the test instruction tlp2: call count ; increment the counter call nz,shift ; shift the scan bit pop hl ; pointer to test case jp z,tlp3 ; done if shift returned NZ ld de,20+20+20 add hl,de ; point to expected crc call cmpcrc ld de,szOk jp z,tlpok push hl ; save pointer to crc ld hl,crcval ld de,szErmsg1 ; jgh: swap crc= and expected= messages call PrintSZ_DE call phex8 ld de,szErmsg2 call PrintSZ_DE pop hl ; get pointer to crc back call phex8 ld de,szCr tlpok: call PrintSZ_DE pop hl inc hl inc hl ret tlp3: push hl ld a,1 ; initialise count and shift scanners ld (cntbit),a ld (shfbit),a ld hl,counter ld (cntbyt),hl ld hl,shifter ld (shfbyt),hl ld b,4 ; bytes in iut field pop hl ; pointer to test case push hl ld de,iut call setup ; setup iut ld b,16 ; bytes in machine state ld de,msbt call setup ; setup machine state jp tlp ; set up a field of the test case ; b = number of bytes ; hl = pointer to base case ; de = destination setup: call subyte inc hl dec b jp nz,setup ret subyte: push bc push de push hl ld c,(hl) ; get base byte ld de,20 add hl,de ; point to incmask ld a,(hl) cp 0 jp z,subshf ld b,8 ; 8 bits subclp: rrca push af ld a,0 call c,nxtcbit ; get next counter bit if mask bit was set xor c ; flip bit if counter bit was set rrca ld c,a pop af dec b jp nz,subclp ld b,8 subshf: ld de,20 add hl,de ; point to shift mask ld a,(hl) cp 0 jp z,substr ld b,8 ; 8 bits sbshf1: rrca push af ld a,0 call c,nxtsbit ; get next shifter bit if mask bit was set xor c ; flip bit if shifter bit was set rrca ld c,a pop af dec b jp nz,sbshf1 substr: pop hl pop de ld a,c ld (de),a ; mangled byte to destination inc de pop bc ret ; get next counter bit in low bit of a cntbit: ds 1 cntbyt: ds 2 nxtcbit: push bc push hl ld hl,(cntbyt) ld b,(hl) ld hl,cntbit ld a,(hl) ld c,a rlca ld (hl),a cp 1 jp nz,ncb1 ld hl,(cntbyt) inc hl ld (cntbyt),hl ncb1: ld a,b and c pop hl pop bc ret z ld a,1 ret ; get next shifter bit in low bit of a shfbit: ds 1 shfbyt: ds 2 nxtsbit: push bc push hl ld hl,(shfbyt) ld b,(hl) ld hl,shfbit ld a,(hl) ld c,a rlca ld (hl),a cp 1 jp nz,nsb1 ld hl,(shfbyt) inc hl ld (shfbyt),hl nsb1: ld a,b and c pop hl pop bc ret z ld a,1 ret ; clear memory at hl, bc bytes clrmem: push af push bc push de push hl ld (hl),0 ld d,h ld e,l inc de dec bc ldir pop hl pop de pop bc pop af ret ; initialise counter or shifter ; de = pointer to work area for counter or shifter ; hl = pointer to mask initmask: push de ex de,hl ld bc,20+20 call clrmem ; clear work area ex de,hl ld b,20 ; byte counter ld c,1 ; first bit ld d,0 ; bit counter imlp: ld e,(hl) imlp1: ld a,e and c jp z,imlp2 inc d imlp2: ld a,c rlca ld c,a cp 1 jp nz,imlp1 inc hl dec b jp nz,imlp ; got number of 1-bits in mask in reg d ld a,d and 0f8h rrca rrca rrca ; divide by 8 (get byte offset) ld l,a ld h,0 ld a,d and 7 ; bit offset inc a ld b,a ld a,080h imlp3: rlca dec b jp nz,imlp3 pop de add hl,de ld de,20 add hl,de ld (hl),a ret ; multi-byte counter count: push bc push de push hl ; ld hl,counter ; 20 byte counter starts here ; ld de,20 ; somewhere in here is the stop bit ; ex de,hl ; add hl,de ; ex de,hl ld hl,counter ld de,counter+20 cntlp: inc (hl) ld a,(hl) cp 0 jp z,cntlp1 ; overflow to next byte ld b,a ld a,(de) and b ; test for terminal value jp z,cntend ld (hl),0 ; reset to zero cntend: pop bc pop de pop hl ret cntlp1: inc l inc e jp cntlp ; multi-byte shifter shift: push bc push de push hl ld hl,shifter ; 20 byte shift register starts here ld de,20 ; somewhere in here is the stop bit ex de,hl add hl,de ex de,hl shflp: ld a,(hl) or a jp z,shflp1 ld b,a ld a,(de) and b jp nz,shlpe ld a,b rlca cp 1 jp nz,shflp2 ld (hl),0 inc hl inc de shflp2: ld (hl),a xor a ; set Z shlpe: pop hl pop de pop bc ret shflp1: inc hl inc de jp shflp counter: ds 2*20 shifter: ds 2*20 ; test harness test: ex af,af' exx di ; disable interrupts ld (spsav),sp ; save stack pointer ld sp,msbt+2 ; point to test-case machine state pop iy ; and load all regs pop ix pop hl pop de pop bc pop af ld sp,(spbt) iut: nop:nop:nop:nop ; Max 4 byte instruction under test ld (spat),sp ; save stack pointer ld sp,spat push af ; save other registers push bc push de push hl push ix push iy ld sp,(spsav) ; restore stack pointer ; pop iy ; jgh: Restore Spectrum's IY ld hl,(msbt) ; copy memory operand ld (msat),hl ld hl,flgsat ; flags after test ld a,(hl) flgmsk: and 0d7h ; mask-out irrelevant bits (self-modified code!) ld (hl),a ld ix,msat ld hl,crcval ; I unwrapped this loop out for speed loop 16 ; total of 16 bytes of state ld a,(ix) inc ix call updcrc ; accumulate crc of this test case lend exx ex af,af' ret ; machine state after test msat: ds 14 ; memop,iy,ix,hl,de,bc,af spat: ds 2 ; stack pointer after test flgsat equ spat-2 ; flags spsav: ds 2 ; saved stack pointer ; display hex string (pointer in hl, byte count in b) hexstr: ld a,(hl) call phex2 inc hl dec b jp nz,hexstr ret ; display hex ; display the big-endian 32-bit value pointed to by hl sp phex8: push af push bc push hl ld b,4 ph8lp: ld a,(hl) call phex2 inc hl dec b jp nz,ph8lp pop hl pop bc pop af ret ; display byte in a sp phex2: push af rrca rrca rrca rrca call phex1 pop af ; fall through ; display low nibble in a phex1: push af push bc push de push hl and $0F cp 10 jp c,ph11 add a,'A'-'9'-1 ph11: add a,'0' call Print pop hl pop de pop bc pop af ret ; szStart db "Z80all instruction exerciser",13,0 szDone db "Tests complete",0 szOk db " ",cGreen,cMid,"OK",cWhite,13,0 szErmsg1 db " ",cRed,cMid," FAIL!",cCret, "CRC:",0 ; was ERROR: szErmsg2 db " expected:",0 szCr: db cWhite,13,0 ; compare crc ; hl points to value to compare to crcval cmpcrc: push hl ld de,crcval ; I unwrapped this loop before I understood the algorithm loop 3 ld a,(de) cp (hl) jp nz,cce inc hl inc e lend ld a,(de) cp (hl) cce: pop hl ret ; 32-bit crc routine ; entry: a contains next byte, hl points to crc ; exit: crc updated ; This code was very slow, so I've modified it a fair bit. updcrc: inc l inc l inc l xor (hl) ; xor with new byte ld e,a ld d,high crcpages dec l dec l dec l ld b,0 ; b = accumulator loop 3 ld a,(de) xor b ld b,(hl) ld (hl),a inc d inc l lend ld a,(de) xor b ld b,(hl) ld (hl),a dec l dec l dec l ret initcrc: ld hl,crcval ld a,0ffh loop 3 ld (hl),a inc l lend ld (hl),a ret crcval ds 4 ; Print control codes cDel equ $08 ; cCret equ $0D ; cCls equ $0C ; cHome equ $0E ; cMid equ $0F ; cClr equ $1B ; ; Print colour select characters cBlack equ $00 ; cBlue equ $01 ; cRed equ $02 ; cMagenta equ $03 ; cGreen equ $04 ; cCyan equ $05 ; cYellow equ $06 ; cWhite equ $07 ; ; Print the zero-terminated string pointed to by HL PrintSZ_DE push de,af ; PSZDE_Lp ld a,(de) ; inc de ; or a ; jr z,PSZDE_X ; call Print ; jr PSZDE_Lp ; PSZDE_X pop af,de ; ret ; Done ; Print the string following the call in memory PrintStrFollow proc ; ex (sp),hl ; push af ; Loop ld a,(hl) ; inc hl ; or a ; jr z,Exit ; call Print ; jr Loop ; Exit pop af ; ex (sp),hl ; retp ; (RET) ; Print the contents of HL in hex PrintHex_HL ld a,h ; call PrintHex_A ; ld a,l ; ; Print the contents of A in hex PrintHex_A call PH2 ; PH2 rrca ; rrca ; rrca ; rrca ; push af ; and $0F ; add a,"0" ; cp "9"+1 ; jr c,PH3 ; add a,"A"-("9"+1) ; PH3 call Print ; pop af ; ret ; ; Print a space Print_Sp push af ; Save ld a,' ' ; Print a space call Print ; pop af ; Done ret ; ; A print character routine. Proportionally spaced characters Print push ix,hl,de,bc,af ; Save them cp cWhite+1 ; jr c,PrintColour ; cp cCls ; jr z,PrintCls ; cp cCret ; jr z,PrintCret ; cp cHome ; jr z,PrintHome ; cp cMid ; jr z,PrintMid ; ld h,PrintWidths/256 ; ld l,a ; ld a,(pCurX) ; add a,(hl) ; call c,PrintDoCret ; call PrintOutChar ; ld a,(pCurX) ; add a,(hl) ; ld (pCurX),a ; PrintExit pop af,bc,de,hl,ix ; ret ; ; Set a colour PrintColour cp 4 ; Above green don't make them bright jr nc,PrintCol1 ; or $40 ; Bright PrintCol1 ld (CurCol),a ; jr PrintExit ; ; Carriage return PrintCret call PrintDoCret ; jr PrintExit ; ; Clear screen - this clears it slowly with a fade effect PrintCls ld e,$00 ; ld hl,$5800 ; ld bc,$02FF ; pC1 ld a,(hl) ; and $07 ; jr z,pC2 ; set 0,e ; dec (hl) ; pC2 cpi ; jp pe,pC1 ; call Delay ; bit 0,e ; jr nz,PrintCls ; ld hl,$4000 ; ld de,$4001 ; ld bc,$1800 ; xor a ; ld (hl),a ; ldir ; ld a,(CurCol) ; ld (hl),a ; ld bc,$02FF ; ldir ; xor a ; out ($FE),a ; PrintHome xor a ; ld (pCurX),a ; ld (ppCurY),a ; ld a,cWhite ; ld (CurCol),a ; ld hl,$4000 ; ld (pCurY),hl ; jr PrintExit ; PrintMid ld a,160 ; ld (pCurX),a ; jr PrintExit ; ; A suitable delay for the fade Delay push bc ; ld bc,1000 ; Del1 cpi ; dec hl ; jp pe,Del1 ; pop bc ; ret ; ; Do the carriage return PrintDoCret ld a,(ppCurY) ; inc a ; PrintSetUpY cp 24 ; Gone off the bottom? jr c PSUY_Ok ; No, it's Okay ; Scroll the screen up one line call ScrollUp ; ld a,23 ; Bottom line PSUY_Ok ld (ppCurY),a ; and $1F ; push hl ; ld l,a ; ld h,$00 ; add hl,hl ; ld de,YTable ; add hl,de ; ld a,(hl) ; inc hl ; ld h,(hl) ; ld l,a ; ld (pCurY),hl ; xor a ; ld (pCurX),a ; pop hl ; ret ; ; Output the character PrintOutChar bit 7,l ; characters $00..$7F only ret nz ; push hl ; ld h,0 ; add hl,hl ; add hl,hl ; add hl,hl ; ld de,PrintChars-256 ; add hl,de ; push hl ; pop ix ; ld a,(pCurX) ; rrca ; rrca ; rrca ; and $1F ; ld de,(pCurY) ; or e ; ld e,a ; push de ; ld a,d ; rrca ; rrca ; rrca ; and $03 ; or $58 ; ld d,a ; ld a,(CurCol) ; ld (de),a ; inc de ; ld (de),a ; pop de ; ld a,(pCurX) ; and $07 ; ld c,a ; ld b,$08 ; OutCharL ld h,(ix) ; ld l,$00 ; ld a,c ; or a ; jr z,OCL1 ; OCL2 srl h ; rr l ; dec a ; jr nz,OCL2 ; OCL1 ld a,(de) ; xor h ; ld (de),a ; inc e ; ld a,(de) ; xor l ; ld (de),a ; dec e ; inc ix ; inc d ; djnz OutCharL ; pop hl ; ret ; ScrollUp push ix,hl,de,bc ; Save ld ix,YTable ; SU_Lp ld hl,(ix+2) ; ld a,l ; or h ; jr z SU_Moved ; ld de,(ix) ; inc ix ; inc ix ; push hl,de ; ld a,d ; rrca ; rrca ; rrca ; and $03 ; or $58 ; ld d,a ; ld a,h ; rrca ; rrca ; rrca ; and $03 ; or $58 ; ld h,a ; ld bc,32 ; ldir ; pop de,hl ; SU_Lp2 push hl,de ; ld bc,32 ; ldir ; pop de,hl ; inc h ; inc d ; ld a,h ; and %00000 111 ; jr nz SU_Lp2 ; jr SU_Lp ; Loop ; Clear the bottom line SU_Moved ld hl,$50E0 ; Clear the bottom line call ClearLine ; pop bc,de,hl,ix ; ret ; ; Clear a line ClearLine push hl ; ld d,h ; ld e,l ; inc de ; ld (hl),0 ; ld bc,31 ; ldir ; pop hl ; inc h ; ld a,h ; and %00000 111 ; jr nz ClearLine ; ret ; Done ; Screen addresses for the character rows YTable defw $4000,$4020,$4040,$4060 ; defw $4080,$40A0,$40C0,$40E0 ; defw $4800,$4820,$4840,$4860 ; defw $4880,$48A0,$48C0,$48E0 ; defw $5000,$5020,$5040,$5060 ; defw $5080,$50A0,$50C0,$50E0 ; defw 0,0,0,0,0,0,0,0 ; So running off the end isn't fatal ; Page bounded data align 256 ; Put these on page boundaries ; The CRC data rearranged for faster access crcpages: DEFB $00,$77,$EE,$99,$07,$70,$E9,$9E DEFB $0E,$79,$E0,$97,$09,$7E,$E7,$90 DEFB $1D,$6A,$F3,$84,$1A,$6D,$F4,$83 DEFB $13,$64,$FD,$8A,$14,$63,$FA,$8D DEFB $3B,$4C,$D5,$A2,$3C,$4B,$D2,$A5 DEFB $35,$42,$DB,$AC,$32,$45,$DC,$AB DEFB $26,$51,$C8,$BF,$21,$56,$CF,$B8 DEFB $28,$5F,$C6,$B1,$2F,$58,$C1,$B6 DEFB $76,$01,$98,$EF,$71,$06,$9F,$E8 DEFB $78,$0F,$96,$E1,$7F,$08,$91,$E6 DEFB $6B,$1C,$85,$F2,$6C,$1B,$82,$F5 DEFB $65,$12,$8B,$FC,$62,$15,$8C,$FB DEFB $4D,$3A,$A3,$D4,$4A,$3D,$A4,$D3 DEFB $43,$34,$AD,$DA,$44,$33,$AA,$DD DEFB $50,$27,$BE,$C9,$57,$20,$B9,$CE DEFB $5E,$29,$B0,$C7,$59,$2E,$B7,$C0 DEFB $ED,$9A,$03,$74,$EA,$9D,$04,$73 DEFB $E3,$94,$0D,$7A,$E4,$93,$0A,$7D DEFB $F0,$87,$1E,$69,$F7,$80,$19,$6E DEFB $FE,$89,$10,$67,$F9,$8E,$17,$60 DEFB $D6,$A1,$38,$4F,$D1,$A6,$3F,$48 DEFB $D8,$AF,$36,$41,$DF,$A8,$31,$46 DEFB $CB,$BC,$25,$52,$CC,$BB,$22,$55 DEFB $C5,$B2,$2B,$5C,$C2,$B5,$2C,$5B DEFB $9B,$EC,$75,$02,$9C,$EB,$72,$05 DEFB $95,$E2,$7B,$0C,$92,$E5,$7C,$0B DEFB $86,$F1,$68,$1F,$81,$F6,$6F,$18 DEFB $88,$FF,$66,$11,$8F,$F8,$61,$16 DEFB $A0,$D7,$4E,$39,$A7,$D0,$49,$3E DEFB $AE,$D9,$40,$37,$A9,$DE,$47,$30 DEFB $BD,$CA,$53,$24,$BA,$CD,$54,$23 DEFB $B3,$C4,$5D,$2A,$B4,$C3,$5A,$2D DEFB $00,$07,$0E,$09,$6D,$6A,$63,$64 DEFB $DB,$DC,$D5,$D2,$B6,$B1,$B8,$BF DEFB $B7,$B0,$B9,$BE,$DA,$DD,$D4,$D3 DEFB $6C,$6B,$62,$65,$01,$06,$0F,$08 DEFB $6E,$69,$60,$67,$03,$04,$0D,$0A DEFB $B5,$B2,$BB,$BC,$D8,$DF,$D6,$D1 DEFB $D9,$DE,$D7,$D0,$B4,$B3,$BA,$BD DEFB $02,$05,$0C,$0B,$6F,$68,$61,$66 DEFB $DC,$DB,$D2,$D5,$B1,$B6,$BF,$B8 DEFB $07,$00,$09,$0E,$6A,$6D,$64,$63 DEFB $6B,$6C,$65,$62,$06,$01,$08,$0F DEFB $B0,$B7,$BE,$B9,$DD,$DA,$D3,$D4 DEFB $B2,$B5,$BC,$BB,$DF,$D8,$D1,$D6 DEFB $69,$6E,$67,$60,$04,$03,$0A,$0D DEFB $05,$02,$0B,$0C,$68,$6F,$66,$61 DEFB $DE,$D9,$D0,$D7,$B3,$B4,$BD,$BA DEFB $B8,$BF,$B6,$B1,$D5,$D2,$DB,$DC DEFB $63,$64,$6D,$6A,$0E,$09,$00,$07 DEFB $0F,$08,$01,$06,$62,$65,$6C,$6B DEFB $D4,$D3,$DA,$DD,$B9,$BE,$B7,$B0 DEFB $D6,$D1,$D8,$DF,$BB,$BC,$B5,$B2 DEFB $0D,$0A,$03,$04,$60,$67,$6E,$69 DEFB $61,$66,$6F,$68,$0C,$0B,$02,$05 DEFB $BA,$BD,$B4,$B3,$D7,$D0,$D9,$DE DEFB $64,$63,$6A,$6D,$09,$0E,$07,$00 DEFB $BF,$B8,$B1,$B6,$D2,$D5,$DC,$DB DEFB $D3,$D4,$DD,$DA,$BE,$B9,$B0,$B7 DEFB $08,$0F,$06,$01,$65,$62,$6B,$6C DEFB $0A,$0D,$04,$03,$67,$60,$69,$6E DEFB $D1,$D6,$DF,$D8,$BC,$BB,$B2,$B5 DEFB $BD,$BA,$B3,$B4,$D0,$D7,$DE,$D9 DEFB $66,$61,$68,$6F,$0B,$0C,$05,$02 DEFB $00,$30,$61,$51,$C4,$F4,$A5,$95 DEFB $88,$B8,$E9,$D9,$4C,$7C,$2D,$1D DEFB $10,$20,$71,$41,$D4,$E4,$B5,$85 DEFB $98,$A8,$F9,$C9,$5C,$6C,$3D,$0D DEFB $20,$10,$41,$71,$E4,$D4,$85,$B5 DEFB $A8,$98,$C9,$F9,$6C,$5C,$0D,$3D DEFB $30,$00,$51,$61,$F4,$C4,$95,$A5 DEFB $B8,$88,$D9,$E9,$7C,$4C,$1D,$2D DEFB $41,$71,$20,$10,$85,$B5,$E4,$D4 DEFB $C9,$F9,$A8,$98,$0D,$3D,$6C,$5C DEFB $51,$61,$30,$00,$95,$A5,$F4,$C4 DEFB $D9,$E9,$B8,$88,$1D,$2D,$7C,$4C DEFB $61,$51,$00,$30,$A5,$95,$C4,$F4 DEFB $E9,$D9,$88,$B8,$2D,$1D,$4C,$7C DEFB $71,$41,$10,$20,$B5,$85,$D4,$E4 DEFB $F9,$C9,$98,$A8,$3D,$0D,$5C,$6C DEFB $83,$B3,$E2,$D2,$47,$77,$26,$16 DEFB $0B,$3B,$6A,$5A,$CF,$FF,$AE,$9E DEFB $93,$A3,$F2,$C2,$57,$67,$36,$06 DEFB $1B,$2B,$7A,$4A,$DF,$EF,$BE,$8E DEFB $A3,$93,$C2,$F2,$67,$57,$06,$36 DEFB $2B,$1B,$4A,$7A,$EF,$DF,$8E,$BE DEFB $B3,$83,$D2,$E2,$77,$47,$16,$26 DEFB $3B,$0B,$5A,$6A,$FF,$CF,$9E,$AE DEFB $C2,$F2,$A3,$93,$06,$36,$67,$57 DEFB $4A,$7A,$2B,$1B,$8E,$BE,$EF,$DF DEFB $D2,$E2,$B3,$83,$16,$26,$77,$47 DEFB $5A,$6A,$3B,$0B,$9E,$AE,$FF,$CF DEFB $E2,$D2,$83,$B3,$26,$16,$47,$77 DEFB $6A,$5A,$0B,$3B,$AE,$9E,$CF,$FF DEFB $F2,$C2,$93,$A3,$36,$06,$57,$67 DEFB $7A,$4A,$1B,$2B,$BE,$8E,$DF,$EF DEFB $00,$96,$2C,$BA,$19,$8F,$35,$A3 DEFB $32,$A4,$1E,$88,$2B,$BD,$07,$91 DEFB $64,$F2,$48,$DE,$7D,$EB,$51,$C7 DEFB $56,$C0,$7A,$EC,$4F,$D9,$63,$F5 DEFB $C8,$5E,$E4,$72,$D1,$47,$FD,$6B DEFB $FA,$6C,$D6,$40,$E3,$75,$CF,$59 DEFB $AC,$3A,$80,$16,$B5,$23,$99,$0F DEFB $9E,$08,$B2,$24,$87,$11,$AB,$3D DEFB $90,$06,$BC,$2A,$89,$1F,$A5,$33 DEFB $A2,$34,$8E,$18,$BB,$2D,$97,$01 DEFB $F4,$62,$D8,$4E,$ED,$7B,$C1,$57 DEFB $C6,$50,$EA,$7C,$DF,$49,$F3,$65 DEFB $58,$CE,$74,$E2,$41,$D7,$6D,$FB DEFB $6A,$FC,$46,$D0,$73,$E5,$5F,$C9 DEFB $3C,$AA,$10,$86,$25,$B3,$09,$9F DEFB $0E,$98,$22,$B4,$17,$81,$3B,$AD DEFB $20,$B6,$0C,$9A,$39,$AF,$15,$83 DEFB $12,$84,$3E,$A8,$0B,$9D,$27,$B1 DEFB $44,$D2,$68,$FE,$5D,$CB,$71,$E7 DEFB $76,$E0,$5A,$CC,$6F,$F9,$43,$D5 DEFB $E8,$7E,$C4,$52,$F1,$67,$DD,$4B DEFB $DA,$4C,$F6,$60,$C3,$55,$EF,$79 DEFB $8C,$1A,$A0,$36,$95,$03,$B9,$2F DEFB $BE,$28,$92,$04,$A7,$31,$8B,$1D DEFB $B0,$26,$9C,$0A,$A9,$3F,$85,$13 DEFB $82,$14,$AE,$38,$9B,$0D,$B7,$21 DEFB $D4,$42,$F8,$6E,$CD,$5B,$E1,$77 DEFB $E6,$70,$CA,$5C,$FF,$69,$D3,$45 DEFB $78,$EE,$54,$C2,$61,$F7,$4D,$DB DEFB $4A,$DC,$66,$F0,$53,$C5,$7F,$E9 DEFB $1C,$8A,$30,$A6,$05,$93,$29,$BF DEFB $2E,$B8,$02,$94,$37,$A1,$1B,$8D ; The proportional font (from Invasion Of The Body Snatchers) PrintChars defb $00,$00,$00,$00,$00,$00,$00,$00 defb $80,$80,$80,$80,$80,$00,$80,$00 defb $A0,$A0,$A0,$00,$00,$00,$00,$00 defb $50,$50,$F8,$50,$F8,$50,$50,$00 defb $20,$78,$A0,$70,$28,$F0,$20,$00 defb $C0,$C8,$10,$20,$40,$98,$18,$00 defb $40,$A0,$A0,$40,$A8,$90,$68,$00 defb $80,$80,$80,$00,$00,$00,$00,$00 defb $20,$40,$80,$80,$80,$40,$20,$00 defb $80,$40,$20,$20,$20,$40,$80,$00 defb $20,$A8,$70,$20,$70,$A8,$20,$00 defb $00,$20,$20,$F8,$20,$20,$00,$00 defb $00,$00,$00,$00,$40,$40,$80,$00 defb $00,$00,$00,$F8,$00,$00,$00,$00 defb $00,$00,$00,$00,$00,$00,$80,$00 defb $00,$08,$10,$20,$40,$80,$00,$00 defb $70,$88,$98,$A8,$C8,$88,$70,$00 defb $20,$60,$20,$20,$20,$20,$70,$00 defb $70,$88,$08,$30,$40,$80,$F8,$00 defb $F8,$08,$10,$30,$08,$88,$70,$00 defb $10,$30,$50,$90,$F8,$10,$10,$00 defb $F8,$80,$F0,$08,$08,$88,$70,$00 defb $38,$40,$80,$F0,$88,$88,$70,$00 defb $F8,$08,$10,$20,$40,$40,$40,$00 defb $70,$88,$88,$70,$88,$88,$70,$00 defb $70,$88,$88,$78,$08,$10,$E0,$00 defb $00,$00,$80,$00,$80,$00,$00,$00 defb $00,$00,$40,$00,$40,$40,$80,$00 defb $10,$20,$40,$80,$40,$20,$10,$00 defb $00,$00,$F8,$00,$F8,$00,$00,$00 defb $80,$40,$20,$10,$20,$40,$80,$00 defb $70,$88,$10,$20,$20,$00,$20,$00 defb $70,$88,$A8,$B8,$B0,$80,$78,$00 defb $20,$50,$88,$88,$F8,$88,$88,$00 defb $F0,$88,$88,$F0,$88,$88,$F0,$00 defb $70,$88,$80,$80,$80,$88,$70,$00 defb $F0,$88,$88,$88,$88,$88,$F0,$00 defb $F8,$80,$80,$F0,$80,$80,$F8,$00 defb $F8,$80,$80,$F0,$80,$80,$80,$00 defb $78,$80,$80,$80,$98,$88,$78,$00 defb $88,$88,$88,$F8,$88,$88,$88,$00 defb $E0,$40,$40,$40,$40,$40,$E0,$00 defb $08,$08,$08,$08,$08,$88,$70,$00 defb $88,$90,$A0,$C0,$A0,$90,$88,$00 defb $80,$80,$80,$80,$80,$80,$F8,$00 defb $88,$D8,$A8,$A8,$88,$88,$88,$00 defb $88,$88,$C8,$A8,$98,$88,$88,$00 defb $70,$88,$88,$88,$88,$88,$70,$00 defb $F0,$88,$88,$F0,$80,$80,$80,$00 defb $70,$88,$88,$88,$A8,$90,$68,$00 defb $F0,$88,$88,$F0,$A0,$90,$88,$00 defb $70,$88,$80,$70,$08,$88,$70,$00 defb $F8,$20,$20,$20,$20,$20,$20,$00 defb $88,$88,$88,$88,$88,$88,$70,$00 defb $88,$88,$88,$88,$88,$50,$20,$00 defb $88,$88,$88,$A8,$A8,$D8,$88,$00 defb $88,$88,$50,$20,$50,$88,$88,$00 defb $88,$88,$50,$20,$20,$20,$20,$00 defb $F8,$08,$10,$20,$40,$80,$F8,$00 defb $F8,$C0,$C0,$C0,$C0,$C0,$F8,$00 defb $00,$80,$40,$20,$10,$08,$00,$00 defb $F8,$18,$18,$18,$18,$18,$F8,$00 defb $20,$70,$A8,$20,$20,$20,$00,$00 defb $00,$00,$00,$00,$00,$00,$F8,$00 defb $00,$00,$00,$00,$00,$00,$00,$00 defb $00,$00,$68,$98,$88,$98,$68,$00 defb $80,$80,$B0,$C8,$88,$C8,$B0,$00 defb $00,$00,$78,$80,$80,$80,$78,$00 defb $08,$08,$68,$98,$88,$98,$68,$00 defb $00,$00,$70,$88,$F8,$80,$70,$00 defb $20,$40,$40,$E0,$40,$40,$40,$00 defb $00,$00,$78,$88,$98,$68,$08,$70 defb $80,$80,$F0,$88,$88,$88,$88,$00 defb $80,$00,$80,$80,$80,$80,$80,$00 defb $00,$20,$00,$20,$20,$20,$20,$C0 defb $80,$80,$90,$A0,$E0,$90,$88,$00 defb $C0,$40,$40,$40,$40,$40,$E0,$00 defb $00,$00,$D0,$A8,$A8,$A8,$A8,$00 defb $00,$00,$F0,$88,$88,$88,$88,$00 defb $00,$00,$70,$88,$88,$88,$70,$00 defb $00,$00,$F0,$88,$88,$F0,$80,$80 defb $00,$00,$78,$88,$88,$78,$08,$08 defb $00,$00,$B0,$C0,$80,$80,$80,$00 defb $00,$00,$78,$80,$70,$08,$F0,$00 defb $00,$20,$F8,$20,$20,$20,$18,$00 defb $00,$00,$88,$88,$88,$88,$78,$00 defb $00,$00,$88,$88,$50,$50,$20,$00 defb $00,$00,$88,$88,$88,$A8,$50,$00 defb $00,$00,$88,$50,$20,$50,$88,$00 defb $00,$00,$90,$90,$90,$F0,$10,$E0 defb $00,$00,$F8,$10,$20,$40,$F8,$00 defb $30,$40,$40,$80,$40,$40,$30,$00 defb $00,$80,$80,$00,$00,$80,$80,$00 defb $C0,$20,$20,$10,$20,$20,$C0,$00 defb $50,$00,$70,$88,$F8,$80,$70,$00 defb $00,$00,$08,$70,$80,$00,$00,$00 ; Character widths PrintWidths defb $07,$09,$09,$09,$09,$09,$09,$03 defb $05,$05,$05,$05,$03,$05,$05,$05 defb $05,$03,$05,$05,$05,$05,$09,$09 ; " " .. defb $07,$09,$07,$02,$05,$09,$07,$09 defb $06,$02,$04,$06,$06,$06,$06,$02 defb $04,$04,$06,$06,$03,$06,$02,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$02,$03,$05,$06,$05,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$04,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$04,$06 defb $06,$02,$04,$06,$04,$06,$06,$06 defb $06,$06,$05,$06,$06,$06,$06,$06 defb $06,$05,$06,$05,$02,$05,$06,$06 if false defb $03,$06,$0C,$12,$18,$1E,$24,$2A ; Wide spaces $80..? defb $30,$36,$3C,$42,$48,$06,$06,$06 defb $01,$02,$03,$04,$05,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 defb $06,$06,$06,$06,$06,$06,$06,$06 endif ; Variables pCurX db 0 ; A logical X position ppCurY db 0 ; A logical Y position pCurY dw 0 ; The actual address CurCol db 0 ; The cursor colour Ye_End equ * ; Now, Zeus saving code. Playing about a bit here. ; Let's generate a tzx file for it, if we can... output_para $5B00,Ye_End - $5B00 ;If you don't have a ParaSys port ignore this. ; Load up a suitable loading screen for it, assuming we can find one... if zeusgetfilelength("Test.scr") = $1B00 import_bin "Test.scr",$4000 ; Now, let's modify this a bit org $4000 ; Clear the top third ds $800,0 ; org $5800 ; ds $100 ; org $5000 ; Clear the bottom third ds $800,0 ; org $5A00 ; ds $100 ; elseif zeusgetfilelength("IOTBS.scr") = $1B00 ; Bugger that one, use this one instead! import_bin "IOTBS.scr",$4000 endif ; Anyway, now we have a loading screen, generate the TZX and an SZX file ; ; Using multipass we get both of these. ; if enabled bCompressForTape and (ZEUSVER >= 37) ; Compress the data ; This builds a block of data which you load at $5B00 and then call at $5B00 (the 0 means don't flash border during decompression) zeuscompress $8000,Ye_End,Entry,$5B00,0 zeusprinthex * ; Generate the TZX file, screen and loader for it. output_tzx "z80test_c.tzx","Z80_Test","",$5800,*-$5800,1,$5B00 ; The values here are a pain. output_szx "z80test_c.szx",0,$5B00 ; Generate code to test else ; This outputs the code uncompressed... output_tzx "z80test_u.tzx","Z80_Test","",$8000,Ye_End-$8000,1,$8000 output_szx "z80test_u.szx",0,Entry ; Generate code to test endif ; The parameters for output_tzx are "filename","spectrum filname",Start address for save, length of saved data, options, execute address ; Options are currently as follows: ; ; 0 -> Just output a CODE block of tape data. ; 1 -> Output a PROGRAM block with the loader, then the data block in interleaved format. ; 2 -> Output a PROGRAM block with the loader, but don't bother with the data at all... this is for brave people who'll add their own. ; Until release these are subject to change if I decide I don't like them. ; Note - the latest version of Zeus is now rather clever about generating the tape data, if I say so myself... if the screen has blank lines Zeus ; won't bother putting them on the tape. Also, if the code block doesn't start at $5800 - ie, does not include the attributes ; then Zeus will send the attributes as part of the screen data before they're needed. ; And if the screen is fully drawn before the code is finished Zeus will use the spare screen data lines to send code. ; ; zexall.src - Z80 instruction set exerciser ; Copyright (C) 1994 Frank D. Cringle ; ; 14-Nov-2015: Modified to assemble with Zeus ; and run correctly on the ZX Spectrum hardware at $8000 ; ; 03-Nov-2002: Modified to assemble with ZMAC and MAXAM ; Copyright (C) 2002 J.G.Harston ; ; For the purposes of this test program, the machine state consists of: ; a 2 byte memory operand, followed by ; the registers iy,ix,hl,de,bc,af,sp ; for a total of 16 bytes. ; The program tests instructions (or groups of similar instructions) ; by cycling through a sequence of machine states, executing the test ; instruction for each one and running a 32-bit crc over the resulting ; machine states. At the end of the sequence the crc is compared to ; an expected value that was found empirically on a real Z80. ; A test case is defined by a descriptor which consists of: ; a flag mask byte, ; the base case, ; the incement vector, ; the shift vector, ; the expected crc, ; a short descriptive message. ; ; The flag mask byte is used to prevent undefined flag bits from ; influencing the results. Documented flags are as per Mostek Z80 ; Technical Manual. ; ; The next three parts of the descriptor are 20 byte vectors ; corresponding to a 4 byte instruction and a 16 byte machine state. ; The first part is the base case, which is the first test case of ; the sequence. This base is then modified according to the next 2 ; vectors. Each 1 bit in the increment vector specifies a bit to be ; cycled in the form of a binary counter. For instance, if the byte ; corresponding to the accumulator is set to 0ffh in the increment ; vector, the test will be repeated for all 256 values of the ; accumulator. Note that 1 bits don't have to be contiguous. The ; number of test cases 'caused' by the increment vector is equal to ; 2^(number of 1 bits). The shift vector is similar, but specifies a ; set of bits in the test case that are to be successively inverted. ; Thus the shift vector 'causes' a number of test cases equal to the ; number of 1 bits in it. ; The total number of test cases is the product of those caused by the ; counter and shift vectors and can easily become unweildy. Each ; individual test case can take a few milliseconds to execute, due to ; the overhead of test setup and crc calculation, so test design is a ; compromise between coverage and execution time. ; This program is designed to detect differences between ; implementations and is not ideal for diagnosing the causes of any ; discrepancies. However, provided a reference implementation (or ; real system) is available, a failing test case can be isolated by ; hand using a binary search of the test space.