Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
70bb250bcd | ||
|
|
a375d365fa |
+126
-29
@@ -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
|
||||||
|
|||||||
Reference in new issue
Block a user