Step, reset, tick_timer proc and struct cleanup.

Added a tick_timer proc so the code handles the step neatly.
Added some new struct fields to accomodate this and moved danglings
struct defs into the simulator definition.
This commit is contained in:
2026-06-19 12:33:47 +02:00
parent e9cf387640
commit 0b5006f985
5 changed files with 55 additions and 28 deletions
+17 -14
View File
@@ -67,23 +67,19 @@ run_gui :: proc(sim: ^Simulator) {
layout := calc_layout(screen_width, screen_height) layout := calc_layout(screen_width, screen_height)
rl.BeginDrawing() rl.BeginDrawing()
rl.ClearBackground(rl.BLACK) rl.ClearBackground(rl.Color{0x18, 0x18, 0x18, 0xFF})
if (!sim.paused) { if (!sim.paused) {
// Cycle the machine to update memory etc // Cycle the machine to update memory etc
emu.run_machine(sim.machine, 12) emu.run_machine(sim.machine, 12)
tick_timers(sim, beep)
}
// Handle delay timer if(sim.paused && sim.step) {
if sim.machine.delay_timer > 0 do sim.machine.delay_timer -= 1 // Cycle the machine to update memory etc
emu.run_machine(sim.machine, 1)
// Current sound file is around 1s so stop tick_timers(sim, beep)
// immediately when timer is 0 sim.step = false
if sim.machine.sound_timer > 0 {
sim.machine.sound_timer -= 1
if !rl.IsSoundPlaying(beep) do rl.PlaySound(beep)
} else {
rl.StopSound(beep)
}
} }
// Top // Top
@@ -115,9 +111,16 @@ run_gui :: proc(sim: ^Simulator) {
rl.UnloadSound(beep) rl.UnloadSound(beep)
rl.CloseAudioDevice() rl.CloseAudioDevice()
rl.CloseWindow() rl.CloseWindow()
}
// Free any allocated memory for the simulator tick_timers :: proc(sim: ^Simulator, beep: rl.Sound) {
delete(sim.disasm) if sim.machine.delay_timer > 0 do sim.machine.delay_timer -= 1
if sim.machine.sound_timer > 0 {
sim.machine.sound_timer -= 1
if !rl.IsSoundPlaying(beep) do rl.PlaySound(beep)
} else {
rl.StopSound(beep)
}
} }
calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout { calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout {
+18 -3
View File
@@ -1,6 +1,8 @@
package simulator package simulator
import "core:log" import "core:log"
import emu "../machine"
import rl "vendor:raylib" import rl "vendor:raylib"
gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) { gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
@@ -15,7 +17,6 @@ gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "RUN") { if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "RUN") {
if sim.rom_loaded { if sim.rom_loaded {
sim.paused = false sim.paused = false
sim.running = true
} else { } else {
log.info("no rom selected, can't run") log.info("no rom selected, can't run")
} }
@@ -23,12 +24,26 @@ gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "PAUSE") { if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "PAUSE") {
sim.paused = true sim.paused = true
sim.running = false }
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "STEP") {
if !sim.step do sim.step = true
} }
if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "RESET") { if btn(&cursor, rect, BUTTON_HEIGHT, BUTTON_WIDTH, PADDING_X, "RESET") {
sim.paused = true
sim.disasm_count = 0
emu.reset_machine(sim.machine)
} }
// @TODO: Get this working
slider_rect := rl.Rectangle{
x = rect.width - 100 - 50,
y = rect.y + 15,
width = 100,
height = 15
}
rl.GuiSlider(slider_rect, "Speed ", nil, &sim.speed_value, 0, 100)
} }
btn :: proc(cursor: ^f32, rect: rl.Rectangle, h, w, gap: f32, label: cstring) -> bool { btn :: proc(cursor: ^f32, rect: rl.Rectangle, h, w, gap: f32, label: cstring) -> bool {
-6
View File
@@ -7,12 +7,6 @@ import rl "vendor:raylib"
import emu "../machine" import emu "../machine"
import tfd "../../external/tinyfiledialogs" import tfd "../../external/tinyfiledialogs"
Instruction :: struct {
address: u16,
raw: u16,
str: string
}
gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) { gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) {
rl.DrawRectangleLinesEx(rect, 1, rl.GRAY) rl.DrawRectangleLinesEx(rect, 1, rl.GRAY)
+1 -1
View File
@@ -12,7 +12,7 @@ gui_status_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
cursor: f32 = rect.x + PADDING_X cursor: f32 = rect.x + PADDING_X
cy := rect.y + rect.height * 0.5 cy := rect.y + rect.height * 0.5
if sim.running && !sim.paused { if !sim.paused {
status_icon(&cursor, cy, rl.GREEN, .CIRCLE, "Running", sim.font) status_icon(&cursor, cy, rl.GREEN, .CIRCLE, "Running", sim.font)
} else { } else {
status_icon(&cursor, cy, rl.RED, .SQUARE, "Paused", sim.font) status_icon(&cursor, cy, rl.RED, .SQUARE, "Paused", sim.font)
+19 -4
View File
@@ -3,18 +3,32 @@ package simulator
import emu "../machine" import emu "../machine"
import rl "vendor:raylib" import rl "vendor:raylib"
// CHIP-8 ROM can be at most 3584 bytes (4096 - 0x200 reserved)
// Each instruction is 2 bytes, 3584 / 2 = 1792 instructions.
MAX_INSTRUCTIONS :: 1792
Instruction :: struct {
address: u16,
raw: u16,
str: [32]u8
}
Simulator :: struct { Simulator :: struct {
// Emulator // Emulator
machine: ^emu.System, machine: ^emu.System,
rom_loaded: bool, rom_loaded: bool,
running: bool,
paused: bool, paused: bool,
step: bool,
cycles_per_second: int, cycles_per_second: int,
speed_value: f32,
// GUI // GUI
font: rl.Font, font: rl.Font,
active_tab: i32, active_tab: i32,
mem_scroll: rl.Vector2, mem_scroll: rl.Vector2,
disasm: []Instruction, // disassembly props
disasm: [MAX_INSTRUCTIONS]Instruction,
disasm_follow: bool,
disasm_count: int,
disasm_scroll: rl.Vector2, disasm_scroll: rl.Vector2,
} }
@@ -23,9 +37,10 @@ run_simulator :: proc(s: ^emu.System) {
sim := Simulator { sim := Simulator {
machine = s, machine = s,
rom_loaded = false, rom_loaded = false,
running = false,
paused = true, paused = true,
cycles_per_second = 12 step = false,
cycles_per_second = 12,
disasm_follow = true
} }
run_gui(&sim) run_gui(&sim)