Compare commits

..
2 Commits
Author SHA1 Message Date
JosephFerano 70bb250bcd Display stack and other things 2026-09-29 21:59:44 +07:00
JosephFerano a375d365fa Fix keypad mappings 2026-09-29 10:08:43 +07:00
+126 -29
View File
@@ -31,10 +31,12 @@ struct Machine
sound-timer: u8 sound-timer: u8
struct State struct State
clear-screen: bool
screen-pixels: [2048 rl/Color] screen-pixels: [2048 rl/Color]
screen-texture: rl/Texture2D screen-texture: rl/Texture2D
font: rl/Font
draw-commands: Vec(DrawCommand) draw-commands: Vec(DrawCommand)
page: int
clear-screen: bool
shift-vx-swap: bool shift-vx-swap: bool
jump-xnn: bool jump-xnn: bool
@@ -56,21 +58,24 @@ const font: [80 u8] =
0xF0, 0x80, 0xF0, 0x80, 0xF0, ;; E 0xF0, 0x80, 0xF0, 0x80, 0xF0, ;; E
0xF0, 0x80, 0xF0, 0x80, 0x80] ;; F 0xF0, 0x80, 0xF0, 0x80, 0x80] ;; F
;; keypad-keys is in layout order, so keypad[i] isn't hex key i. That doesn't matter until EX9E and EXA1. const keypad-mapping: [16 u8] =
const keypad-keys: [16 rl/Key] = [1, 2, 3, 0xC, 4, 5, 6, 0xD, 7, 8, 9, 0xE, 0xA, 0, 0xB, 0xF]
const keypad-keymap: [16 rl/Key] =
[:key-one, :key-two, :key-three, :key-four, [:key-one, :key-two, :key-three, :key-four,
:key-q, :key-w, :key-e, :key-r, :key-q, :key-w, :key-e, :key-r,
:key-a, :key-s, :key-d, :key-f, :key-a, :key-s, :key-d, :key-f,
:key-z, :key-x, :key-c, :key-v] :key-z, :key-x, :key-c, :key-v]
;; [:key-one, :key-two, :key-three, :key-c,
;; :key-four, :key-five, :key-six, :key-d,
;; :key-seven, :key-eight, :key-nine, :key-e,
;; :key-a, :key-zero, :key-b, :key-f]
const keypad-chars: str = "123c456d789ea0bf" const hex-numbers: str = "0123456789ABCDEF"
let screen-width: int = 1024 const reg-names: [16 str] = ["V0", "V1", "V2", "V3", "V4", "V5", "V6", "V7",
let screen-height: int = 768 "V8", "V9", "VA", "VB", "VC", "VD", "VE", "VF"]
;; let screen-width: int = 1300
;; let screen-height: int = 650
let screen-width: int = 965
let screen-height: int = 550
let pixels-width: int = 64 let pixels-width: int = 64
let pixels-height: int = 32 let pixels-height: int = 32
let ips: int = 700 let ips: int = 700
@@ -107,6 +112,7 @@ fn step() -> ()
0xEE -> 0xEE ->
cpu.pc = cpu.stack[cpu.sp] cpu.pc = cpu.stack[cpu.sp]
cpu.sp -= 1 cpu.sp -= 1
_ -> println("Unrecognized 0x0 instruction")
0x1 -> cpu.pc = inst.nnn 0x1 -> cpu.pc = inst.nnn
0x2 -> ;; Call a subroutine 0x2 -> ;; Call a subroutine
cpu.stack[cpu.sp] = cpu.pc cpu.stack[cpu.sp] = cpu.pc
@@ -124,12 +130,12 @@ fn step() -> ()
0x2 -> cpu.v[inst.x] &= cpu.v[inst.y] 0x2 -> cpu.v[inst.x] &= cpu.v[inst.y]
0x3 -> cpu.v[inst.x] ^= cpu.v[inst.y] 0x3 -> cpu.v[inst.x] ^= cpu.v[inst.y]
0x4 -> 0x4 ->
let sum = cpu.v[inst.x] + cpu.v[inst.y] let sum = u16(cpu.v[inst.x]) + u16(cpu.v[inst.y])
cpu.v[inst.x] = sum cpu.v[inst.x] = u8(sum)
cpu.v[0xF] = u8(sum >> 8) cpu.v[0xF] = u8(sum >> 8)
0x5 -> 0x5 ->
let diff = u16(cpu.v[inst.x]) - u16(cpu.v[inst.y]) let diff = u16(cpu.v[inst.x]) - u16(cpu.v[inst.y])
cpu.v[inst.x] = diff cpu.v[inst.x] = u8(diff)
cpu.v[0xF] = u8(diff >> 8 & 0x1 ^ 1) cpu.v[0xF] = u8(diff >> 8 & 0x1 ^ 1)
0x6 -> 0x6 ->
if state.shift-vx-swap if state.shift-vx-swap
@@ -138,16 +144,18 @@ fn step() -> ()
cpu.v[inst.x] = cpu.v[inst.x] >> 1 cpu.v[inst.x] = cpu.v[inst.x] >> 1
0x7 -> 0x7 ->
let diff = u16(cpu.v[inst.y]) - u16(cpu.v[inst.x]) let diff = u16(cpu.v[inst.y]) - u16(cpu.v[inst.x])
cpu.v[inst.x] = diff cpu.v[inst.x] = u8(diff)
cpu.v[0xF] = u8(diff >> 8 & 0x1 ^ 1) cpu.v[0xF] = u8(diff >> 8 & 0x1 ^ 1)
0xE -> 0xE ->
if state.shift-vx-swap if state.shift-vx-swap
cpu.v[inst.x] = cpu.v[inst.y] cpu.v[inst.x] = cpu.v[inst.y]
cpu.v[0xF] = (cpu.v[inst.x] & 0x80) >> 7 cpu.v[0xF] = (cpu.v[inst.x] & 0x80) >> 7
cpu.v[inst.x] = cpu.v[inst.x] << 1 cpu.v[inst.x] = cpu.v[inst.x] << 1
_ -> println("Unrecognized 0x8 instruction")
0x9 -> if cpu.v[inst.x] != cpu.v[inst.y] then cpu.pc += 2 0x9 -> if cpu.v[inst.x] != cpu.v[inst.y] then cpu.pc += 2
0xA -> cpu.index = inst.nnn 0xA -> cpu.index = inst.nnn
0xB -> 0xB -> cpu.pc = inst.nnn + if state.jump-xnn then cpu.v[inst.x] else cpu.v[0]
0xC -> cpu.v[inst.x] = u8(rand-int()) & inst.nn
;; DXYN ;; DXYN
0xD -> 0xD ->
put(state.draw-commands, DrawCommand{.x (cpu.v[inst.x] % u8(pixels-width)) put(state.draw-commands, DrawCommand{.x (cpu.v[inst.x] % u8(pixels-width))
@@ -155,13 +163,22 @@ fn step() -> ()
.pixels inst.n .pixels inst.n
.addr cpu.index}) .addr cpu.index})
cpu.v[0xF] = 0 cpu.v[0xF] = 0
0xE ->
let pressed = machine.keypad[inst.x]
if (inst.nn == 0x9E and pressed) or (inst.nn == 0xA1 and not pressed)
cpu.pc += 2
_ -> println("Instruction not handled: ", inst.op) _ -> println("Instruction not handled: ", inst.op)
fn run-update() -> () fn run-update() -> ()
cycles += f64(rl/get-frame-time()) * ips for i, key in keypad-keymap
machine.keypad[keypad-mapping[int(i)]] = rl/is-key-down(key)
for i, key in keypad-keys if rl/is-key-pressed(:key-minus)
machine.keypad[int(i)] = rl/is-key-down(key) state.page = max(0, state.page - 1)
if rl/is-key-pressed(:key-equal)
state.page = min(5, state.page + 1)
cycles += f64(rl/get-frame-time()) * ips
while cycles >= 1.0 while cycles >= 1.0
step() step()
@@ -175,32 +192,107 @@ fn run-update() -> ()
for i,pixel in machine.vbuffer for i,pixel in machine.vbuffer
state.screen-pixels[i] = if pixel then rl/white else rl/black state.screen-pixels[i] = if pixel then rl/white else rl/black
;; for i,pixel in machine.vbuffer for 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
;; state.screen-pixels[i] = rl/white state.screen-pixels[i] = rl/white
rl/update-texture(state.screen-texture, Ptr(const u8)(addr(state.screen-pixels))) rl/update-texture(state.screen-texture, Ptr(const u8)(addr(state.screen-pixels)))
if machine.delay-timer > 0 then machine.delay-timer -= 1 if machine.delay-timer > 0 then machine.delay-timer -= 1
if machine.sound-timer > 0 then machine.sound-timer -= 1 if machine.sound-timer > 0 then machine.sound-timer -= 1
fn draw-text-normal(text: str, x: $t, y: $t, color: rl/Color) -> () where is-numeric($t)
rl/draw-text-ex(state.font, text, rl/Vector2(f32(x), f32(y)), 21, 0.0, color)
fn run-drawing() -> () fn run-drawing() -> ()
rl/clear-background(rl/black) rl/clear-background(rl/black)
rl/draw-fps(10, 10)
rl/draw-text("Keypad", 10, 40, 21, rl/white) draw-text-normal("Keypad", 10, 200, rl/white)
let key-size = 30 let key-size = 25
for i, key in keypad-keys for i, key in keypad-keymap
let x = 10 + (key-size * (i % 4)) let x = 10 + (key-size * (i % 4))
y = 70 + (key-size * (i / 4)) y = 230 + (key-size * (i / 4))
color = if machine.keypad[keypad-mapping[i]] then rl/green else rl/white
rl/draw-rectangle-lines(x, y, key-size, key-size, color)
;; TODO: Maybe we don't need hex-numbers anymore?
draw-text-normal(hex-numbers[i..i + 1], x + 4, y + 4, color)
draw-text-normal("Actual", 150, 200, rl/white)
for i,key in machine.keypad
let x = 150 + (key-size * (i % 4))
y = 230 + (key-size * (i / 4))
color = if machine.keypad[i] then rl/green else rl/white color = if machine.keypad[i] then rl/green else rl/white
rl/draw-rectangle-lines(x, y, key-size, key-size, color) rl/draw-rectangle-lines(x, y, key-size, key-size, color)
rl/draw-text(keypad-chars[i..i + 1], x + key-size / 4, y + key-size / 4, 16, color) draw-text-normal("0123456789ABCDEF"[i..i + 1], x + 4, y + 4, color)
let scale: f32 = 8.0 ;; Registers
let reg-x = 290
for i in 0..16
;; draw-text-normal(str(i64->bytes(i64(cpu.v[i]))), 520, 60 + 26 * i, rl/white)
let reg-val = tformat("V{:X}=0x{:02X}", i, cpu.v[i])
draw-text-normal(reg-val, reg-x, 200 + 21 * i, rl/white)
let scale: f32 = 5.5
src = rl/Rectangle(0, 0, f32(pixels-width), f32(pixels-height)) src = rl/Rectangle(0, 0, f32(pixels-width), f32(pixels-height))
dst = rl/Rectangle(10, 250, f32(pixels-width) * scale, f32(pixels-height) * scale) 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-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)
for i in 0..16
let row = i % 8
col = i / 8
x = 10
y = 20 * row
w = 80
h = 20
start-y = 360
idx-txt = tformat(" {:X}|", i)
rl/draw-rectangle-lines(x + col * w, start-y + y, w, h, rl/white)
draw-text-normal(idx-txt, x + col * w, start-y + y, rl/white)
if i < cpu.sp
let addr-txt = tformat("0x{:02X}", cpu.stack[i])
draw-text-normal(addr-txt, x + 33 + col * w, start-y + y, rl/white)
let x = 195
draw-text-normal(tformat(" i=0x{:02X}", cpu.index), x, 360, rl/white)
draw-text-normal(tformat("pc=0x{:02X}", cpu.sp), x, 380, rl/white)
draw-text-normal(tformat("dt=0x{:02}", machine.delay-timer), x, 400, rl/white)
draw-text-normal(tformat("st=0x{:02}", machine.sound-timer), x, 420, rl/white)
let hex-rows = 32
hex-cols = 24
padding = 4
cell-w = 24
cell-h = 16
grid-x = 370
grid-y = 25
grid-w = hex-cols * cell-w + padding * 2
grid-h = hex-rows * cell-h + padding * 2
slots-per-page = hex-rows * hex-cols
for i in 0..4096 / slots-per-page + 1
let color = if state.page == i then rl/green else rl/white
tab-w = 80
start-num = i * slots-per-page
end-num = min(4096, (i + 1) * slots-per-page)
tab-name = tformat("{:03X}-{:03X}", start-num, end-num - 1)
rl/draw-rectangle(grid-x - 1 + i * tab-w + (i * 2), grid-y - 20, tab-w, 20, color)
draw-text-normal(tab-name, grid-x + 1 + i * tab-w + (i * 2), grid-y - 20, rl/black)
rl/draw-rectangle-lines(grid-x, grid-y, grid-w, grid-h, rl/white)
for r in 0..hex-rows
for c in 0..hex-cols
let idx = c + r * hex-cols + hex-cols * hex-rows * state.page
if idx < length(machine.memory)
let reg-val = tformat("{:02X}", machine.memory[idx])
let x-padding = if c % 2 == 0 then 2 else -2
draw-text-normal(reg-val, grid-x + x-padding + c * cell-w, grid-y + padding + r * cell-h, rl/white)
cpu.stack[0] = 0xAA
cpu.stack[1] = 0xAB
cpu.stack[2] = 0xAC
cpu.stack[3] = 0xAD
cpu.sp = 15
fn main() -> i32 fn main() -> i32
rl/set-trace-log-level(:log-warning) rl/set-trace-log-level(:log-warning)
@@ -208,6 +300,10 @@ fn main() -> i32
defer rl/close-window() defer rl/close-window()
rl/set-target-fps(60) rl/set-target-fps(60)
let font = rl/load-font-ex("JetBrainsMono-Regular.otf", 21, [])
defer rl/unload-font(state.font)
state.font = font
state.page = 2
cpu.pc = 0x200 cpu.pc = 0x200
let img = rl/gen-image-color(pixels-width, pixels-height, rl/black) let img = rl/gen-image-color(pixels-width, pixels-height, rl/black)
state.screen-texture = rl/load-texture-from-image(img) state.screen-texture = rl/load-texture-from-image(img)
@@ -221,6 +317,7 @@ fn main() -> i32
run-update() run-update()
rl/with-drawing: rl/with-drawing:
run-drawing() run-drawing()
free-temp()
restart continue() restart continue()
() ()
0 0