; ******************************************************************* ; *** *** ; *** VIP2K Chip 8 interpreter *** ; *** *** ; *** This software is copyright 2018 by Marcel van Tongeren *** ; *** You have permission to use, modify, copy, and distribute *** ; *** this software so long as this copyright notice is retained. *** ; *** This software may not be used in commercial applications *** ; *** without express written permission from the author. *** ; ******************************************************************* ; Origin set to 07000H, EOF = 0768FH ORG 07000H ; CPU Type: CPU 1802 ; Labels: CHIP8_EXEC EQU 7000H CHIP8_COMMAND_F EQU 7005H R700D EQU 700DH R7028 EQU 7028H R703C EQU 703CH R7040 EQU 7040H NEXT_DIGIT EQU 704BH S705B EQU 705BH R706B EQU 706BH CTL_R EQU 7075H CTL_K EQU 707CH CHIP8_COMMAND_3 EQU 7083H S7084 EQU 7084H SKIP_INSTRUCTION EQU 7088H NO_SKIP EQU 708AH CHIP8_COMMAND_4 EQU 708BH S708C EQU 708CH CHIP8_COMMAND_9 EQU 7091H CHIP8_COMMAND_5 EQU 7095H CHIP8_COMMAND_E EQU 7099H R70A4 EQU 70A4H CHIP8_ExA1 EQU 70A7H CHIP8_Ex9E EQU 70ACH CHIP8_Fx07_Start EQU 70B1H CHIP8_Fx15_Start EQU 70B7H KEY_UP EQU 70BDH R70CE EQU 70CEH CHIP8_00DD EQU 70DDH CHIP8_00E0 EQU 70E0H CHIP8_00EE EQU 70EEH R70E4 EQU 70E4H CHIP8_COMMAND_D_2P EQU 70F3H R7123 EQU 7123H R7138 EQU 7138H CHIP8_COMMAND_D_2P_DRAW EQU 7141H R714A EQU 714AH R7154 EQU 7154H R7168 EQU 7168H R7173 EQU 7173H R717E EQU 717EH R7189 EQU 7189H CHIP8_COMMAND_D_2P_END EQU 7196H CTL_S EQU 71A2H STORE_SCREEN_RES EQU 71A5H CTL_L EQU 71B1H CHIP8_COMMAND_TABLE EQU 71B6H CHIP8_START EQU 71E0H R71F0 EQU 71F0H R71FC EQU 71FCH R7205 EQU 7205H R721A EQU 721AH RES_3x5 EQU 722EH R723A EQU 723AH RESTORE_KEY_MAP EQU 724FH R7258 EQU 7258H REPEAT_BYTES EQU 725FH R7263 EQU 7263H R726D EQU 726DH MAIN_CHIP8_LOOP EQU 7278H SPEED_KEY EQU 7296H S729E EQU 729EH SPEED_DELAY EQU 72B2H R72B6 EQU 72B6H CTL_KEY EQU 72C9H J72CC EQU 72CCH CHIP8_COMMAND_0 EQU 72D0H CHIP8_COMMAND_00 EQU 72D9H R72DB EQU 72DBH CTL_Q EQU 72DFH CHIP8_COMMAND_D_3P EQU 72E8H J7319 EQU 7319H R732F EQU 732FH CHIP8_COMMAND_D_3P_DRAW EQU 7339H R7345 EQU 7345H R734F EQU 734FH S7367 EQU 7367H R7372 EQU 7372H R737D EQU 737DH R7388 EQU 7388H R7393 EQU 7393H CHIP8_COMMAND_D_3P_END EQU 73A0H CHIP8_COMMAND_2 EQU 73ACH CHIP8_COMMAND_1 EQU 73B3H CHIP8_COMMAND_B EQU 73BCH R73CC EQU 73CCH CHIP8_COMMAND_6 EQU 73CEH CHIP8_COMMAND_7 EQU 73D1H CHIP8_COMMAND_8 EQU 73D6H R73DE EQU 73DEH S73EA EQU 73EAH CHIP8_COMMAND_C EQU 73F3H CHIP8_COMMAND_A EQU 7405H FIVEL_INTERRUPT_END EQU 740EH FIVEL_INTERRUPT EQU 7415H FIVEL_DISPLAY_9 EQU 7429H FIVEL_DISPLAY_8 EQU 742CH FIVEL_COUNTER0 EQU 7457H FIVEL_NO_SHIFT EQU 7463H FIVEL_NO_CTL EQU 7469H FIVEL_KEY_PRESS EQU 7492H R7493 EQU 7493H R7499 EQU 7499H FIVEL_NO_KEY_PRESS EQU 749DH PATTERN_3x5 EQU 7544H PATTERN_2x4 EQU 755CH FOURL_INTERRUPT_END EQU 756CH FOURL_INTERRUPT EQU 7573H FOURL_DISPLAY_9 EQU 758AH FOURL_DISPLAY_8 EQU 758DH FOURL_COUNTER0 EQU 75B2H FOURL_NO_SHIFT EQU 75BEH FOURL_NO_CTL EQU 75C4H FOURL_KEY_PRESS EQU 75EDH R75EE EQU 75EEH R75F4 EQU 75F4H FOURL_NO_KEY_PRESS EQU 75F8H ROM_KEY_MAP EQU 7640H CHIP8_IDENTIFIER EQU 768BH ; Register Definitions: R0 EQU 0 R1 EQU 1 R2 EQU 2 R3 EQU 3 R4 EQU 4 R5 EQU 5 R6 EQU 6 R7 EQU 7 R8 EQU 8 R9 EQU 9 RA EQU 10 RB EQU 11 RC EQU 12 RD EQU 13 RE EQU 14 RF EQU 15 ; Start code segment CHIP8_EXEC DB 00H, 0DDH ; SYS 0DD - Chip 8 code to clear complete VIP2K video RAM DB 12H, 00H ; JP 200 - Start Chip 8 user code at 0x8200 DB 00H ; F commands: Fx07, Fx0A, Fx15, Fx18, Fx1E, Fx29, Fx33, Fx55, Fx65 ; Second byte is used for lower address (R4.0) which means a jump to 70aa so below code has a 'fixed location in the page CHIP8_COMMAND_F LDA R5 ; Get second byte Fxaa instruction PLO R4 ; Store second byte in PC, R4.0. ; LD Vx, DT -> Vx = Delaytimer CHIP8_Fx07 BR CHIP8_Fx07_Start DB 00H ; LD Vx, K -> Vx = key, wait for keypress CHIP8_Fx0A LDI 0F9H PLO R7 ; R7 = FFF9 i.e. keyboard code R700D LDN R7 ; Get keyboard code SMI 7FH ; Loop if keyboard code != 7F, i.e. wait till all keys are 'up' BNZ R700D ; this loop is needed otherwise Chip 8 code will detect multiple key presses at a time BR KEY_UP DB 00H ; LD DT, Vx -> Delaytimer = Vx CHIP8_Fx15 BR CHIP8_Fx15_Start DB 00H ; ST, Vx -> Soundtimer = Vx CHIP8_Fx18 SEP R3 ; No sound, so routine is just returning to main loop DB 00H DB 00H DB 64H ; Used for BCD conversion DB 0AH ; Used for BCD conversion DB 01H ; Used for BCD conversion ; ADD I, Vx -> I = I + Vx CHIP8_Fx1E SEX R6 GLO RA ADD ; Add M(R6) to RA.0, i.e. I = I + Vx PLO RA BNF R7028 ; If DF we need to add 1 to RA.1 GHI RA ADI 01H ; Add 1 to RA.1 PHI RA R7028 SEP R3 ; LD F, Vx -> Point I to 5 byte numeric sprite for value in Vx CHIP8_Fx29 LDI 75H PHI RA ; RA.1 = 75, 7500-75FF contains the VIP sprite table LDN R6 ANI 0FH PLO RA ; RA.0 = Vx (0-F) LDN RA PLO RA ; RA.0 = M(RA), lower byte of sprite location is stored on 7500-750F. SEP R3 ; LD B, Vx -> Store BCD value of Vx in [I], [I+1], [I+2] CHIP8_Fx33 SEX R6 LDN R6 ; Get Vx PHI RF ; RF.1 = Vx GHI R4 ;7036: 94 PHI RE ; RE.1 = R3.1 = 70, RE should point to bytes on 701B where the BCD constants are stored LDI 1BH PLO RE ; RE = 701B DEC RA ; RA = RA - 1 (i.e register I), as it should point to start value after INC A at start of loop R703C INC RA ; RA = RA + 1, next BCD digit LDI 00H ; STR RA ; Start with M(RA) = 0 R7040 LDN RE ; Get current BCD constant SD ; Subtract constant from Vx BNF NEXT_DIGIT ; If minus go to next digit STR R6 ; Vx = Vx - BCD constant LDN RA ADI 01H STR RA ; M(RA) = M(RA) + 1 BR R7040 ; Continue loop NEXT_DIGIT LDA RE ; Get current BCD constant and move RE to next constant SHR BNF R703C ; Continue until constant 1 (i.e. bit 0 = 1) GHI RF STR R6 ; Vx = saved Vx value DEC RA DEC RA ; Restore RA / I SEP R3 DB 00H ; LD [I], Vx -> Store V0 .. Vx in [I] .. [I+x] CHIP8_Fx55 DEC R2 ; R2 = R2 - 1 to have stack ready for a push GLO R6 STR R2 ; Save Vx pointer on stack for comparison LDI 0E0H PLO R7 ; Point R7 to Vy, y=0 (FFE0) S705B LDN R7 STR RA ; M(RA) = I = Vy GLO R7 XOR ; XOR Vy with Vx INC R7 ; R7 = R7 + 1, i.e, R7 to next variable INC RA ; RA = RA + 1 BNZ S705B ; Loop if more variables should be copied INC R2 ; Set stack back SEP R3 ; LD Vx, [I] -> Read V0 .. Vx from [I] .. [I+x CHIP8_Fx65 DEC R2 ; R2 = R2 - 1 to have stack ready for a push GLO R6 STR R2 ; Save Vx pointer on stack for comparison LDI 0E0H PLO R7 ; Point R7 to Vy, y=0 (FFE0) R706B LDN RA STR R7 ; Vy = M(RA) = I GLO R7 XOR ; XOR Vy with Vx INC R7 ; R7 = R7 + 1, i.e, R7 to next variable INC RA ; RA = RA + 1 BNZ R706B ; Loop if more variables should be copied INC R2 ; Set stack back SEP R3 CTL_R LOAD R3,CHIP8_START ; Restart Chip 8 SEP R3 CTL_K LOAD R3,RESTORE_KEY_MAP SEP R3 ; Restore keyboard mapping ; SE Vx , kk -> Skip next instruction if Vx == kk CHIP8_COMMAND_3 LDA R5 ; Get value kk S7084 SEX R6 XOR ; XOR kk with Vx BNZ NO_SKIP ; Skip instrucion if Vx == kk SKIP_INSTRUCTION INC R5 INC R5 ; Chip 8 PC + 2 to skip instruction NO_SKIP SEP R3 ; SNE Vx, kk -> Skip next instruction if Vx != kk CHIP8_COMMAND_4 LDA R5 ; Get value kk S708C SEX R6 XOR ; XOR kk with Vx BNZ SKIP_INSTRUCTION; Skip instrucion if Vx != kk SEP R3 ; SNE Vx, Vy -> Skip next instruction if Vx != Vy CHIP8_COMMAND_9 LDA R5 ; R5 + 1 so it points to the next instrction LDN R7 ; Get Vy BR S708C ; Do the same action as CHIP8_COMMAND_4 but with Vy CHIP8_COMMAND_5 LDA R5 ; R5 + 1 so it points to the next instrction LDN R7 ; Get Vy BR S7084 ; Do the same action as CHIP8_COMMAND_3 but with Vy ; E commands: Ex9E, ExA1 ; Second byte is used for lower address (R4.0) which means a jump to 70aa so below code has a 'fixed location in the page CHIP8_COMMAND_E LDI 0F9H PLO R7 ; R7 = FFF9, i.e. key code BR R70A4 ; Continue on 70A4 BR CHIP8_Ex9E ; Branch as we only have 3 bytes here and we needed some more space DB 00H BR CHIP8_ExA1 ; Branch as we only have 3 bytes here and we needed some more space DB 00H R70A4 SEX R6 LDA R5 ; Get second byte PLO R4 ; Store second byte in R4.0 which is the PC and as such exectue CHIP8_Ex9E or CHIP8_ExA1 ; SKP Vx -> Skip next instruction if key Vx up CHIP8_ExA1 LDN R7 ; Get key code SM BNZ SKIP_INSTRUCTION; Skip instruction if key pressed is not equal to Vx SEP R3 ; SKNP Vx -> Skip next instruction if key Vx down CHIP8_Ex9E LDN R7 ; Get key code SM BZ SKIP_INSTRUCTION; Skip instruction if key pressed is equal to Vx SEP R3 ; LD Vx, DT -> Vx = Delaytimer CHIP8_Fx07_Start LDI 0FAH PLO R7 ; R7 = FFFA i.e. Delaytimer LDN R7 ; Get timer value STR R6 ; Vx = M(R6) = Delaytime SEP R3 ; LD DT, Vx -> Delaytimer = Vx CHIP8_Fx15_Start LDI 0FAH PLO R7 ; R7 = FFFA i.e. Delaytimer LDN R6 STR R7 ; FFFA = M(R6) = Delaytime SEP R3 KEY_UP LDN R7 SMI 7FH BZ KEY_UP ; Loop if FFF9 == F7, i.e. wait until a key is pressed LDN R7 ANI 80H BNZ R70CE ; Exit routine if bit 7=1 (for all CTL keys) in that case the main Chip 8 loop will handle CTL function LDN R7 SMI 10H BDF R700D ; Loop back to start key detection routine if key code < 10, i.e. not a valid Chip 8 key (0-F) LDN R7 STR R6 ; Vx = M(R6) R70CE SEP R3 DB 00H ;70CF: 00 DB 00H ;70D0: 00 DB 00H ;70D1: 00 DB 00H ;70D2: 00 DB 00H ;70D3: 00 DB 00H ;70D4: 00 DB 00H ;70D5: 00 DB 00H ;70D6: 00 DB 00H ;70D7: 00 DB 00H ;70D8: 00 DB 00H ;70D9: 00 DB 00H ;70DA: 00 DB 00H ;70DB: 00 DB 00H ;70DC: 00 ; Same as CLS except this routine is called from the interpreter to make sure the complete video RAM is cleared CHIP8_00DD LDI 0FCH LSKP ; Load FC to get RC to point to FCFC and as such clear E800-FCFC ; CLS -> Clear display CHIP8_00E0 LDI 0ECH PHI RC ; Load EC to get RC to point to ECEC and as such clear E800-ECEC PLO RC ; RC.0 = RC.1 simplified to keep the code to fit in available space R70E4 LDI 00H STR RC ; M(RC) = 0 DEC RC ; RC = RC - 1 GHI RC SMI 0E7H BNZ R70E4 ; Loop if RC != E7xx SEP R3 ; RETURN -> Return from subroutine CHIP8_00EE LDA R2 PHI R5 LDA R2 PLO R5 ; Pull R5 from stack, R5 = Chip 8 PC SEP R3 ; DRW Vx, Vy, n -> Draw n byte sprite stored at [I] at Vx, Vy. Set VF = collision ; Drawing routine to draw a pattern of bytes where every bit will result in 2 pixels ; This routine is used for the small screen resolution, i.e. 2x4 CHIP8_COMMAND_D_2P DEC R2 ; R2 = R2 - 1 to have stack ready for a push LDN R6 ANI 3FH STR R2 ; Stack = Vx, horizontal drawing position ADD ; STR R2 ; Stack = 2*Vx as we want two pixels wide so horizontal position is also doubled ANI 07H PHI RD ; RD.1 containts the number of bits left to shift later as byte contains 8 bits, i.e. 8 positions LDN R2 ; Get 2xVx SHR SHR SHR ; D = 2*Vx/8, so we can identify the 'byte' position in memory ADI 0D5H PLO RC LDI 0E8H PHI RC ; RC = horizontal screen location, we have added E8D5 as that is the memory location of top left of screen ; We don't use E800 so the viewable screen is in the 'middle' LDN R7 ANI 1FH PLO RD ; RD.0 = Vy, vertical drwaing position SHL PLO RE ; RE.0 = Vy * 2 LDI 76H PHI RE ; RE.1 = 76, resulting in M(RE) containing the value to be added to get the horizontal poitions ; Table at 7600 contains 32 16 bit values low byte first followed by high for all 32 lines SEX RE GLO RC ADD ; Add low byte PLO RC INC RE GHI RC ADC ; Add high byte + carry from low PHI RC ; RC is drawing position in memory LDA R5 ANI 0FH PLO RD ; RD.0 = number of lines to be drawn PLO R8 ; R8.0 = number of lines to be drawn LDI 0EFH PLO R6 ; R6 = VF for storing of collision flag LDI 00H STR R6 ; VF / collision flag = 0, i.e. no graphic collision detected as yet R7123 GLO R8 BZ CHIP8_COMMAND_D_2P_END ; All lines drawn, finalize routine DEC R8 ; Number of lines - 1 LOAD RE,PATTERN_2x4 ; RE = Pattern table LDI 0F2H PLO R7 ; R7 = FFF2, FFF0-FFF2 will contain 24 bit pattern based on byte to be drawn. ; Reason to use 24 bit is that every bit needs to be drawn as 2 pixels and could be shifted right max 8 pixels SEX R7 LDI 00H STXD STXD STR R7 ; FFF0-FFF2 = 0, pattern reset LDA RA PHI RF ; RF.1 = byte to be drawn (M(RA) or M(I), RA/I is incremented for next byte) R7138 GHI RF SHR ; DF = first bit, 1 means a pixels should be drawn PHI RF ; RF is shifted right 1 bit so next time we take the next bit into DF BDF CHIP8_COMMAND_D_2P_DRAW INC RE INC RE ; Increment pattern table BR R714A CHIP8_COMMAND_D_2P_DRAW LDI 0F1H PLO R7 ; R7 = FFF1 LDA RE ; Get second byte for 2 pixel pattern for current bit OR STXD ; OR result on pattern location LDA RE ; Get first byte for 2 pixel pattern for current bit OR STR R7 ; OR result on pattern location R714A GLO RE SMI 6CH ; Check if all bits are done (end of 2 pixel pattern table is xx6C) BNZ R7138 ; if not done, loop back for next bit LDI 00H PLO RF ; RF.0 = 0, don't think this was needed, maybe we can remove it in a later version? GHI RD PLO RE ; RE.0 number of bits to shift to get the final horizontal position R7154 GLO RE BZ R7168 ; If RE.0 = 0 we are ready shifting LDI 0F0H PLO R7 ; R7 = FFF0 LDN R7 SHR STR R7 ; Shift first byte one right INC R7 LDN R7 SHRC STR R7 ; Shift second byte one right INC R7 LDN R7 SHRC STR R7 ; Shift third byte one right DEC RE ; Decrement number of bits to be shifted BR R7154 ; Loop back R7168 LDI 0F0H PLO R7 ; R7 = FFF0, which now contains the 24 bit pattern to be drawn on the first line SEX RC LDN R7 AND ; AND first byte pattern to be drawn with video memory BZ R7173 ; If zero we have no collision with what is already on the screen LDI 01H STR R6 ; If not zero set the collision flag R7173 LDA R7 XOR STR RC ; XOR first byte pattern to be drawn with video memory and store it back in video memory INC RC ; RC = next screen position LDN R7 AND ; AND second byte pattern to be drawn with video memory BZ R717E ; If zero we have no collision with what is already on the screen LDI 01H STR R6 ; If not zero set the collision flag R717E LDA R7 XOR STR RC ; XOR second byte pattern to be drawn with video memory and store it back in video memory INC RC ; RC = next screen position LDN R7 AND ; AND second byte pattern to be drawn with video memory BZ R7189 ; If zero we have no collision with what is already on the screen LDI 01H STR R6 ; If not zero set the collision flag R7189 LDA R7 XOR STR RC ; XOR second byte pattern to be drawn with video memory and store it back in video memory GLO RC ADI 18H PLO RC GHI RC ADCI 00H PHI RC ; RC = next line (RC + 0x18) BR R7123 ; Loop back CHIP8_COMMAND_D_2P_END SEX R2 GLO RD STR R2 ; Stack = number of lines dranw GLO RA SM PLO RA GHI RA SMBI 00H PHI RA ; RA = RA - number of lines drawn, i.e. reset RA to what it was at entry INC R2 ; Set stack back SEP R3 CTL_S LDI 01H STR R2 ; Stack = 1 which will be used to indicate 2x4 screen resolution STORE_SCREEN_RES LOAD R3,CHIP8_START ; Set R3 to start of Chip 8 interpreter LDI 0A9H PLO R6 ; R6 = FFA9, screen resolution location LDX STR R6 ; Store resolution on FFA9 (i.e 1 0r 0) SEP R3 ; Restart Chip 8 CTL_L LDI 00H STR R2 ; Stack = 1 which will be used to indicate 2x4 screen resolution BR STORE_SCREEN_RES CHIP8_COMMAND_TABLE DW CHIP8_COMMAND_1 DW CHIP8_COMMAND_2 DW CHIP8_COMMAND_3 DW CHIP8_COMMAND_4 DW CHIP8_COMMAND_5 DW CHIP8_COMMAND_6 DW CHIP8_COMMAND_7 DW CHIP8_COMMAND_8 DW CHIP8_COMMAND_9 DW CHIP8_COMMAND_A DW CHIP8_COMMAND_B DW CHIP8_COMMAND_C DW CHIP8_COMMAND_D_3P DW CHIP8_COMMAND_E DW CHIP8_COMMAND_F DB 00H ;71D4: 00 DB 00H ;71D5: 00 DB 00H ;71D6: 00 DB 00H ;71D7: 00 DB 00H ;71D8: 00 DB 00H ;71D9: 00 DB 00H ;71DA: 00 DB 00H ;71DB: 00 DB 00H ;71DC: 00 DB 00H ;71DD: 00 DB 00H ;71DE: 00 DB 00H ;71DF: 00 CHIP8_START SEX R3 DIS DB 23H ; Disable interrupt, PC = 3, X = 2 INP 7 ; TV OFF LOAD R7,CHIP8_IDENTIFIER LDI 0FFH PHI R6 LDI 0A0H PLO R6 ; R6 = FFA0, FFA0 will contain CHIP8 identifier (CHIP8) if system RAM page (FFxx) is initialized R71F0 LDA R6 STR R2 LDA R7 SM PLO RC ; RC.0 is difference between FFA0 and the CHIP8 identifier BNZ R71FC ; if not zero we have not initialized system RAM page GLO R6 SMI 0A5H BNZ R71F0 ; Idenifier is checked if we reach FFA5, 5 bytes checked R71FC LOAD R7,CHIP8_COMMAND_TABLE LDI 0B2H PLO R6 R7205 LDA R7 STR R6 INC R6 GLO R6 SMI 0D0H BNZ R7205 ; Copy CHIP8 command table to FFB2, we need to have it RAM so we can have two differen D command locations ; depending on screen resolution GLO RC BZ R721A ; Skip ressetting of FFA8 (speed) and FFA9 (resolution) if RAM was already initialized LDI 0A8H PLO R6 LDI 00H STR R6 INC R6 STR R6 ; Reset speed and resolution BR RES_3x5 ; If RAM was not initialized start in 3x5 resolution R721A LDI 0A9H PLO R6 LDN R6 BZ RES_3x5 ; If FFA9 = 0 we need to set 3x5 resolution RES_2x4 LOAD R1,FOURL_INTERRUPT LOAD R7,CHIP8_COMMAND_D_2P BR R723A RES_3x5 LOAD R1,FIVEL_INTERRUPT LOAD R7,CHIP8_COMMAND_D_3P R723A LDI 0CAH PLO R6 ; R6 = location COMMAND D GHI R7 STR R6 INC R6 GLO R7 STR R6 ; Store correct COMMAND D start address which was loaded in R7 above, depending on resolution mode LOAD R5,CHIP8_EXEC ; R5 = CHIP 8 PC = Start address 7000 which contains a clear video RAM and a jump to 200/ 8200. INP 6 ; TV ON SEX R3 RET DB 23H ; Enable interrupt, PC = 3, X = 2 GLO RC BZ R726D ; IF RC = 0 System RAM was initialized so skip keyboard map restore RESTORE_KEY_MAP LDI 00H PLO R6 ; R6 = FF00 start of RAM keyboard map LOAD R7,ROM_KEY_MAP ; R7 = ROM keyboard map R7258 LDA R7 BZ REPEAT_BYTES ; If ROM keyboard map is zero branch to go to repeat bytes STR R6 ; RAM keyboard MAP = ROM keyboard MAP INC R6 BR R7258 ; Next byte REPEAT_BYTES LDA R7 BZ R726D ; If ROM keyboard map has 2 zero's in a row we are 'done' PLO RC ; RC.0 = number of bytes to be repeated R7263 LDN R7 STR R6 ; RAM keyboard MAP = ROM keyboard MAP INC R6 ; Next RAM byte DEC RC ; number of bytes -1 GLO RC BNZ R7263 ; If more bytes loop INC R7 ; Next ROM byte BR R7258 ; Loop back R726D LDI 0A8H PLO R6 ; R6 = FFA8, i.e. speed delay LDN R6 PHI R8 ; R8.1 = Speed delay LDI 0F9H PLO R6 ; R6 = FFF9, i.e keyboard code LDI 7FH STR R6 ; Reset keyboard code as 'no key pressed' ; This loop is fetching the CHIP8 instruction and executing it by a SEP R4, instruction returns with a SEP R3 MAIN_CHIP8_LOOP SEX R2 GHI R6 PHI R7 ; R7.1 = FF LDI 0F9H PLO R6 ; R6 = FFF9, i.e keyboard code LDN R6 PLO R6 ; Get keycode ANI 80H BZ S729E ; If bit 7 = 0 no CTL key is pressed, continue with main loop GLO R6 ; SMI 0F0H BM SPEED_KEY ; If key code between 80-F0 we have a speed key GLO R6 SHL ANI 0FH ORI 0F0H PLO RC LDI 74H PHI RC ; RC = CTL jump table LDN RC ; If jump table contains zero, just assume speed key BNZ CTL_KEY SPEED_KEY LDI 0A8H PLO R7 GLO R6 ANI 7FH STR R7 ; M(R7) = new speed factor PHI R8 ; R8.1 = new speed factor S729E LDI 0FFH PHI RC ; RC.1 = FF LDA R5 PLO RF ; RF.0 = first instruction byte SHR SHR SHR SHR ; D = CHIP8 COMMAND BZ CHIP8_COMMAND_0 PLO R6 ; R6.0 = CHIP8 COMMAND SMI 0DH BZ R72B6 ; If COMMAND D skip delay for speed GHI R8 BZ R72B6 ; If R8 (speed delay) is zero continue loop PLO RC SPEED_DELAY DEC RC GLO RC BNZ SPEED_DELAY ; WAIT according to speed delay R72B6 GLO R6 SHL ADI 0B0H PLO RC ; RC = CHIP8 COMMAND table pointing to current instruction address (FFB2-FFCF) GLO RF ANI 0FH ORI 0E0H PLO R6 ; R6 = Vx (FFEx, i.e FFE0-FFEF) LDN R5 SHR SHR SHR SHR ORI 0E0H PLO R7 ; R6 = Vy (FFEy, i.e FFE0-FFEF) CTL_KEY LDA RC PHI R4 LDN RC J72CC PLO R4 ; R4 = Instruction address (or CTL_KEY address) SEP R4 ; Execute! BR MAIN_CHIP8_LOOP ; SYS aaa -> Call CDP1802 code at aaa CHIP8_COMMAND_0 GLO RF ANI 0FH BZ CHIP8_COMMAND_00 ORI 80H ; SYS 1aa to SYS Faa will branch to 8aaa, as CHIP8 user program is stored at 8200 instead of 200 BR R72DB CHIP8_COMMAND_00 ADI 70H ; SYS 00aa, the original 00aa routines are located on 70aa in VIP2K Chip 8 R72DB PHI R4 LDA R5 BR J72CC ; R4 = aaa, with additional changes as above. Then 'Execute' CTL_Q SEX R4 DIS DB 04H ; Disable interrupt, PC = 4, X = 0 INP 7 ; TV OFF LDI 00H PHI R0 PLO R0 ; R0 = 0 SEP R0 ; Restart VIP2K Monitor ; DRW Vx, Vy, n -> Draw n byte sprite stored at [I] at Vx, Vy. Set VF = collision ; Drawing routine to draw a pattern of bytes where every bit will result in 3 pixels ; This routine is used for the small screen resolution, i.e. 2x4 CHIP8_COMMAND_D_3P DEC R2 ; R2 = R2 - 1 to have stack ready for a push LDN R6 ANI 3FH STR R2 ; Stack = Vx, horizontal drawing position ADD ADD STR R2 ; Stack = 3*Vx as we want three pixels wide so horizontal position is also tripled ANI 07H PHI RD ; RD.1 containts the number of bits left to shift later as byte contains 8 bits, i.e. 8 positions LDN R2 ; Get 3xVx SHR SHR SHR ; D = 3*Vx/8, so we can identify the 'byte' position in memory ADI 4FH PLO RC LDI 0E8H PHI RC ; RC = horizontal screen location, we have added E84F as that is the memory location of top left of screen ; We don't use E800 so the viewable screen is in the 'middle' LDN R7 ANI 1FH PLO RD ; RD.0 = Vy, vertical drwaing position SHL PLO RE ; RE.0 = Vy * 2 LDI 76H PHI RE ; RE.1 = 76, resulting in M(RE) containing the value to be added to get the horizontal poitions ; Table at 7600 contains 32 16 bit values low byte first followed by high for all 32 lines SEX RE GLO RC ADD ; Add low byte PLO RC INC RE GHI RC ADC ; Add high byte + carry from low PHI RC ; RC is drawing position in memory LDA R5 ANI 0FH PLO RD ; RD.0 = number of lines to be drawn PLO R8 ; R8.0 = number of lines to be drawn LDI 0EFH PLO R6 ; R6 = VF for storing of collision flag LDI 00H STR R6 ; VF / collision flag = 0, i.e. no graphic collision detected as yet J7319 GLO R8 ;7319: 88 BZ CHIP8_COMMAND_D_3P_END ; All lines drawn, finalize routine DEC R8 ; Number of lines - 1 LOAD RE,PATTERN_3x5 ; RE = Pattern table LDI 0F3H PLO R7 ; R7 = FFF3, FFF0-FFF3 will contain 32 bit pattern based on byte to be drawn. ; Reason to use 32 bit is that every bit needs to be drawn as 3 pixels and could be shifted right max 8 pixels SEX R7 LDI 00H STXD STXD STXD STR R7 ; FFF0-FFF3 = 0, pattern reset LDA RA PHI RF ; RF.1 = byte to be drawn (M(RA) or M(I), RA/I is incremented for next byte) R732F GHI RF SHR ; DF = first bit, 1 means a pixels should be drawn PHI RF ; RF is shifted right 1 bit so next time we take the next bit into DF BDF CHIP8_COMMAND_D_3P_DRAW INC RE INC RE INC RE ; Increment pattern table BR R7345 ;7337: 30 45 CHIP8_COMMAND_D_3P_DRAW LDI 0F2H PLO R7 ; R7 = FFF2 LDA RE ; Get last byte for 3 pixel pattern for current bit OR STXD ; OR result on pattern location LDA RE ; Get second byte for 3 pixel pattern for current bit OR STXD ; OR result on pattern location LDA RE ; Get first byte for 3 pixel pattern for current bit OR STR R7 ; OR result on pattern location R7345 GLO RE SMI 5CH ; Check if all bits are done (end of 3 pixel pattern table is xx5C) BNZ R732F ; if not done, loop back for next bit LDI 00H PLO RF ; RF.0 = 0, don't think this was needed, maybe we can remove it in a later version? GHI RD PLO RE ; RE.0 number of bits to shift to get the final horizontal position R734F GLO RE BZ S7367 ; If RE.0 = 0 we are ready shifting LDI 0F0H PLO R7 ; R7 = FFF0 LDN R7 SHR STR R7 ; Shift first byte one right INC R7 LDN R7 SHRC STR R7 ; Shift second byte one right INC R7 LDN R7 SHRC STR R7 ; Shift third byte one right INC R7 LDN R7 SHRC STR R7 ; Shift fourth byte one right DEC RE ; Decrement number of bits to be shifted BR R734F ; Loop back S7367 LDI 0F0H PLO R7 ; R7 = FFF0, which now contains the 24 bit pattern to be drawn on the first line SEX RC LDN R7 AND ; AND first byte pattern to be drawn with video memory BZ R7372 ; If zero we have no collision with what is already on the screen LDI 01H STR R6 ; If not zero set the collision flag R7372 LDA R7 XOR STR RC ; XOR first byte pattern to be drawn with video memory and store it back in video memory INC RC ; RC = next screen position LDN R7 AND ; AND second byte pattern to be drawn with video memory BZ R737D ; If zero we have no collision with what is already on the screen LDI 01H STR R6 ; If not zero set the collision flag R737D LDA R7 XOR STR RC ; XOR second byte pattern to be drawn with video memory and store it back in video memory INC RC ; RC = next screen position LDN R7 AND ; AND third byte pattern to be drawn with video memory BZ R7388 ; If zero we have no collision with what is already on the screen LDI 01H STR R6 ; If not zero set the collision flag R7388 LDA R7 XOR STR RC ; XOR third byte pattern to be drawn with video memory and store it back in video memory INC RC ; RC = next screen position LDN R7 AND ; AND fourth byte pattern to be drawn with video memory BZ R7393 ; If zero we have no collision with what is already on the screen LDI 01H STR R6 ; If not zero set the collision flag R7393 LDA R7 XOR STR RC ; XOR fourth byte pattern to be drawn with video memory and store it back in video memory GLO RC ADI 17H PLO RC GHI RC ADCI 00H PHI RC ; RC = next line (RC + 0x17) BR J7319 ; Loop back CHIP8_COMMAND_D_3P_END SEX R2 GLO RD STR R2 ; Stack = number of lines dranw GLO RA SM PLO RA GHI RA SMBI 00H PHI RA ; RA = RA - number of lines drawn, i.e. reset RA to what it was at entry INC R2 ; Set stack back SEP R3 ; CALL aaa -> Call subroutine at aaa CHIP8_COMMAND_2 INC R5 GLO R5 DEC R2 STXD GHI R5 STR R2 DEC R5 ; Store CHIP 8 PC (R5) on stack, which will be restored at RETURN ; JP aaa -> Jump to address aaa CHIP8_COMMAND_1 LDA R5 PLO R5 GLO R6 ANI 0FH ORI 80H PHI R5 ; R5 = CHIP 8 PC = aaa + 8000, 8000 is added as Chip 8 code on VIP2K is stored at 8200 instead of 200 SEP R3 ; JP V0, aaa -> Jump to address aaa + V0 CHIP8_COMMAND_B LDI 0E0H PLO R7 ; R7 = V0 SEX R7 LDA R5 ADD ; Add V0 PLO R5 GLO R6 ANI 0FH ORI 80H BNF R73CC ADI 01H R73CC PHI R5 ; R5 = CHIP 8 PC = aaa + V0 8000, 8000 is added as Chip 8 code on VIP2K is stored at 8200 instead of 200 SEP R3 ;73CD: D3 ; LD Vx, kk -> Vx = kk CHIP8_COMMAND_6 LDA R5 ; Get kk STR R6 ; M(R6) = Vx = kk SEP R3 ; ADD Vx, kk -> Vx = Vx + kk CHIP8_COMMAND_7 LDA R5 ; Get kk SEX R6 ADD STR R6 ; M(R6) = Vx = Vx + kk SEP R3 ; LD, OR, AND, XOR etc (like Fx 1802 instrucions) Vx, Vy CHIP8_COMMAND_8 LDA R5 ; Get second instuction byte ANI 0FH BNZ R73DE ; Branch for all instructions except 8xy0 LDN R7 STR R6 ; M(R6) = Vx = Vy SEP R3 R73DE PLO RF ; RF.0 is command type (last nibble) DEC R2 LDI 0D4H ; STXD ; Store SEP R4 on stack GLO RF ORI 0F0H STR R2 ; Store command type as 1802 instruction on stack Fz SEX R6 ; Stack = Vx LDN R7 ; D = Vy SEP R2 ; Execute 1802 instruction Fz and then return with SEP R4 to S73EA S73EA STR R6 LDI 0EFH PLO R6 ; R6 = VF, carry flag LDI 00H SHLC STR R6 ; Store carry SEP R3 ;73F2: D3 ; RND Vx , kk -> Vx = random AND kk CHIP8_COMMAND_C INC R9 ; R9 is the random number generator, incremented at every interrupt and on command C, ; just in case no interrupt happend. GLO R9 PLO RE ; RE.0 is random number GHI R4 PHI RE ; RE.1 = R4.1 = 73, RE is a random location in page 73 GHI R9 SEX RE ADD ; Add value on RE to high byte of random number STR R6 ; Store in Vx SHRC ; Divide by 2 SEX R6 ADD ; Add Vx PHI R9 ; Save in R9.1 STR R6 ; Store in Vx LDA R5 AND ; AND with kk STR R6 ; Store in Vx SEP R3 ; LD I, aaa -> I = aaa CHIP8_COMMAND_A LDA R5 PLO RA GLO R6 ANI 0FH ORI 80H PHI RA ; RA = aaa + 8000, 8000 is added as Chip 8 code on VIP2K is stored at 8200 instead of 200 SEP R3 FIVEL_INTERRUPT_END INC R2 LDA R2 PLO R6 ; Pull R6.0 from stack LDA R2 SHL LDA R2 RET FIVEL_INTERRUPT DEC R2 SAV ; --- DMA burst for first 'single' display line, should be empty (from video RAM EBF6-EC0F) DEC R2 STXD SHRC ; --- DMA burst for second 'single' display line, should be empty (from video RAM EC10-EC29) STXD INC R9 ; Increment R9 which is used in Chip 8 for random number generation GLO R6 ; --- DMA burst for third 'single' display line, should be empty (from video RAM EC2A-EC43) STXD ; Push R6.0 to stack LDI 09H PLO R6 ; R6.0 = 9 line counter (9 lines until R0.1 carry) ; --- DMA burst for fourth 'single' display line, should be empty (from video RAM EC44-EC5D) LDI 0E8H ; PHI RB ; RB.1 = start of video RAM IDL ; re-sync DMAs, just in case.... ; --- DMA burst for fifth 'single' display line, should be empty (from video RAM EC5E-EC77) PHI R0 ; R0.1 = start of video RAM LDI 00H PLO R0 ; R0.0 = start of video RAM ; --- DMA burst for display line 1, same line will be repeated 5 times FIVEL_DISPLAY_9 PLO RB ; RB.0 = R0.0 so it can be used to reset R0.0 later PLO R0 ; Reset R0.0 DEC R6 ; decrement line count ; --- DMA burst for display line 2 FIVEL_DISPLAY_8 PLO R0 ; Reset R0.0 GHI R0 PHI RB ; RB.1 = R0.1 so it can be used to reset R0.1 later ; --- DMA burst for display line 3 GLO RB ; D was equal to R0.1 so we have to fetch RB.0 PLO R0 ; Reset R0.0 PLO R0 ; dummy / NOP ; --- DMA burst for display line 4 PLO R0 ; Reset R0.0 GLO R6 ; Get line count SMI 01H ; set DF if last line ; --- DMA burst for display line 5 GLO R0 PLO RB ; RB.0 = R0.0 so it can be used for line 10 if needed BPZ FIVEL_DISPLAY_9 ; Loop for 9 lines ; -- DMA burst for display line 1 - 10th line FIVEL_DISPLAY_10 PLO R0 ; Reset R0.0 GHI RB PHI R0 ; Reset R0.1 ; -- DMA burst for display line 2 - 10th line PHI R0 ; Reset R0.1 GLO RB PLO R0 ; Reset R0.0 ; -- DMA burst for display line 3 - 10th line PLO R0 ; Reset R0.0 GHI RB PHI R0 ; Reset R0.1 ; -- DMA burst for display line 4 - 10th line PHI R0 ; Reset R0.1 GLO RB PLO R0 ; Reset R0.0 ; -- DMA burst for display line 5 - 10th line LDI 08H ; PLO R6 ; R6.0 = 8 line counter ; 9 lines until R0.1 carry but load 8 as we skip the first DEC R6 as we branch to FIVEL_DISPLAY_8 GLO R0 ; -- DMA burst for display line 1 - 11th line PLO RB ; RB.0 = R0.0 so it can be used to reset R0.0 later PLO R0 ; Reset R0.0 B1 FIVEL_DISPLAY_8 ; Reason to do this additional line here is because we need 1 additional instruction (B1) ; to branch back which makes us skip one DEC R9. LDI 0FAH PLO R6 ; R6 = FFFA, R6.1 is always FF in Chip 8 LDN R6 ; D = countdown counter BZ FIVEL_COUNTER0 ; Do nothing if counter = 0 SMI 01H STR R6 ; Countdown counter - 1 FIVEL_COUNTER0 DEC R6 ; R6 = FFF9, keyboard code LDI 0FFH PHI RB LDI 00H PLO RB ; RB = Keyboard mapping table, FF00 BN3 FIVEL_NO_SHIFT ADI 50H PLO RB ; RB = SHIFT area keyboard mapping table FIVEL_NO_SHIFT BN2 FIVEL_NO_CTL GLO RB ADI 28H PLO RB ; RB = CTL area keyboard mapping table FIVEL_NO_CTL INP 1 SMI 0FFH BNZ FIVEL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 1 INP 2 SMI 0FFH BNZ FIVEL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 2 INP 3 SMI 0FFH BNZ FIVEL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 3 INP 4 SMI 0FFH BNZ FIVEL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 4 INP 5 SMI 0FFH BZ FIVEL_NO_KEY_PRESS FIVEL_KEY_PRESS LDX R7493 SHL BNF R7499 INC RB BR R7493 R7499 LDN RB ; Get keyboard code STR R6 ; Store keyboard code on FFF9 BR FIVEL_INTERRUPT_END FIVEL_NO_KEY_PRESS LDI 7FH STR R6 ; 'Clear' keyboard code on FFF9 BR FIVEL_INTERRUPT_END DB 00H ;74A2: 00 DB 00H ;74A3: 00 DB 00H ;74A4: 00 DB 00H ;74A5: 00 DB 00H ;74A6: 00 DB 00H ;74A7: 00 DB 00H ;74A8: 00 DB 00H ;74A9: 00 DB 00H ;74AA: 00 DB 00H ;74AB: 00 DB 00H ;74AC: 00 DB 00H ;74AD: 00 DB 00H ;74AE: 00 DB 00H ;74AF: 00 DB 00H ;74B0: 00 DB 00H ;74B1: 00 DB 00H ;74B2: 00 DB 00H ;74B3: 00 DB 00H ;74B4: 00 DB 00H ;74B5: 00 DB 00H ;74B6: 00 DB 00H ;74B7: 00 DB 00H ;74B8: 00 DB 00H ;74B9: 00 DB 00H ;74BA: 00 DB 00H ;74BB: 00 DB 00H ;74BC: 00 DB 00H ;74BD: 00 DB 00H ;74BE: 00 DB 00H ;74BF: 00 DB 00H ;74C0: 00 DB 00H ;74C1: 00 DB 00H ;74C2: 00 DB 00H ;74C3: 00 DB 00H ;74C4: 00 DB 00H ;74C5: 00 DB 00H ;74C6: 00 DB 00H ;74C7: 00 DB 00H ;74C8: 00 DB 00H ;74C9: 00 DB 00H ;74CA: 00 DB 00H ;74CB: 00 DB 00H ;74CC: 00 DB 00H ;74CD: 00 DB 00H ;74CE: 00 DB 00H ;74CF: 00 DB 00H ;74D0: 00 DB 00H ;74D1: 00 DB 00H ;74D2: 00 DB 00H ;74D3: 00 DB 00H ;74D4: 00 DB 00H ;74D5: 00 DB 00H ;74D6: 00 DB 00H ;74D7: 00 DB 00H ;74D8: 00 DB 00H ;74D9: 00 DB 00H ;74DA: 00 DB 00H ;74DB: 00 DB 00H ;74DC: 00 DB 00H ;74DD: 00 DB 00H ;74DE: 00 DB 00H ;74DF: 00 DB 00H ;74E0: 00 DB 00H ;74E1: 00 DB 00H ;74E2: 00 DB 00H ;74E3: 00 DB 00H ;74E4: 00 DB 00H ;74E5: 00 DB 00H ;74E6: 00 DB 00H ;74E7: 00 DB 00H ;74E8: 00 DB 00H ;74E9: 00 DB 00H ;74EA: 00 DB 00H ;74EB: 00 DB 00H ;74EC: 00 DB 00H ;74ED: 00 DB 00H ;74EE: 00 DB 00H ;74EF: 00 ; Branch table for Keyboard codes F0-F4 @ 74F0 DW CTL_R ; Keyboard code F0 - CTL R DW CTL_Q ; Keyboard code F1 - CTL Q DW CTL_K ; Keyboard code F2 - CTL K DW CTL_L ; Keyboard code F3 - CTL L DW CTL_S ; Keyboard code F4 - CTL S DB 00H ;74FA: 00 DB 00H ;74FB: 00 DB 00H ;74FC: 00 DB 00H ;74FD: 00 DB 00H ;74FE: 00 DB 00H ;74FF: 00 ; Chip 8 character table pointers @ 7500 DB 30H ; 0 -> 7530 DB 39H ; 1 -> 7539 DB 22H ; 2 -> 7522 DB 2AH ; 3 -> 752A DB 3EH ; 4 -> 753E DB 20H ; 5 -> 7520 DB 24H ; 6 -> 7524 DB 34H ; 7 -> 7534 DB 26H ; 8 -> 7526 DB 28H ; 9 -> 7528 DB 2EH ; A -> 752E DB 18H ; B -> 7518 DB 14H ; C -> 7514 DB 1CH ; D -> 751C DB 10H ; E -> 7510 DB 12H ; F -> 7512 ; Chip 8 charcater table @ 7510 DB 0F0H ;7510: F0 DB 80H ;7511: 80 DB 0F0H ;7512: F0 DB 80H ;7513: 80 DB 0F0H ;7514: F0 DB 80H ;7515: 80 DB 80H ;7516: 80 DB 80H ;7517: 80 DB 0F0H ;7518: F0 DB 50H ;7519: 50 DB 70H ;751A: 70 DB 50H ;751B: 50 DB 0F0H ;751C: F0 DB 50H ;751D: 50 DB 50H ;751E: 50 DB 50H ;751F: 50 DB 0F0H ;7520: F0 DB 80H ;7521: 80 DB 0F0H ;7522: F0 DB 10H ;7523: 10 DB 0F0H ;7524: F0 DB 80H ;7525: 80 DB 0F0H ;7526: F0 DB 90H ;7527: 90 DB 0F0H ;7528: F0 DB 90H ;7529: 90 DB 0F0H ;752A: F0 DB 10H ;752B: 10 DB 0F0H ;752C: F0 DB 10H ;752D: 10 DB 0F0H ;752E: F0 DB 90H ;752F: 90 DB 0F0H ;7530: F0 DB 90H ;7531: 90 DB 90H ;7532: 90 DB 90H ;7533: 90 DB 0F0H ;7534: F0 DB 10H ;7535: 10 DB 10H ;7536: 10 DB 10H ;7537: 10 DB 10H ;7538: 10 DB 60H ;7539: 60 DB 20H ;753A: 20 DB 20H ;753B: 20 DB 20H ;753C: 20 DB 70H ;753D: 70 DB 0A0H ;753E: A0 DB 0A0H ;753F: A0 DB 0F0H ;7540: F0 DB 20H ;7541: 20 DB 20H ;7542: 20 DB 00H ;7543: 00 ; Pattern table used to convert 8 bit pattern to 3 pixels per bit PATTERN_3x5 DB 07H ;7544: 07 DB 00H ;7545: 00 DB 00H ;7546: 00 DB 38H ;7547: 38 DB 00H ;7548: 00 DB 00H ;7549: 00 DB 0C0H ;754A: C0 DB 01H ;754B: 01 DB 00H ;754C: 00 DB 00H ;754D: 00 DB 0EH ;754E: 0E DB 00H ;754F: 00 DB 00H ;7550: 00 DB 70H ;7551: 70 DB 00H ;7552: 00 DB 00H ;7553: 00 DB 80H ;7554: 80 DB 03H ;7555: 03 DB 00H ;7556: 00 DB 00H ;7557: 00 DB 1CH ;7558: 1C DB 00H ;7559: 00 DB 00H ;755A: 00 DB 0E0H ;755B: E0 ; Pattern table used to convert 8 bit pattern to 2 pixels per bit PATTERN_2x4 DB 03H ;755C: 03 DB 00H ;755D: 00 DB 0CH ;755E: 0C DB 00H ;755F: 00 DB 30H ;7560: 30 DB 00H ;7561: 00 DB 0C0H ;7562: C0 DB 00H ;7563: 00 DB 00H ;7564: 00 DB 03H ;7565: 03 DB 00H ;7566: 00 DB 0CH ;7567: 0C DB 00H ;7568: 00 DB 30H ;7569: 30 DB 00H ;756A: 00 DB 0C0H ;756B: C0 FOURL_INTERRUPT_END INC R2 LDA R2 PLO R6 ; Pull R6.0 from stack LDA R2 SHL LDA R2 RET FOURL_INTERRUPT DEC R2 SAV ; --- DMA burst for first 'single' display line, should be empty (from video RAM ECFA-ED13) DEC R2 STXD SHRC ; --- DMA burst for second 'single' display line, should be empty (from video RAM ED14-ED2D) STXD INC R9 ; Increment R9 which is used in Chip 8 for random number generation GLO R6 ; --- DMA burst for third 'single' display line, should be empty (from video RAM ED2E-ED47) STXD ; Push R6.0 to stack LDI 09H PLO R6 ; R6.0 = 9 line counter (9 lines until R0.1 carry) ; --- DMA burst for fourth 'single' display line, should be empty (from video RAM ED48-ED61) LDI 00H PLO RB ; RB.0 = 0 so it can be used to reset R0.0 later LDI 0E8H ; --- DMA burst for fifth 'single' display line, should be empty (from video RAM ED62-ED7B) PHI RB ; RB.1 = start of video RAM IDL ; re-sync DMAs ; --- DMA burst for fifth 'single' display line, should be empty (from video RAM ED7C-ED95) PHI R0 ; R0.1 = start of video RAM LDI 00H PLO R0 ; R0.0 = start of video RAM ; --- DMA burst for display line 1, same line will be repeated 4 times FOURL_DISPLAY_9 PLO R0 ; Reset R0.0 DEC R6 ; decrement line count GHI R0 ; --- DMA burst for display line 2 FOURL_DISPLAY_8 PHI RB ; RB.1 = R0.1 so it can be used to reset R0.1 later GLO RB PLO R0 ; Reset R0.0 ; --- DMA burst for display line 3 PLO R0 ; Reset R0.0 GLO R6 ; Get line count SMI 01H ; set DF if last line ; --- DMA burst for display line 4 GLO R0 PLO RB ; RB.0 = R0.0 so it can be used for line 10 if needed BPZ FOURL_DISPLAY_9 ; Loop for 9 lines ; -- DMA burst for display line 1 - 10th line FOURL_DISPLAY_10 PLO R0 ; Reset R0.0 GHI RB PHI R0 ; Reset R0.1 ; -- DMA burst for display line 2 - 10th line PHI R0 ; Reset R0.1 GLO RB PLO R0 ; Reset R0.0 ; -- DMA burst for display line 3 - 10th line PLO R0 ; Reset R0.0 GHI RB PHI R0 ; Reset R0.1 ; -- DMA burst for display line 4 - 10th line LDI 08H PLO R6 ; R6.0 = 8 line counter GLO R0 ; -- DMA burst for display line 1 - 11th line PLO RB ; RB.0 = R0.0 so it can be used to reset R0.0 later PLO R0 ; Reset R0.0 B1 FOURL_DISPLAY_8 ; Reason to do this additional line here is because we need 1 additional instruction (B1) ; to branch back which makes us skip one DEC R9. LDI 0FAH PLO R6 ; R6 = FFFA, R6.1 is always FF in Chip 8 LDN R6 ; D = countdown counter BZ FOURL_COUNTER0 ; Do nothing if counter = 0 SMI 01H STR R6 ; Countdown counter - 1 FOURL_COUNTER0 DEC R6 ; R6 = FFF9, keyboard code LDI 0FFH PHI RB LDI 00H PLO RB ; RB = Keyboard mapping table, FF00 BN3 FOURL_NO_SHIFT ADI 50H PLO RB ; RB = SHIFT area keyboard mapping table FOURL_NO_SHIFT BN2 FOURL_NO_CTL GLO RB ADI 28H PLO RB ; RB = CTL area keyboard mapping table FOURL_NO_CTL INP 1 SMI 0FFH BNZ FOURL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 1 INP 2 SMI 0FFH BNZ FOURL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 2 INP 3 SMI 0FFH BNZ FOURL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 3 INP 4 SMI 0FFH BNZ FOURL_KEY_PRESS GLO RB ADI 08H PLO RB ; RB = Keycol 4 INP 5 SMI 0FFH BZ FOURL_NO_KEY_PRESS FOURL_KEY_PRESS LDX R75EE SHL BNF R75F4 INC RB BR R75EE R75F4 LDN RB ; Get keyboard code STR R6 ; Get keyboard code BR FOURL_INTERRUPT_END FOURL_NO_KEY_PRESS LDI 7FH STR R6 ; 'Clear' keyboard code on FFF9 BR FOURL_INTERRUPT_END DB 00H ;75FD: 00 DB 00H ;75FE: 00 DB 00H ;75FF: 00 ; Line location table low byte followed by high byte DB 00H ;7600: 00 DB 00H ;7601: 00 DB 1AH ;7602: 1A DB 00H ;7603: 00 DB 34H ;7604: 34 DB 00H ;7605: 00 DB 4EH ;7606: 4E DB 00H ;7607: 00 DB 68H ;7608: 68 DB 00H ;7609: 00 DB 82H ;760A: 82 DB 00H ;760B: 00 DB 9CH ;760C: 9C DB 00H ;760D: 00 DB 0B6H ;760E: B6 DB 00H ;760F: 00 DB 0D0H ;7610: D0 DB 00H ;7611: 00 DB 0EAH ;7612: EA DB 00H ;7613: 00 DB 04H ;7614: 04 DB 01H ;7615: 01 DB 1EH ;7616: 1E DB 01H ;7617: 01 DB 38H ;7618: 38 DB 01H ;7619: 01 DB 52H ;761A: 52 DB 01H ;761B: 01 DB 6CH ;761C: 6C DB 01H ;761D: 01 DB 86H ;761E: 86 DB 01H ;761F: 01 DB 0A0H ;7620: A0 DB 01H ;7621: 01 DB 0BAH ;7622: BA DB 01H ;7623: 01 DB 0D4H ;7624: D4 DB 01H ;7625: 01 DB 0EEH ;7626: EE DB 01H ;7627: 01 DB 08H ;7628: 08 DB 02H ;7629: 02 DB 22H ;762A: 22 DB 02H ;762B: 02 DB 3CH ;762C: 3C DB 02H ;762D: 02 DB 56H ;762E: 56 DB 02H ;762F: 02 DB 70H ;7630: 70 DB 02H ;7631: 02 DB 8AH ;7632: 8A DB 02H ;7633: 02 DB 0A4H ;7634: A4 DB 02H ;7635: 02 DB 0BEH ;7636: BE DB 02H ;7637: 02 DB 0D8H ;7638: D8 DB 02H ;7639: 02 DB 0F2H ;763A: F2 DB 02H ;763B: 02 DB 0CH ;763C: 0C DB 03H ;763D: 03 DB 26H ;763E: 26 DB 03H ;763F: 03 ; ROM Keyboard mapping table which is copied to FF00 on start-up. ; When a 00 is used the folloing byte indicates how many time the third byte should be repeated ROM_KEY_MAP DB 06H ;7640: 06 DB 7FH ;7641: 7F DB 7FH ;7642: 7F DB 7FH ;7643: 7F DB 0BH ;7644: 0B DB 7FH ;7645: 7F DB 7FH ;7646: 7F DB 05H ;7647: 05 DB 07H ;7648: 07 DB 7FH ;7649: 7F DB 04H ;764A: 04 DB 08H ;764B: 08 DB 7FH ;764C: 7F DB 0FH ;764D: 0F DB 7FH ;764E: 7F DB 04H ;764F: 04 DB 08H ;7650: 08 DB 02H ;7651: 02 DB 06H ;7652: 06 DB 7FH ;7653: 7F DB 0CH ;7654: 0C DB 0DH ;7655: 0D DB 0EH ;7656: 0E DB 03H ;7657: 03 DB 09H ;7658: 09 DB 7FH ;7659: 7F DB 7FH ;765A: 7F DB 05H ;765B: 05 DB 7FH ;765C: 7F DB 7FH ;765D: 7F DB 7FH ;765E: 7F DB 02H ;765F: 02 DB 00H ;7660: 00 DB 01H ;7661: 01 DB 00H ;7662: 00 DB 00H ;7663: 00 DB 04H ;7664: 04 DB 7FH ;7665: 7F DB 0AH ;7666: 0A DB 7FH ;7667: 7F DB 01H ;7668: 01 DB 92H ;7669: 92 DB 00H ;766A: 00 DB 06H ;766B: 06 DB 7FH ;766C: 7F DB 98H ;766D: 98 DB 8CH ;766E: 8C DB 00H ;766F: 00 DB 05H ;7670: 05 DB 7FH ;7671: 7F DB 0F0H ;7672: F0 DB 9EH ;7673: 9E DB 86H ;7674: 86 DB 7FH ;7675: 7F DB 0F2H ;7676: F2 DB 00H ;7677: 00 DB 04H ;7678: 04 DB 7FH ;7679: 7F DB 0A4H ;767A: A4 DB 80H ;767B: 80 DB 7FH ;767C: 7F DB 0F3H ;767D: F3 DB 7FH ;767E: 7F DB 7FH ;767F: 7F DB 0F4H ;7680: F4 DB 7FH ;7681: 7F DB 0AAH ;7682: AA DB 00H ;7683: 00 DB 06H ;7684: 06 DB 7FH ;7685: 7F DB 0F1H ;7686: F1 DB 0B0H ;7687: B0 DB 00H ;7688: 00 DB 50H ;7689: 50 DB 7FH ;768A: 7F CHIP8_IDENTIFIER DB 'CHIP8' ;768B: 43 ;768C: 48 ;768D: 49 ;768E: 50 ;768F: 38 END