lr35902ish racket
Go to file
2020-06-12 16:07:59 +12:00
old-code lots of untested opcodes lmao 2020-06-12 16:07:59 +12:00
.gitignore lots of untested opcodes lmao 2020-06-12 16:07:59 +12:00
opcodes.txt lots of untested opcodes lmao 2020-06-12 16:07:59 +12:00
README.md lots of untested opcodes lmao 2020-06-12 16:07:59 +12:00
tests.rkt lots of untested opcodes lmao 2020-06-12 16:07:59 +12:00
vm.rkt lots of untested opcodes lmao 2020-06-12 16:07:59 +12:00

zybino: LR35902ish racket language

very early days for now.

in the racket repl (comments for reader comprehension, remove before running):

(run-vm #x150 #x150 #x19 ; start-address, end-memory-view-addr, number-bytes-view
   '(#x3E #x69           ; LD A, $69
     #x26 #x01           ; LD H, $01
     #x2E #x67           ; LD L, $67
     #x77                ; LD (HL), A
     #x2E #x5B           ; LD L, $5B
     #x36 #xE6           ; LD (HL), $E6  ($E6 is the opcode for XOR $xx)
     #x10                ; STOP          (this instruction @ address $015B)
     #xF0                ;               (non-instruction, will be arg for previous byte)
     #x2E #x68           ; LD L, $68
     #x77                ; LD (HL), A
     #xC2 #x64 #x01      ; JP NZ, $0164
     #x10                ; STOP
     #x7D                ; LD A, L       (address $0164)
     #x10                ; STOP
     ))

will evaluate to:

PC: $0166, SP: $0000, Flags: %00000000
BC: $0000, DE: $0000
HL: $0168, AF: $6800
(HL): $60
$0150 > $3e $69 $26 $01 $2e $67 $77 $2e $5b $36 $e6 $e6 $f0 $2e $68 $77 $c3 $64 $01 $10 $7d $10 $00 $69 $60 < $0168

here we can see the program loaded starting from address $0150, including the XOR instruction loaded to $015B during execution, and the $69 we loaded to memory, along with the result of XOR $F0 we loaded to memory, at $0167 and $0168 respectively. we can also see that the A register is $68, the same as the L register, as the conditional JP NZ instruction executed properly and we skipped the STOP at address $0163.

example 2 - loops

running:

(run-vm #x0000 #x0160 8
  '(#x26 #x01      ; LD H, $01
    #x2E #x61      ; LD L, $60
    #x3E #x05      ; LD A, $05
    #x77           ; LD (HL), A
    #x2C           ; INC L
    #x3D           ; DEC A
    #xFE #x00      ; CP $00
    #xC2 #x06 #x00 ; JP NZ, $0008
    #x10           ; STOP
    )))

evaluates to:

PC: $000f, SP: $0000, Flags: %10000000
BC: $0000, DE: $0000
HL: $0166, AF: $0080
(HL): $00
$0160 > $00 $05 $04 $03 $02 $01 $00 $00 < $0167

where we can see the zero flag set (bit 7), thus triggering the conditional loop, and the result of our loop saved to addresses $0161 to $0166

notes

currently supported instructions are:

  • JP #addr
  • JP [cc], #addr
  • LD [reg], #imm
  • LD [reg], [reg]
  • XOR #imm
  • AND #imm
  • OR #imm
  • ADD #imm
  • ADC #imm
  • SUB #imm
  • SBC #imm
  • CP #imm
  • XOR [reg]
  • AND [reg]
  • OR [reg]
  • ADD [reg]
  • ADC [reg]
  • SUB [reg]
  • SBC [reg]
  • CP [reg]
  • INC [reg]
  • DEC [reg]
  • STOP
  • NOP

all other instructions treated as NOP

on a gameboy, the instruction LD (HL), (HL) is treated as a HALT, however i am not making a gameboy perfect vm as of now, so opcode $76 is currently treated as LD (HL), (HL)