; *******************************************************************
; ***                                                             ***
; ***                 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
