CHIP-8-Interpreter

Das ist der komplette(!) originale CHIP-8-Interpreter des COSMAC VIP. Quelle: VIPER-Magazin 1-02 August 1978.

Der CHIP-8-Interpreter ist extrem platzsparend programmiert, er belegt nicht einmal 0.5 KByte! Diese Kompaktheit spiegelt sich beispielsweise auch in den Hex-Werten der Maschinencode-Instruktionen wieder: Die Befehle der F-Gruppe haben einen zweistellige Nummer, diese entspricht der Startadresse der zugehörigen Befehlsinterpretation. Damit sparte man sich die Bytes für eine zusätzliche Sprungtabelle.

Das Handbuch zum COSMAC VIP enthält auch das Datenblatt zum Prozessor CDP 1802 incl. Befehlsliste.

COSMAC Register Summary

D 	8 Bits 	Data Register (Accumulator)
N 	4 Bits 	Holds Low-Order Instr. Digit
DF 	1 Bit 	Data Flag (ALU Carry)
I 	4 Bits 	Holds High-Order Instr. Digit
R 	16 Bits 1 of 16 Scratchpad Registers
  R0.1 R0.0
  R1.1 R1.0
  ...
  RF.1 RF.0
T 	8 Bits 	Holds old X, P after Interrupt (X is high byte)
P 	4 Bits 	Designates which register is Program Counter
                   zeigt auf Registerarray
IE 	1 Bit 	Interrupt Enable
X 	4 Bits 	Designates which register is Data Pointer
                   zeigt auf Registerarray
Q 	1 Bit 	Output Flip Flop

instruction set

MNEM    NAME                                    OPCODE
ADC     Add with Carry                          74
ADCI b  Add with Carry Immediate                7C bb
ADD     Add                                     F4
ADI b   Add Immediate                           FC bb
AND     Logical AND                             F2
ANI b   AND Immediate                           FA bb
B1 a    Branch on External Flag 1               34 aa
B2 a    Branch on External Flag 2               35 aa
B3 a    Branch on External Flag 3               36 aa
B4 a    Branch on External Flag 4               37 aa
BDF a   Branch if DF is 1                       33 aa
BN1 a   Branch on Not External Flag 1           3C aa
BN2 a   Branch on Not External Flag 2           3D aa
BN3 a   Branch on Not External Flag 3           3E aa
BN4 a   Branch on Not External Flag 4           3F aa
BNF a   Branch if DF is 0                       3B aa
BNQ a   Branch if Q is off                      39 aa
BNZ a   Branch on Not Zero                      3A aa
BQ a    Branch if Q is on                       31 aa
BR a    Branch unconditionally                  30 aa
BZ a    Branch on Zero                          32 aa
DEC r   Decrement Register                      2r
DIS     Return and Disable Interrupts           71
GHI r   Get High byte of Register               9r
GLO r   Get Low byte of Register                8r
IDL     Idle                                    00
INC r   Increment Register                      1r
INP p   Input to memory and D (for p = 9 to F)  6p
IRX     Increment R(X)                          60
LBDF aa Long Branch if DF is 1                  C3 aaaa
LBNF aa Long Branch if DF is 0                  CB aaaa
LBNQ aa Long Branch if Q is off                 C9 aaaa
LBNZ aa Long Branch if Not Zero                 CA aaaa
LBQ aa  Long Branch if Q is on                  C1 aaaa
LBR aa  Long Branch unconditionally             C0 aaaa
LBZ aa  Long Branch if Zero                     C2 aaaa
LDA r   Load D and Advance                      4r
LDI b   Load D Immediate                        F8 bb
LDN r   Load D via N (for r = 1 to F)           0r
LDX     Load D via R(X)                         F0
LDXA    Load D via R(X) and Advance             72
LSDF    Long Skip if DF is 1                    CF
LSIE    Long Skip if Interrupts Enabled         CC
LSKP    Long Skip                               C8
LSNF    Long Skip if DF is 0                    C7
LSNQ    Long Skip if Q is off                   C5
LSNZ    Long Skip if Not Zero                   C6
LSQ     Long Skip if Q is on                    CD
LSZ     Long Skip if Zero                       CE
MARK    Save X and P in T                       79
NOP     No Operation                            C4
OR      Logical OR                              F1
ORI b   OR Immediate                            F9 bb
OUT p   Output from memory (for p = 1 to 7)     6p
PHI r   Put D in High byte of register          Br
PLO r   Put D in Low byte of register           Ar
REQ     Reset Q                                 7A
RET     Return                                  70
SAV     Save T                                  78
SD      Subtract D from memory                  F5
SDB     Subtract D from memory with Borrow      75
SDBI b  Subtract D with Borrow, Immediate       7D bb
SDI b   Subtract D from memory Immediate byte   FD bb
SEP r   Set P                                   Dr
SEQ     Set Q                                   7B
SEX r   Set X                                   Er
SHL     Shift D Left                            FE
SHLC    Shift D Left with Carry                 7E
SHR     Shift D Right                           F6
SHRC    Shift D Right with Carry                76
SKP     Skip one byte                           38
SM      Subtract Memory from D                  F7
SMB     Subtract Memory from D with Borrow      77
SMBI b  Subtract Memory with Borrow, Immediate  7F bb
SMI b   Subtract Memory from D, Immediate       FF bb
STR r   Store D into memory                     5r
STXD    Store D via R(X) and Decrement          73
XOR     Exclusive OR                            F3
XRI b   Exclusive OR, Immediate                 FB bb

