Compare commits
2
Commits
49c471ece6
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ca694f77d | ||
|
|
de58014d0f |
+35
-27
@@ -29,6 +29,7 @@ class State
|
|||||||
audio-stream: rl/AudioStream
|
audio-stream: rl/AudioStream
|
||||||
font: rl/Font
|
font: rl/Font
|
||||||
page: int
|
page: int
|
||||||
|
fullscreen: bool
|
||||||
step-mode: bool
|
step-mode: bool
|
||||||
clear-screen: bool
|
clear-screen: bool
|
||||||
pending-key: u8?
|
pending-key: u8?
|
||||||
@@ -122,11 +123,13 @@ fn parse-instruction(pc: u16) -> Instruction
|
|||||||
fn reset() -> ()
|
fn reset() -> ()
|
||||||
cpu = Cpu{}
|
cpu = Cpu{}
|
||||||
machine = Machine{}
|
machine = Machine{}
|
||||||
;; load-rom("./IBM Logo.ch8")
|
load-rom("./IBM Logo.ch8")
|
||||||
;; load-rom("./vendor/chip8-test-suite/bin/1-chip8-logo.ch8")
|
;; load-rom("./vendor/chip8-test-suite/bin/1-chip8-logo.ch8")
|
||||||
;; load-rom("./vendor/chip8-test-suite/bin/2-ibm-logo.ch8")
|
;; load-rom("./vendor/chip8-test-suite/bin/2-ibm-logo.ch8")
|
||||||
;; load-rom("./vendor/chip8-test-suite/bin/3-corax+.ch8")
|
;; load-rom("./vendor/chip8-test-suite/bin/3-corax+.ch8")
|
||||||
load-rom("./vendor/chip8-test-suite/bin/4-flags.ch8")
|
;; load-rom("./vendor/chip8-test-suite/bin/4-flags.ch8")
|
||||||
|
;; load-rom("./roms/Breakout [Carmelo Cortez, 1979].ch8")
|
||||||
|
load-rom("./roms/Brix [Andreas Gustafsson, 1990].ch8")
|
||||||
cpu.pc = 0x200
|
cpu.pc = 0x200
|
||||||
|
|
||||||
fn decode-instruction(inst: Instruction) -> str
|
fn decode-instruction(inst: Instruction) -> str
|
||||||
@@ -182,18 +185,15 @@ fn decode-instruction(inst: Instruction) -> str
|
|||||||
|
|
||||||
;; You should extract the execution from the other stuff here so you can manually
|
;; You should extract the execution from the other stuff here so you can manually
|
||||||
;; run an instruction when needed, all it needs is a parsed instruction
|
;; run an instruction when needed, all it needs is a parsed instruction
|
||||||
fn step() -> ()
|
fn step(inst: Instruction) -> ()
|
||||||
if cpu.pc >= length(machine.memory) - 2
|
if cpu.pc >= length(machine.memory) - 2
|
||||||
cpu.pc = 0
|
cpu.pc = 0
|
||||||
return
|
return
|
||||||
|
|
||||||
let inst = parse-instruction(cpu.pc)
|
|
||||||
|
|
||||||
cpu.pc += 2
|
cpu.pc += 2
|
||||||
match inst.op
|
match inst.op
|
||||||
0x0 ->
|
0x0 ->
|
||||||
match inst.nn
|
match inst.nn
|
||||||
;; TODO: Maybe this can be a draw command that clears the screen rather than special cased
|
|
||||||
0xE0 -> state.clear-screen = true
|
0xE0 -> state.clear-screen = true
|
||||||
0xEE ->
|
0xEE ->
|
||||||
cpu.sp -= 1
|
cpu.sp -= 1
|
||||||
@@ -253,12 +253,12 @@ fn step() -> ()
|
|||||||
loop bit in reverse(0..8)
|
loop bit in reverse(0..8)
|
||||||
if byte >> bit & 0x1 == 1 and idx < length(machine.vbuffer)
|
if byte >> bit & 0x1 == 1 and idx < length(machine.vbuffer)
|
||||||
if machine.vbuffer[idx] then collision = true
|
if machine.vbuffer[idx] then collision = true
|
||||||
machine.vbuffer[idx] = true
|
machine.vbuffer[idx] = not machine.vbuffer[idx]
|
||||||
idx += 1
|
idx += 1
|
||||||
|
|
||||||
cpu.v[0xF] = if collision then 1 else 0
|
cpu.v[0xF] = if collision then 1 else 0
|
||||||
0xE ->
|
0xE ->
|
||||||
let pressed = machine.keypad[inst.x]
|
let pressed = machine.keypad[cpu.v[inst.x]]
|
||||||
match inst.nn
|
match inst.nn
|
||||||
0x9E -> if pressed then cpu.pc += 2
|
0x9E -> if pressed then cpu.pc += 2
|
||||||
0xA1 -> if not pressed then cpu.pc += 2
|
0xA1 -> if not pressed then cpu.pc += 2
|
||||||
@@ -295,8 +295,7 @@ fn step() -> ()
|
|||||||
|
|
||||||
fn run-update() -> ()
|
fn run-update() -> ()
|
||||||
loop i, key in keypad-keymap
|
loop i, key in keypad-keymap
|
||||||
if rl/is-key-down(key) and not state.step-mode
|
machine.keypad[keypad-mapping[i]] = rl/is-key-down(key)
|
||||||
machine.keypad[keypad-mapping[i]] = true
|
|
||||||
if state.pending-key as reg
|
if state.pending-key as reg
|
||||||
cpu.v[reg] = u8(i)
|
cpu.v[reg] = u8(i)
|
||||||
state.pending-key = nil
|
state.pending-key = nil
|
||||||
@@ -306,10 +305,11 @@ fn run-update() -> ()
|
|||||||
if rl/is-key-pressed(:key-equal)
|
if rl/is-key-pressed(:key-equal)
|
||||||
state.page = min(5, state.page + 1)
|
state.page = min(5, state.page + 1)
|
||||||
|
|
||||||
if rl/is-key-pressed(:key-r)
|
if rl/is-key-pressed(:key-period)
|
||||||
reset()
|
reset()
|
||||||
return
|
return
|
||||||
|
if rl/is-key-pressed(:key-enter)
|
||||||
|
state.fullscreen = not state.fullscreen
|
||||||
if rl/is-key-pressed(:key-space)
|
if rl/is-key-pressed(:key-space)
|
||||||
state.step-mode = not state.step-mode
|
state.step-mode = not state.step-mode
|
||||||
|
|
||||||
@@ -325,23 +325,28 @@ fn run-update() -> ()
|
|||||||
return
|
return
|
||||||
|
|
||||||
if state.step-mode
|
if state.step-mode
|
||||||
if rl/is-key-pressed(:key-n)
|
if rl/is-key-pressed(:key-n) or rl/is-key-pressed-repeat(:key-n)
|
||||||
step()
|
let inst = parse-instruction(cpu.pc)
|
||||||
if rl/is-key-pressed-repeat(:key-n)
|
step(inst)
|
||||||
step()
|
|
||||||
else
|
else
|
||||||
cycles += f64(rl/get-frame-time()) * ips
|
cycles += f64(rl/get-frame-time()) * ips
|
||||||
|
|
||||||
loop cycles >= 1.0
|
loop cycles >= 1.0
|
||||||
step()
|
let inst = parse-instruction(cpu.pc)
|
||||||
|
step(inst)
|
||||||
|
;; Apparently on the COSMAC VIP and other devices, drawing would wait for the next scree
|
||||||
|
;; refresh which ran at 60hz
|
||||||
|
if inst.op == 0xD
|
||||||
|
cycles = 0.0
|
||||||
|
break
|
||||||
cycles -= 1.0
|
cycles -= 1.0
|
||||||
|
|
||||||
|
fill(state.screen-pixels, rl/black)
|
||||||
if state.clear-screen
|
if state.clear-screen
|
||||||
state.clear-screen = false
|
state.clear-screen = false
|
||||||
fill(state.screen-pixels, rl/black)
|
|
||||||
else
|
else
|
||||||
loop i,pixel in machine.vbuffer
|
loop i,pixel in machine.vbuffer
|
||||||
state.screen-pixels[i] = if pixel then rl/white else rl/black
|
if pixel
|
||||||
|
state.screen-pixels[i] = rl/white
|
||||||
|
|
||||||
;; loop i,pixel in machine.vbuffer
|
;; loop i,pixel in machine.vbuffer
|
||||||
;; if i % 2 == 0 and i / pixels-width % 2 == 0 or i % 2 == 1 and i / pixels-width % 2 == 1
|
;; if i % 2 == 0 and i / pixels-width % 2 == 0 or i % 2 == 1 and i / pixels-width % 2 == 1
|
||||||
@@ -357,6 +362,16 @@ fn draw-text-normal(text: str, x: $t, y: $t, color: rl/Color) -> () where is-num
|
|||||||
fn run-drawing() -> ()
|
fn run-drawing() -> ()
|
||||||
rl/clear-background(rl/black)
|
rl/clear-background(rl/black)
|
||||||
|
|
||||||
|
;; Texture
|
||||||
|
let scale: f32 = if state.fullscreen then 14 else 5
|
||||||
|
src = rl/Rectangle(0, 0, f32(pixels-width), f32(pixels-height))
|
||||||
|
dst = rl/Rectangle(10, 10, f32(pixels-width) * scale, f32(pixels-height) * scale)
|
||||||
|
rl/draw-texture-pro(state.screen-texture, src, dst, rl/Vector2(0.0, 0.0), 0.0, rl/white)
|
||||||
|
rl/draw-rectangle-lines(i32(dst.x), i32(dst.y), i32(dst.width), i32(dst.height), rl/white)
|
||||||
|
|
||||||
|
if state.fullscreen
|
||||||
|
return
|
||||||
|
|
||||||
draw-text-normal("Keypad", 10, 200, rl/white)
|
draw-text-normal("Keypad", 10, 200, rl/white)
|
||||||
let key-size = 25
|
let key-size = 25
|
||||||
loop i, key in keypad-keymap
|
loop i, key in keypad-keymap
|
||||||
@@ -394,13 +409,6 @@ fn run-drawing() -> ()
|
|||||||
let reg-val = format("V{:X}=0x{:02X}", i, cpu.v[i])
|
let reg-val = format("V{:X}=0x{:02X}", i, cpu.v[i])
|
||||||
draw-text-normal(reg-val, reg-x, 200 + 21 * i, rl/white)
|
draw-text-normal(reg-val, reg-x, 200 + 21 * i, rl/white)
|
||||||
|
|
||||||
;; Texture
|
|
||||||
let scale: f32 = 5.5
|
|
||||||
src = rl/Rectangle(0, 0, f32(pixels-width), f32(pixels-height))
|
|
||||||
dst = rl/Rectangle(10, 10, f32(pixels-width) * scale, f32(pixels-height) * scale)
|
|
||||||
rl/draw-texture-pro(state.screen-texture, src, dst, rl/Vector2(0.0, 0.0), 0.0, rl/white)
|
|
||||||
rl/draw-rectangle-lines(i32(dst.x), i32(dst.y), i32(dst.width), i32(dst.height), rl/white)
|
|
||||||
|
|
||||||
;; Stack
|
;; Stack
|
||||||
loop i in 0..16
|
loop i in 0..16
|
||||||
let row = i % 8
|
let row = i % 8
|
||||||
|
|||||||
Reference in new issue
Block a user