Compare commits
2
Commits
49c471ece6
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ca694f77d | ||
|
|
de58014d0f |
+35
-27
@@ -29,6 +29,7 @@ class State
|
||||
audio-stream: rl/AudioStream
|
||||
font: rl/Font
|
||||
page: int
|
||||
fullscreen: bool
|
||||
step-mode: bool
|
||||
clear-screen: bool
|
||||
pending-key: u8?
|
||||
@@ -122,11 +123,13 @@ fn parse-instruction(pc: u16) -> Instruction
|
||||
fn reset() -> ()
|
||||
cpu = Cpu{}
|
||||
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/2-ibm-logo.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
|
||||
|
||||
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
|
||||
;; 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
|
||||
cpu.pc = 0
|
||||
return
|
||||
|
||||
let inst = parse-instruction(cpu.pc)
|
||||
|
||||
cpu.pc += 2
|
||||
match inst.op
|
||||
0x0 ->
|
||||
match inst.nn
|
||||
;; TODO: Maybe this can be a draw command that clears the screen rather than special cased
|
||||
0xE0 -> state.clear-screen = true
|
||||
0xEE ->
|
||||
cpu.sp -= 1
|
||||
@@ -253,12 +253,12 @@ fn step() -> ()
|
||||
loop bit in reverse(0..8)
|
||||
if byte >> bit & 0x1 == 1 and idx < length(machine.vbuffer)
|
||||
if machine.vbuffer[idx] then collision = true
|
||||
machine.vbuffer[idx] = true
|
||||
machine.vbuffer[idx] = not machine.vbuffer[idx]
|
||||
idx += 1
|
||||
|
||||
cpu.v[0xF] = if collision then 1 else 0
|
||||
0xE ->
|
||||
let pressed = machine.keypad[inst.x]
|
||||
let pressed = machine.keypad[cpu.v[inst.x]]
|
||||
match inst.nn
|
||||
0x9E -> if pressed then cpu.pc += 2
|
||||
0xA1 -> if not pressed then cpu.pc += 2
|
||||
@@ -295,8 +295,7 @@ fn step() -> ()
|
||||
|
||||
fn run-update() -> ()
|
||||
loop i, key in keypad-keymap
|
||||
if rl/is-key-down(key) and not state.step-mode
|
||||
machine.keypad[keypad-mapping[i]] = true
|
||||
machine.keypad[keypad-mapping[i]] = rl/is-key-down(key)
|
||||
if state.pending-key as reg
|
||||
cpu.v[reg] = u8(i)
|
||||
state.pending-key = nil
|
||||
@@ -306,10 +305,11 @@ fn run-update() -> ()
|
||||
if rl/is-key-pressed(:key-equal)
|
||||
state.page = min(5, state.page + 1)
|
||||
|
||||
if rl/is-key-pressed(:key-r)
|
||||
if rl/is-key-pressed(:key-period)
|
||||
reset()
|
||||
return
|
||||
|
||||
if rl/is-key-pressed(:key-enter)
|
||||
state.fullscreen = not state.fullscreen
|
||||
if rl/is-key-pressed(:key-space)
|
||||
state.step-mode = not state.step-mode
|
||||
|
||||
@@ -325,23 +325,28 @@ fn run-update() -> ()
|
||||
return
|
||||
|
||||
if state.step-mode
|
||||
if rl/is-key-pressed(:key-n)
|
||||
step()
|
||||
if rl/is-key-pressed-repeat(:key-n)
|
||||
step()
|
||||
if rl/is-key-pressed(:key-n) or rl/is-key-pressed-repeat(:key-n)
|
||||
let inst = parse-instruction(cpu.pc)
|
||||
step(inst)
|
||||
else
|
||||
cycles += f64(rl/get-frame-time()) * ips
|
||||
|
||||
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
|
||||
|
||||
fill(state.screen-pixels, rl/black)
|
||||
if state.clear-screen
|
||||
state.clear-screen = false
|
||||
fill(state.screen-pixels, rl/black)
|
||||
else
|
||||
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
|
||||
;; 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() -> ()
|
||||
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)
|
||||
let key-size = 25
|
||||
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])
|
||||
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
|
||||
loop i in 0..16
|
||||
let row = i % 8
|
||||
|
||||
Reference in new issue
Block a user