2023: s.a. https://laurencescotford.com/chip-8-on-the-cosmac-vip-index/ An in-depth disassembly and analysis of the original CHIP-8 interpreter on the COSMAC VIP.

		; J.W. Wentworth's Analysis of VIP CHIP 8 Interpreter
		; retyped vp130331

		cpu	1802
		
		; '*' before opcode marks branch destination

0000: 91	  GHI  R1	; 0X ->	RB.1 (where 0X is then highest memory page no. as determined
0001: BB	  PHI  RB	; by Operating System) -- designates display page
0002: FF 01	  SMI  01h	; 0X-1 -> R2.1 (stack pointer)
0004: B2	  PHI  R2
0005: B6	  PHI  R6	; 0X-1 -> R6.1 (VX pointer)
0006: F8 CF	  LDI  CF
0008: A2	  PLO  R2	; CF ->	R2.0 (stack pointer set	to 0YCF, where Y=X-1)
0009: F8 81	  LDI  81h	; Set R1 (PC for Interrupt Routine) to 8146
000B: B1	  PHI  R1
000C: F8 46	  LDI  46h
000E: A1	  PLO  R1
000F: 90	  GHI  R0	; Pre-set R4 to	001B in	preparation for	assignment as PC
0010: B4	  PHI  R4
0011: F8 1B	  LDI  1Bh
0013: A4	  PLO  R4
0014: F8 01	  LDI  01h	; 01 ->	R5.1
0016: B5	  PHI  R5
0017: F8 FC	  LDI  FC	; FC ->	R5.0  (R5 now set to 01FC; will	serve as PC for	CHIP-8
0019: A5	  PLO  R5	; instructions,	commencing with	two instructions included on page 01
001A: D4	  SEP  R4	; 4 -> P (R4 becomes PC	at this	point)

		; FETCH	AND DECODE ROUTINE

001B: 96	* GHI  R6	; 0Y ->	R7.1 (high byte	of VY pointer)
001C: B7	  PHI  R7
001D: E2	  SEX  R2	; 2 -> X
001E: 94	  GHI  R4	; 00 ->	RC.1
001F: BC	  PHI  RC
0020: 45	  LDA  R5	; Load by R5 and advance (Fetch	first byte of Chip-8 Instruction)
0021: AF	  PLO  RF	; Put in RF.0 (temporary storage)
0022: F6	  SHR		; Shift	right 4	times (MSD to LSD position)
0023: F6	  SHR
0024: F6	  SHR
0025: F6	  SHR
0026: 32 44	  BZ   44h	; If D=0 (i.e.,	if Op Code digit is zero), branch to 0044
0028: F9 50	  ORI  50h	; OR Immediate with 50
002A: AC	  PLO  RC	; Put in RC.0 (RC now points to 005a, where "a" is MSD of CHIP-8 Instruction)
002B: 8F	  GLO  RF	; Get RF.0 (high byte of instruction)
002C: FA 0F	  ANI  0Fh	; AND with 0F, OR with F0 (thus forming byte Fb, where "b" is the second
002E: F9 F0	  ORI  F0	; hex digit in the CHIP-8 Instruction, used in some instructions to designate VX)
0030: A6	  PLO  R6	; Put in R6.0 (R6 becomes VX pointer)
0031: 05	  LDN  R5	; Load via R5 (second byte of CHIP-8 Instruction)
0032: F6	  SHR		; Shift right 4 times
0033: F6	  SHR
0034: F6	  SHR
0035: F6	  SHR
0036: F9 F0	  ORI  F0	; OR with F0 
0038: A7	  PLO  R7	; and put in R7.0 (sets VY pointer)
0039: 4C	  LDA  RC	; Load via RC and advance (Loads high byte of address for appropriate subroutine)
003A: B3	  PHI  R3	; Put in R3.1
003B: 8C	  GLO  RC	; Get RC.0 (=5(a+1))
003C: FC 0F	  ADI  0Fh	; Add 0F, put in RC.0 (points to low byte of start address for appropriate
003E: AC	  PLO  RC	; subroutine to execute CHIP-8 Instruction)
003F: 0C	  LDN  RC	; Load via RC
0040: A3	* PLO  R3	; Put in R3.0
0041: D3	  SEP  R3	; Call subroutine designated by first digit of CHIP-8 Instruction (if not zero)
0042: 30 1B	* BR   1Bh	; Branch to 001B to fetch next instruction

		; ROUNTINE FOR FIRST DIGIT 0

0044: 8F	* GLO  RF	; Get RF.0 (high byte of instruction)
0045: FA 0F	  ANI  0Fh	; AND with 0F to save LSD only
0047: B3	  PHI  R3	; Put in R3.1 (select page on which subroutine will found)
0048: 45	  LDA  R5	; Load via R5 and advance (2nd byte of inst.)
0049: 30 40	  BR   40h	; Branch to 0040 to call subroutine (00E0 for erase page, 00EE for return from
				; subroutine, 0MMM for machine-language subroutine)

004B: 22	  DEC  R2	; Decrement R2 (stack pointer)
004C: 69	  INP  1h	; Turn display ON (interrupts will occur, controlled by routine at 8146)
004D: 12	  INC  R2	; Increment R2
004E: D4	  SEP  R4	; return to 0042
004F: 00	  IDL		; Filler
0050: 00	  IDL		; Filler

0051: 01	  db 1		; High bytes for pointer to start of subroutines selected by first digit
0052: 01	  db 1		; of CHIP 8 instructions (1 through F)
0053: 01	  db 1
0054: 01	  db 1
0055: 01	  db 1
0056: 01	  db 1
0057: 01	  db 1
0058: 01	  db 1
0059: 01	  db 1
005A: 01	  db 1
005B: 01	  db 1
005C: 01	  db 1
005D: 00	  db 0
005E: 01	  db 1
005F: 01	  db 1
;
0060: 00	IDL		; Filler

;				; Low Bytes for subroutine pointers
0061: 7C        db 7Ch		; 1 -> 017C
0062: 75        db 75h		; 2 -> 0175
0063: 83        db 83h          ; 3 -> 0183
0064: 8B        db 8Bh          ; 4 -> 018B
0065: 95        db 95h          ; 5 -> 0195
0066: B4        db 0B4h         ; 6 -> 01B4
0067: B7        db 0B7h         ; 7 -> 01B7
0068: BC        db 0BCh         ; 8 -> 01BC
0069: 91        db 91h          ; 9 -> 0191
006A: EB        db 0EBh         ; A -> 01EB
006B: A4        db 0A4h         ; B -> 01A4
006C: D9        db 0D9h         ; C -> 01D9
006D: 70        db 70h          ; D -> 0070
006E: 99        db 99h          ; E -> 0199
006F: 05        db 05h          ; F -> 0105
;

		; DISPLAY SUBROUTINE (1st Digit = D)

0070: 06	* LDN  R6	; Load by R6 (VX)
0071: FA 07	  ANI  07h	; Put last 3 bits in RE.1
0073: BE	  PHI  RE
0074: 06	  LDN  R6	; Load by R6
0075: FA 3F	  ANI  3Fh	; AND with 3F (save lower 6 bits)
0077: F6	  SHR		; shift right 3 times (save middle 3 digits)
0078: F6	  SHR
0079: F6	  SHR
007A: 22	  DEC  R2	; Decrement Stack
007B: 52	  STR  R2	; Store in Stack
007C: 07	  LDN  R7	; Load via R7 (VY)
007D: FA 1F	  ANI  1Fh	; AND with 1F (save 5 lowest bits)
007F: FE	  SHL		; shift left 3 times
0080: FE	  SHL
0081: FE	  SHL
0082: F1	  OR		; OR with top of stack
0083: AC	  PLO  RC	; Put Result in RC.0
0084: 9B	  GHI  RB	; Get RB.1, put in RC.1 (0X) -- RC now points to start address
0085: BC	  PHI  RC	; of first byte of pattern
0086: 45	  LDA  R5	; Load via R5 and advance -- fetches 2nd byte of CHIP 8 instruction
0087: FA 0F	  ANI  0F	; Put LSD in both RD.0 and R7.0 (No. of bytes in pattern)
0089: AD	  PLO  RD
008A: A7	  PLO  R7
008B: F8 D0	  LDI  D0	; D0 -> R6.0
008D: A6	  PLO  R6
008E: 93	* GHI  R3	; 00 -> RF.0
008F: AF	  PLO  RF
0090: 87	  GLO  R7	; Get R7.0 (No. of bytes); branch if D=0 to 00F3 (when branch occurs,
0091: 32 F3	  BZ   F3	; display bytes have been processed and stored commencing at 0YD0)
0093: 27	  DEC  R7	; Decrement R7
0094: 4A	  LDA  RA	; Load via RA (I pointer) and advance (Loads display byte)
0095: BD	  PHI  RD	; Put in RD.1
0096: 9E	  GHI  RE	; Get RE.1 (3 LSB's of VX), Put in RE.0
0097: AE	  PLO  RE
0098: 8E	  GLO  RE	; Get RE.0; if D=0, branch to 00A4 (When branch occurs, display bytes
0099: 32 A4	  BZ   A4	; will have been split into two parts in the event that display address
				; did not coincide with as memory byte address)
009B: 9D	  GHI  RD	; Get RD.1,
009C: F6	  SHR		; shift right,
009D: BD	  PHI  RD	; and return to RD.1 (left portion of split diplay byte)
009E: 8F	  GLO  RF	; Get RF.0,
009F: 76	  SHRC		; ring shift right (picking up carry, if any, from step 009C),
00A0: AF	  PLO  RF	; return to RF.0 -- thes instructions form right portion of split display byte.
00A1: 2E	  DEC  RE	; Decrement RE
00A2: 30 98	  BR   98	; Branch to 0098
		;
00A4: 9D	* GHI  RD	; Get RD.1 (left portion of split diplay byte)
00A5: 56	  STR  R6	; and store via R6
00A6: 16	  INC  R6	; Increment R6
00A7: 8F	  GLO  RF	; Get RF.0 (right portion of split diplay byte)
00A8: 56	  STR  R6	; and store via R6
00A9: 16	  INC  R6	; Increment R6
00AA: 30 8E	  BR   8E	; Branch to 008E
		;
00AC: 00	* IDL		; Wait for display interrupt
00AD: EC	  SEX  RC	; C -> X (C points to start address for first new byte in display page)
00AE: F8 D0	  LDI  D0	; D0 -> R6.0 (points to first processed display byte)
00B0: A6	  PLO  R6
00B1: 93	  GHI  R3	; 00 -> R7.0 (R7.0 will be used as a marker for "collisions"
00B2: A7	  PLO  R7	; between new and existing pattern)
00B3: 8D	* GLO  RD	; Get RD.0 (no. of bytes remaining);
00B4: 32 D9	  BZ   D9	; if D=0, branch to 00D9
00B6: 06	  LDN  R6	; Load via R6 (processed display byte)
00B7: F2	  AND		; AND with contents at current address in pattern on display page
00B8: 2D	  DEC  RD	; Decrement RD
00B9: 32 BE	  BZ   BE	; if D=0 (i.e., no "collision" occurs) branch to 00BE
00BB: F8 01	  LDI  01	; 01 -> R7.0 (marker to indicate that a "collision" has occured)
00BD: A7	  PLO  R7
00BE: 46	* LDA  R6	; Load via R6 (processed display byte)
00BF: F3	  XOR		; XOR with existing byte
00C0: 5C	  STR  RC	; Store via RC (in display page)
00C1: 02	  LDN  R2	; Load from top of stack (3 LBS's of display page address),
00C2: FB 07	  XRI  07	; XOR with 07;
00C4: 32 D2	  BZ   D2	; if result is zero, branch to 00D2 (display pattern is at
				; right-hand edge of display "window")
00C6: 1C	  INC  RC	; Increment RC
00C7: 06	  LDN  R6	; Load via R6 (right portion of processed diplay byte),
00C8: F2	  AND		; AND via R6 (existing contents of display page address);
00C9: 32 CE	  BZ   CE	; branch if result is zero (i.e., if there is no "collision") to 00CE
00CB: F8 01	  LDI  01	; 01 -> R7.0 (marker to indicate that a "collision" has occured)
00CD: A7	  PLO  R7
00CE: 06	* LDN  R6	; Load via R6,
00CF: F3	  XOR		; XOR with contents already present at designated address of display
00D0: 5C	  STR  RC	; page, and store via RC (on display page)
00D1: 2C	  DEC  RC	; Decrement RC
00D2: 16	* INC  R6	; Increment R6
00D3: 8C	  GLO  RC	; Get RC.0,
00D4: FC 08	  ADI  08	; Add 08,
00D6: AC	  PLO  RC	; and return to RC.0
00D7: 3B B3	  BNF  B3	; if DF=0 (i.e., if next byte location remains on display page), branch to 00B3
00D9: F8 FF	* LDI  FF	; FF -> R6.0 (R6 points to Variable F)
00DB: A6	  PLO  R6
00DC: 87	  GLO  R7
00DD: 56	  STR  R6
00DE: 12	  INC  R2	; Increment stack
00DF: D4	* SEP  R4	; Return to FETCH routine at 0042

		; ERASE DISPLAY PAGE -- Inst. 00E0

00E0: 9B	  GHI  RB	; 0X -> RF.1
00E1: BF	  PHI  RF
00E2: F8 FF	  LDI  FF	; FF -> RF.0
00E4: AF	  PLO  RF
00E5: 93	* GHI  R3	; 00 -> D
00E6: 5F	  STR  RF	; Store via RF
00E7: 8F	  GLO  RF	; Get RF.0;
00E8: 32 DF	  BZ   DF	; if zero, branch to 00DF for exit to FETCH
00EA: 2F	  DEC  RF	; Decrement RF
00EB: 30 E5	  BR   E5	; Branch to 00E5

00ED: 00	  IDL		; Filler

		; INST. 00EE -- Return from Subroutine

00EE: 42	  LDA  R2	; Load from stack and advance,
00EF: B5	  PHI  R5	; put in R5.1
00F0: 42	  LDA  R2	; Load from stack and advance,
00F1: A5	  PLO  R5	; put in R5.0 (R5 now points to next CHIP 8 instruction)
00F2: D4	  SEP  R4	; Return to FETCH routine at 0042

		; PART OF DISPLAY SUBROUTINE

00F3: 8D	* GLO  RD	; Get RD.0 (remaining no. of bytes in pattern),
00F4: A7	  PLO  R7	; put in R7.0
00F5: 87	* GLO  R7	; Get R7.0;
00F6: 32 AC	  BZ   AC	; if zero, branch to 00AC (When branch occurs, RA (I Pointer)
				; will have returned to its initial value)
00F8: 2A	  DEC  RA	; Decrement RA
00F9: 27	  DEC  R7	; Decrement R7
00FA: 30 F5	  BR   F5	; Branch to 00F5
		;
00FC: 00	  IDL		; Fillers
00FD: 00	  IDL
00FE: 00	  IDL
00FF: 00	  IDL
0100: 00	  IDL
0101: 00	  IDL
0102: 00	  IDL
0103: 00	  IDL
0104: 00	  IDL

		; FINAL DECODING OF "F" instructions

0105: 45	  LDA  R5	; Load via R5 and advance (2nd byte of CHIP 8 instruction)
0106: A3	  PLO  R3	; put in R3 (go to designated address)

		; Instruction FX07 (Let VX = Timer)

0107: 98	  GHI  R8	; Get R8.1
0108: 56	  STR  R6	; Store via R6 (i.e., as VX)
0109: D4	  SEP  R4	; Return to 0042

		; Instruction FX0A (Let VX = Hex Key)

010A: F8 81	  LDI  81	; RC = 8195 (keyboard scanning subroutine)
010C: BC	  PHI  RC
010D: F8 95	  LDI  95
010F: AC	  PLO  RC
0110: 22	  DEC  R2	; Decrement stack pointer
0111: DC	  SEP  RC	; Call keyboard scanning subroutine at 8195 (key entry is in D upon return)
0112: 12	  INC  R2	; Increment stack pointer
0113: 56	  STR  R6	; Store via R6 (i.e., as VX)
0114: D4	  SEP  R4	; Return to 0042

		; Instruction FX15 (Set Timer to VX)

0115: 06	  LDN  R6	; Load via R6 (loads VX),
0116: B8	  PHI  R8	; put in R8.1
0117: D4	  SEP  R4	; Return to 0042

		; Instruction FX18 (Set tone duration = VX)

0118: 06	  LDN  R6	; Load via R6 (loads VX)
0119: A8	  PLO  R8	; Put in R8.0 (tone timer)
011A: D4	  SEP  R4	; Return to 0042

		; Constants needed for Instruction FX33

011B: 64	* db	100
011C: 0A	  db	10
011D: 01	  db	1

		; Instruction FX1E

011E: E6	  SEX  R6	; 6 -> X
011F: 8A	  GLO  RA	; Get RA.0
0120: F4	  ADD		; Add VX
0121: AA	  PLO  RA	; Put in RA.0 (as updated I pointer)
0122: 3B 28	  BNF  28	; If DF=0 (i.e., if updated I remains on the same memory page), branch to 0128
0124: 9A	  GHI  RA	; Increment RA.1
0125: FC 01	  ADI  01
0127: BA	  PHI  RA
0128: D4	* SEP  R4	; Return to 0042

		; Instruction FX29 (Let I = 5-byte diplay pattern for LSD of VX)

0129: F8 81	  LDI  81	; 81 -> RA.1
012B: BA	  PHI  RA
012C: 06	  LDN  R6	; Load via R6 (VX)
012D: FA 0F	  ANI  0F	; AND with 0F (save last digit),
012F: AA	  PLO  RA	; put in RA.0
0130: 0A	  LDN  RA	; Load via RA (start address for 5-byte pattern of hex digit),
0131: AA	  PLO  RA	; put in RA.O
0132: D4	  SEP  R4	; Return to 0042

		; Instruction FX33 (Let MI = 3-decimal digit equivalent of VX)

0133: E6	  SEX  R6	; 6 -> X
0134: 06	  LDN  R6	; Load via R6 (VX),
0135: BF	  PHI  RF	; put in RF.1
0136: 93	  GHI  R3	; 01 -> RE.1
0137: BE	  PHI  RE
0138: F8 1B	  LDI  1B	; 1B -> RE.0 (RE = 011B)
013A: AE	  PLO  RE
013B: 2A	  DEC  RA	; Decrement RA
013C: 1A	* INC  RA	; Increment RA (cancels prev. step upon first entry into pgm loop,
				; but needed in later "passes" around the loop}
013D: F8 00	  LDI  00	; Store 00 via RA (I pointer)
013F: 5A	  STR  RA
0140: 0E	* LDN  RE	; load via RE (Decimal 100, 10 or 1)
0141: F5	  SD		; Subtract from M(R6) -- i.e., subtract from YX
0142: 3B 4B	  BNF  4B	; Branch if Minus to 014B
0144: 56	  STR  R6	; Store result via R6
0145: 0A	  LDN  RA	; Increment memory location contents pointed to by RA (= I Pointer)
0146: FC 01	  ADI  01
0148: 5A	  STR  RA
0149: 30 40	  BR   40	; Branch to 0140
014B: 4E	* LDA  RE	; load via RE and advance
014C: F6	  SHR		; Shift Right
014D: 3B 3C	  BNF  3C	; If DF=0 (i.e.,if decimal 100's, 10's and 1's have not been processed), branch to 013C
014F: 9F	  GHI  RF	; Get RF. 1 (original value of VX)
0150: 56	  STR  R6	; Stcre via R6 (restores original value of VX)
0151: 2A	  DEC  RA	; Decrement RA twice
0152: 2A	  DEC  RA
0153: D4	  SEP  R4	; Return to 0042

0154: 00	  IDL		; Filler

		; Instruction FX55 (Let MI = V0:VX)

0155: 22	  DEC  R2	; Decrement stack pointer
0156: 86	  GLO  R6	; Get R6.0 (pointer for VX),
0157: 52	  STR  R2	; and store in stack
0158: F8 F0	  LDI  F0	; F0 -> R7.0
015A: A7	  PLO  R7
015B: 07	* LDN  R7	; Load via R7
015C: 5A	  STR  RA	; Store via RA (I pointer)
015D: 87	  GLO  R7	; Get R7.0
015E: F3	  XOR		; XOR with top of stack (VX pointer)
015F: 17	  INC  R7	; Increment R7
0160: 1A	  INC  RA	; Increment RA
0161: 3A 5B	  BNZ  5B	; If D<>0 (i.e., if R7 at Step 5E has not yet reached value of YX pointer), branch to 015B
0163: 12	  INC  R2	; Increment stack pointer
0164: D4	  SEP  R4	; Return to 0042

		; Instruction FX65 (Let V0:VX = MI)

0165: 22	  DEC  R2	; Decrement stack pointer
0166: 86	  GLO  R6	; Get R6.0 (pointer for VX)
0167: 52	  STR  R2	; Store in stack
0168: F8 F0	  LDI  F0	; F0 -> R7.0
016A: A7	  PLO  R7
016B: 0A	* LDN  RA	; Load via RA (i.e., via I)
016C: 57	  STR  R7	; Store via R7
016D: 87	  GLO  R7	; Get R7.0
016E: F3	  XOR		; XOR with top of stack (VX pointer)
016F: 17	  INC  R7	; Increment R7
0170: 1A	  INC  RA	; Increment RA
0171: 3A 6B	  BNZ  6B	; If D<>0 (i.e., if R7 at Step 6E has not yet reached value of YX pointer), branch to 016B
0173: 12	  INC  R2	; Increment stack pointer
0174: D4	  SEP  R4	; Return to 0042

		; Instruction 2MMM (do subroutine at MMM)

0175: 15	  INC  R5	; Increment R5 (point to next CHIP 8 instruction after return)
0176: 85	  GLO  R5	; Get R5.0
0177: 22	  DEC  R2	; Decrement stack pointer
0178: 73	  STXD		; Store in stack and decrement
0179: 95	  GHI  R5	; Get R5.1
017A: 52	  STR  R2	; Store in stack
017B: 25	  DEC  R5	; Decrement R5 (points to low byte of current instruction)
017C: 45	  LDA  R5	; Load via R5 and advance
017D: A5	  PLO  R5	; Put in R5.0
017E: 86	  GLO  R6	; Get R6.0 (contains 2nd digit of current instruction)
017F: FA 0F	  ANI  0F	; AND with OF (save 2nd digit of Chip 8 instruction) 
0181: B5	  PHI  R5	; and put in R5.1 (R5 now points to first instruction of subroutine commencing at 0MMM)
0182: D4	* SEP  R4	; Return to 0042

		; Instruction 3XKK (Skip if VX=KK)

0183: 45	  LDA  R5	; Load by R5 and advance (KK -> D)
0184: E6	* SEX  R6	; 6 -> X
0185: F3	  XOR		; XOR (operands are KK and VX)
0186: 3A 82	  BNZ  82	; If D <> 0 (i.e., if VX <> KK), branch to 0182
0188: 15	* INC  R5	; Increment R5 twice (causing skip of next Chip 8 instruction)
0189: 15	  INC  R5
018A: D4	  SEP  R4	; Return to 0042

		; Instruction 4XKK (Skip if VX<>KK)

018B: 45	  LDA  R5	; Load by R5 and advance (KK -> D)
018C: E6	* SEX  R6	; 6 -> X
018D: F3	  XOR		; XOR (operands are KK and VX)
018E: 3A 88	  BNZ  88	; If D <> 0, branch to 0188
0190: D4	  SEP  R4	; Return to 0042

		; Instruction 9XY0 (Skip if VK<>VY)

0191: 45	  LDA  R5	; Load by R5 and advance
0192: 07	  LDN  R7	; Load by R7 (VY ->  D)
0193: 30 8C	  BR   8C	; Branch to 018C {operands for subsequent XOR operation will be VY and VX)

		; Instruction 5XY0 (Skip if VK=VY)

0195: 45	  LDA  R5	; Load by R5 and advance
0196: 07	  LDN  R7	; Load by R7 (VY ->  D)
0197: 30 84	  BR   84	; Branch to 0184 {operands for subsequent XOR operation will be VY and VX)

		; Instruction EX9E (Skip if VX=Key)
		; and EX91 (Skip if VX<>Key)

0199: E6	  SEX  R6	; 6 -> X
019A: 62	  OUT  2	; Output VX to keyboard latch, increment R6
019B: 26	  DEC  R6	; Decrement R6 (cancel advance of prev 0 step)
019C: 45	  LDA  R5	; load by R5 and advance (either 9E or A1 is loaded into D)
019D: A3	  PLO  R3	; Put in R3 (go to designated address)
		;
019E: 36 88	  B3   88	; if EF3 = 1 (i.e., if key matching LSD of VX is down) go to 0188
01A0: D4	  SEP  R4	; Return to 0042
		;
01A1: 3E 88	  BN3  88	; If EF3 = 0 (hex key matching LSD of VX not pressed), branch to 0188
01A3: D4	  SEP  R4	; Return to 0042

		; Instruction BMMM (Go to 0MMM + V0)

01A4: F8 F0	  LDI  F0	; FO -> R7.0 (R7 points to V0)
01A6: A7	  PLO  R7
01A7: E7	  SEX  R7	; 7 -> X
01A8: 45	  LDA  R5	; Load by R5 and advance (Loads 2nd byte of instruction)
01A9: F4	  ADD		; Add V0
01AA: A5	  PLO  R5	; Put in R5.0
01AB: 86	  GLO  R6	; Get LSD af R6.0 (2nd digit of instruction)
01AC: FA 0F	  ANI  0F
01AE: 3B B2	  BNF  B2	; If DF=0 (i.e., if there was no carry from addition operation at Step A9), branch to 0182
01B0: FC 01	  ADI  01	; Add 01
01B2: B5	  PHI  R5	; Put in R5.1
01B3: D4	  SEP  R4	; Return to 0042

		; Instruction 6XKK (Let VX = KK)

01B4: 45	  LDA  R5	; Load by R5 and advance (KK -> D)
01B5: 56	  STR  R6	; Store via R6 (as VX)
01B6: D4	  SEP  R4	; Return to 0042

		; Instruction 7XKK (Let VX = VX+KK)

01B7: 45	  LDA  R5	; Load by R5 and advance (KK -> D)
01B8: E6	  SEX  R6	; 6 -> X
01B9: F4	  ADD		; Add (D = VX+KK)
01BA: 56	  STR  R6	; Store via R6 (as updated VX)
01BB: D4	  SEP  R4	; Return to 0042

		; Instruction 8XYN (ALU operations with VX and VY as operands)

01BC: 45	  LDA  R5	; Load by R5 and advance (Loads 2nd byte of instruction)
01BD: FA 0F	  ANI  0F	; AND with 0F (save 2nd digit)
01BF: 3A C4	  BNZ  C4	; If D<>0, branch to 01C4
01C1: 07	  LDN  R7	; load by R7 (VY -> D)
01C2: 56	  STR  R6	; Store via R6 (as VX)
01C3: D4	  SEP  R4	; Return to 0042
		;
01C4: AF	* PLO  RF	; Put in RF.0
01C5: 22	  DEC  R2	; Decrement stack pointer
01C6: F8 D3	  LDI  D3	; D3->D
01C8: 73	  STXD		; Store in stack and decrement
01C9: 8F	  GLO  RF	; Get RF.0 (last digit of instruction)
01CA: F9 F0	  ORI  F0	; OR with F0 (forms an instruction code in the ALU group
				; --codes F1, F2, F3, F4, F5, F6, F7 and FE are valid}
01CC: 52	  STR  R2	; Store in stack (stack now holds a 2-instruction routine)
01CD: E6	  SEX  R6	; 6 -> X
01CE: 07	  LDN  R7	; load by R7 (VY -> D)
01CF: D2	  SEP  R2	; 2 -> D (calls routine developed in stack)
01D0: 56	  STR  R6	; Store result via R6 (as VX)
01D1: F8 FF	  LDI  FF	; FF -> R6.0 (points to VF)
01D3: A6	  PLO  R6
01D4: F8 00	  LDI  00	; 00 -> D
01D6: 7E	  SHLC		; Ring Shift Left (moves 0F to LSB)
01D7: 56	  STR  R6	; Store via R6 (as VF)
01D8: D4	  SEP  R4	; Return to 0042

		; Instruction CXKK (Let VX = Random Byte, masked by KK)

01D9: 19	  INC  R9	; Increment R9
01DA: 89	  GLO  R9	; Get R9.0, put in RE.0 (NOTE: R9 is a special pointer for this random-number
				; generator, and is incremented once for every TV scan by the interrupt routine.)
01DB: AE	  PLO  RE	
01DC: 93	  GHI  R3	; 01 -> RE.1
01DD: BE	  PHI  RE	; (RE now points to some byte on memory page 01)
01DE: 99	  GHI  R9	; Get R9.1 (Random byte resulting from last previous use of this instruction)
01DF: EE	  SEX  RE	; E -> X
01E0: F4	  ADD		; Add byte pointed to by RE
01E1: 56	  STR  R6	; Store via R6
01E2: 76	  SHRC		; Ring shift right
01E3: E6	  SEX  R6	; 6 -> X
01E4: F4	  ADD		; Add original byte formed at Step 01E0 to its ring-shifted version
01E5: B9	  PHI  R9	; Put in R9.1 (as starting point for next use of this instruction)
01E6: 56	  STR  R6	; Store via R6 (byte still un-masked)
01E7: 45	  LDA  R5	; Load via R5 and advance (loads 2nd byte of Ch ip 8 instruction, KK)
01E8: F2	  AND		; AND with byte pointed to by R6
01E9: 56	  STR  R6	; Store result via R6 (as VX)
01EA: D4	  SEP  R4	; Return to 0042

		; Instruction AMMM (Let I = 0MMM)

01EB: 45	  LDA  R5	; Load by R5 and advance (2nd byte of instruction) 
01EC: AA	  PLO  RA	; Put in RA.0
01ED: 86	  GLO  R6	; Get R6.0
01EE: FA 0F	  ANI  0F
01F0: BA	  PHI  RA	; Put 2nd digit in RA.1
01F1: D4	  SEP  R4	; Return to 0042
		;
01F2: 00	  IDL		; Fillers
01F3: 00	  IDL
01F4: 00	  IDL
01F5: 00	  IDL
01F6: 00	  IDL
01F7: 00	  IDL
01F8: 00	  IDL
01F9: 00	  IDL
01FA: 00	  IDL
01FB: 00	  IDL

		; Preliminary CHIP 8 instructions to precede every CHIP 8 programm

01FC: 00 E0	* dw	00E0	; calls routine at 00E0 to erase display page
01FE: 00 4B	  dw	004B	; calls routine at 0042 to turn on display

		END

; SUMMARY OF REGISTER FUNCTIONS IN CHIP 8 PROGRAMS
; 
; 									Initial Setting
; RO DMA Pointer							----
; R1 Program Counter (PC) for Interrupt Routine				8146
; R2 Stack Pointer							0YCF
; R3 PC for Interpreter Subroutines					----
; R4 PC for Interpreter FETCH AND DECODE routine			001B
; R5 Pointer for CHIP 8 Instructions					01FC
; R6 VX Pointer: in DXYN (Display) Instructions, also serves		0Y--*
;    as pointer for processed display bytes, later as VF pointer
; R7 VY Pointer for instructions involving VY; V0 Pointer for		0Y--*
;    BMMM Instructions; R7.0 is a "scratch pad" register in
;    DXYN, FX55 and FX65 Instructions
; R8 Timers controlled by Interrupt Routine (R8.1 is a generalpurpose	----
;    timer: R8.0 is a tone and de-bounce timer)
; R9 Special Pointer and "Scratch Pad" used in Random Number		----
;    Generally utilized in CXKK Instructions--changed by
;    Interrupt Routine
; RA I Pointer for CHIP 8 Instructions					----
; RB RB.1 is Display Page Pointer: RB.0 is "Scratch Pad" for		0Y--*
;    Interrupt Routine
; RC Temporary Pointer for FETCH AND DECODE Routine;			00--
;    Destination Address Pointer for DXYN Instructions; PC for
;    Keyboard Scanning Subroutine in FX0A Instructions.
; RD Both Sections Used as "Scratch Pad" Registers in DXYN		----
;    (Display Instruetions)
; RE Pointer for Constants Needed in FX33 Instructions: RE.1		----
;    is a "Scratch Pad" Register for DXYN (Display) Instructions
; RF Display Page Address Pointer for 00E0 (Erase) Instructions;	----
;    RF.0 Used as "Scratch Pad" in FETCH AND DECODE
;    Routine and also in DXYN Instructions
; 
; 
; NOTE: Registers available for machine-language subroutines are R7, RC,
;    RD, RE and RF, but subroutines themselves must provide any initial settings
;    required--CHIP 8 instructions may alter these register settings, as indicated
;    above.
; *: In basic VIP system with 2K RAM, 0X = 07 and 0Y = 06. In general,
;    0X, is highest memory page and 0Y = 0X-1.
  • homecomputer/chip8/chip8interpreter.txt
  • Zuletzt geändert: 2023/06/08 12:41
  • von volkerp