Created
November 23, 2020 10:39
-
-
Save tobiasvl/486e81543c27107f40d6f76c89202a1c to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; ******************************************************************* | |
; *** *** | |
; *** VIP2K Chip 8 interpreter *** | |
; *** *** | |
; *** This software is copyright 2008 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment