Compare commits
7 Commits
6ca732f178
...
30a37f26c5
| Author | SHA1 | Date | |
|---|---|---|---|
| 30a37f26c5 | |||
| 97f34d72a7 | |||
| 65b692f293 | |||
| 6d706a34cd | |||
| 6a43058033 | |||
| 7403efa6cf | |||
| 9d83c49872 |
Binary file not shown.
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 322 KiB |
@@ -1,7 +1,5 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
// load_rom, anything rom related
|
|
||||||
|
|
||||||
import "core:log"
|
import "core:log"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
|
||||||
|
|||||||
+18
-3
@@ -35,12 +35,13 @@ Layout :: struct {
|
|||||||
bottom_panel : rl.Rectangle,
|
bottom_panel : rl.Rectangle,
|
||||||
cpu : rl.Rectangle,
|
cpu : rl.Rectangle,
|
||||||
status_bar : rl.Rectangle,
|
status_bar : rl.Rectangle,
|
||||||
|
info_box : rl.Rectangle,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize main the gui 'window'
|
// Initialize main the gui 'window'
|
||||||
run_gui :: proc(sim: ^Simulator) {
|
run_gui :: proc(sim: ^Simulator) {
|
||||||
rl.SetConfigFlags({.WINDOW_RESIZABLE})
|
rl.SetConfigFlags({.WINDOW_RESIZABLE})
|
||||||
rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "raylib")
|
rl.InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Octal Cookie - Chip 8 Simulator")
|
||||||
rl.InitAudioDevice()
|
rl.InitAudioDevice()
|
||||||
rl.SetTargetFPS(60)
|
rl.SetTargetFPS(60)
|
||||||
beep := rl.LoadSound("./assets/sounds/beep.wav")
|
beep := rl.LoadSound("./assets/sounds/beep.wav")
|
||||||
@@ -70,9 +71,10 @@ run_gui :: proc(sim: ^Simulator) {
|
|||||||
rl.BeginDrawing()
|
rl.BeginDrawing()
|
||||||
rl.ClearBackground(rl.Color{0x18, 0x18, 0x18, 0xFF})
|
rl.ClearBackground(rl.Color{0x18, 0x18, 0x18, 0xFF})
|
||||||
|
|
||||||
|
cycles := int(sim.cpu_hz / SIM_FPS)
|
||||||
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, cycles)
|
||||||
tick_timers(sim, beep)
|
tick_timers(sim, beep)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +104,13 @@ run_gui :: proc(sim: ^Simulator) {
|
|||||||
|
|
||||||
// Bottom
|
// Bottom
|
||||||
// ------------------------------------------
|
// ------------------------------------------
|
||||||
gui_bottom_tabs(layout.bottom_panel, sim)
|
gui_bottom_panel(layout.bottom_panel, sim)
|
||||||
gui_status_bar(layout.status_bar, sim)
|
gui_status_bar(layout.status_bar, sim)
|
||||||
|
|
||||||
|
// Info Box
|
||||||
|
// ------------------------------------------
|
||||||
|
gui_info_box(layout.info_box, sim, screen_width, screen_height)
|
||||||
|
|
||||||
rl.EndDrawing()
|
rl.EndDrawing()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,5 +201,14 @@ calc_layout :: proc(screen_width: f32, screen_height: f32) -> Layout {
|
|||||||
width = screen_width,
|
width = screen_width,
|
||||||
height = STATUS_BAR_H,
|
height = STATUS_BAR_H,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ------------------------------------------
|
||||||
|
// Info Box
|
||||||
|
info_box = rl.Rectangle{
|
||||||
|
x = (screen_width / 2 - 200),
|
||||||
|
y = (screen_height / 2 - 200),
|
||||||
|
width = 400,
|
||||||
|
height = 140
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,40 +2,30 @@ package simulator
|
|||||||
|
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
gui_bottom_tabs :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
gui_bottom_panel :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
rl.DrawRectangleLinesEx(rect, 1, rl.GRAY)
|
rl.DrawRectangleLinesEx(rect, 1, rl.GRAY)
|
||||||
|
|
||||||
// Setup tab bar
|
|
||||||
tabs := [?]cstring{ "Memory", "Log" }
|
|
||||||
|
|
||||||
tab_bar_rect := rl.Rectangle{
|
|
||||||
rect.x,
|
|
||||||
rect.y,
|
|
||||||
rect.width,
|
|
||||||
BUTTON_HEIGHT + PADDING_Y
|
|
||||||
}
|
|
||||||
|
|
||||||
// inside draw loop:
|
|
||||||
rl.GuiTabBar(tab_bar_rect, &tabs[0], i32(len(tabs)), &sim.active_tab)
|
|
||||||
|
|
||||||
memory_view_bounds := rl.Rectangle {
|
memory_view_bounds := rl.Rectangle {
|
||||||
x = rect.x + PADDING_X,
|
x = rect.x + PADDING_X,
|
||||||
y = rect.y + PADDING_Y + tab_bar_rect.height,
|
y = rect.y + PADDING_Y,
|
||||||
width = (rect.width - (PADDING_X * 2)) / 2,
|
width = (rect.width - (PADDING_X * 2)) / 2,
|
||||||
height = rect.height - (PADDING_Y * 2) - tab_bar_rect.height,
|
height = rect.height - (PADDING_Y * 2),
|
||||||
}
|
}
|
||||||
|
gui_tab_memory(memory_view_bounds, sim)
|
||||||
|
|
||||||
disasm_view_bounds := rl.Rectangle {
|
disasm_view_bounds := rl.Rectangle {
|
||||||
x = rect.x + memory_view_bounds.width + PADDING_X,
|
x = rect.x + memory_view_bounds.width + PADDING_X,
|
||||||
y = rect.y + PADDING_Y + tab_bar_rect.height,
|
y = rect.y + PADDING_Y,
|
||||||
width = (rect.width - (PADDING_X * 2)) / 2,
|
width = ((rect.width - (PADDING_X * 2)) / 2) / 2,
|
||||||
height = rect.height - (PADDING_Y * 2) - tab_bar_rect.height,
|
height = rect.height - (PADDING_Y * 2),
|
||||||
}
|
}
|
||||||
|
|
||||||
switch sim.active_tab {
|
|
||||||
case 0: // draw registers panel
|
|
||||||
gui_tab_memory(memory_view_bounds, sim)
|
|
||||||
gui_tab_disasm(disasm_view_bounds, sim)
|
gui_tab_disasm(disasm_view_bounds, sim)
|
||||||
case 1: // draw memory panel
|
|
||||||
case 2: // draw display panel
|
stack_view_bounds := rl.Rectangle {
|
||||||
|
x = disasm_view_bounds.x + disasm_view_bounds.width,
|
||||||
|
y = rect.y + PADDING_Y,
|
||||||
|
width = ((rect.width - (PADDING_X * 2)) / 2) / 2,
|
||||||
|
height = rect.height - (PADDING_Y * 2),
|
||||||
}
|
}
|
||||||
|
gui_tab_stack(stack_view_bounds, sim)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package simulator
|
package simulator
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
import "core:log"
|
import "core:log"
|
||||||
|
|
||||||
import emu "../machine"
|
import emu "../machine"
|
||||||
@@ -36,14 +37,41 @@ gui_control_bar :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
emu.reset_machine(sim.machine)
|
emu.reset_machine(sim.machine)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO: Get this working
|
|
||||||
slider_rect := rl.Rectangle{
|
slider_rect := rl.Rectangle{
|
||||||
x = rect.width - 100 - 50,
|
x = rect.width - 210,
|
||||||
y = rect.y + 15,
|
y = rect.y + PADDING_X + 5,
|
||||||
width = 100,
|
width = 100,
|
||||||
height = 15
|
height = 15
|
||||||
}
|
}
|
||||||
rl.GuiSlider(slider_rect, "Speed ", nil, &sim.speed_value, 0, 100)
|
hz_label := fmt.ctprintf("%dHz", int(sim.cpu_hz))
|
||||||
|
rl.GuiSlider(slider_rect, "Speed ", hz_label, &sim.cpu_hz, 200, MAX_HZ)
|
||||||
|
|
||||||
|
mouse := rl.GetMousePosition()
|
||||||
|
if rl.CheckCollisionPointRec(mouse, slider_rect) {
|
||||||
|
rl.SetMouseCursor(.POINTING_HAND)
|
||||||
|
} else {
|
||||||
|
rl.SetMouseCursor(.DEFAULT)
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_rect := rl.Rectangle{
|
||||||
|
x = slider_rect.x - slider_rect.width - 20,
|
||||||
|
y = slider_rect.y,
|
||||||
|
width = 55,
|
||||||
|
height = 15,
|
||||||
|
}
|
||||||
|
if rl.GuiButton(reset_rect, "reset") {
|
||||||
|
sim.cpu_hz = DEFAULT_CPU_HZ
|
||||||
|
}
|
||||||
|
|
||||||
|
info_rect := rl.Rectangle{
|
||||||
|
x = rect.width - 35,
|
||||||
|
y = rect.y + PADDING_X,
|
||||||
|
width = 25,
|
||||||
|
height = BUTTON_HEIGHT,
|
||||||
|
}
|
||||||
|
if rl.GuiButton(info_rect, " ? ") {
|
||||||
|
sim.info_box = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
content_rect := rl.Rectangle {
|
content_rect := rl.Rectangle {
|
||||||
x = panel_rect.x,
|
x = panel_rect.x,
|
||||||
y = panel_rect.y - PANEL_HEADER,
|
y = panel_rect.y - PANEL_HEADER,
|
||||||
width = panel_rect.width + PANEL_HEADER,
|
width = panel_rect.width - 15,
|
||||||
height = f32(len(roms)) * LINE_HEIGHT
|
height = f32(len(roms)) * LINE_HEIGHT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package simulator
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
gui_info_box :: proc(rect: rl.Rectangle, sim: ^Simulator, screen_width: f32, screen_height: f32) {
|
||||||
|
if sim.info_box {
|
||||||
|
screen_rect := rl.Rectangle{0, 0, screen_width, screen_height}
|
||||||
|
rl.DrawRectangleRec(screen_rect, {0, 0, 0, 140})
|
||||||
|
if rl.GuiWindowBox(rect, "App Info") > 0 {
|
||||||
|
sim.info_box = false
|
||||||
|
}
|
||||||
|
|
||||||
|
content_y := rect.y + 24
|
||||||
|
center_x := rect.x + rect.width / 2
|
||||||
|
|
||||||
|
name_text : cstring = "Octal Cookie"
|
||||||
|
desc_text : cstring = "A CHIP-8 emulator and simulator written in Odin."
|
||||||
|
source_text : cstring = "https://codeberg.org/jasonhilder/octal_cookie"
|
||||||
|
|
||||||
|
name_size := rl.MeasureTextEx(sim.font, name_text, 18, 1)
|
||||||
|
desc_size := rl.MeasureTextEx(sim.font, desc_text, 18, 1)
|
||||||
|
source_size := rl.MeasureTextEx(sim.font, source_text, 18, 1)
|
||||||
|
|
||||||
|
rl.DrawTextEx(sim.font, name_text, {center_x - name_size.x / 2, content_y + 20}, 18, 1, rl.WHITE)
|
||||||
|
|
||||||
|
rl.DrawTextEx(sim.font, desc_text, {center_x - desc_size.x / 2, content_y + 46}, 18, 1, rl.WHITE)
|
||||||
|
|
||||||
|
source_pos := rl.Vector2{center_x - source_size.x / 2, content_y + 72}
|
||||||
|
rl.DrawTextEx(sim.font, source_text, source_pos, 18, 1, rl.SKYBLUE)
|
||||||
|
|
||||||
|
source_rect := rl.Rectangle{
|
||||||
|
x = source_pos.x,
|
||||||
|
y = source_pos.y,
|
||||||
|
width = source_size.x,
|
||||||
|
height = source_size.y,
|
||||||
|
}
|
||||||
|
|
||||||
|
mouse := rl.GetMousePosition()
|
||||||
|
if rl.CheckCollisionPointRec(mouse, source_rect) {
|
||||||
|
rl.SetMouseCursor(.POINTING_HAND)
|
||||||
|
|
||||||
|
rl.DrawRectangleRec( {source_pos.x, source_pos.y + source_size.y - 1, source_size.x, 1}, rl.SKYBLUE,)
|
||||||
|
|
||||||
|
if rl.IsMouseButtonPressed(.LEFT) {
|
||||||
|
rl.OpenURL("https://codeberg.org/jasonhilder/octal_cookie")
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
rl.SetMouseCursor(.DEFAULT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
package simulator
|
package simulator
|
||||||
|
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:strings"
|
|
||||||
import rl "vendor:raylib"
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
gui_tab_disasm :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
gui_tab_disasm :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
rl.DrawRectangleRec(rect, rl.DARKGRAY)
|
|
||||||
|
|
||||||
// Header background
|
// Header background
|
||||||
rl.DrawRectangle(i32(rect.x), i32(rect.y), i32(rect.width), i32(PANEL_HEADER), rl.BLACK)
|
rl.DrawRectangle(i32(rect.x), i32(rect.y), i32(rect.width), i32(PANEL_HEADER), rl.BLACK)
|
||||||
// Header: Address label
|
|
||||||
rl.DrawTextEx(sim.font, "Disassembled Instructions", {rect.x + 4, rect.y + 4}, 18, 1, rl.WHITE)
|
rl.DrawTextEx(sim.font, "Disassembled Instructions", {rect.x + 4, rect.y + 4}, 18, 1, rl.WHITE)
|
||||||
|
|
||||||
follow_label : cstring = "Follow: ON" if sim.disasm_follow else "Follow: OFF"
|
follow_label : cstring = "Follow: ON" if sim.disasm_follow else "Follow: OFF"
|
||||||
@@ -27,51 +23,47 @@ gui_tab_disasm :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
}
|
}
|
||||||
rl.GuiPanel(panel_rect, nil)
|
rl.GuiPanel(panel_rect, nil)
|
||||||
|
|
||||||
// Total height of all instructions
|
|
||||||
content_rect := rl.Rectangle {
|
content_rect := rl.Rectangle {
|
||||||
x = panel_rect.x,
|
x = panel_rect.x,
|
||||||
y = panel_rect.y - PANEL_HEADER,
|
y = panel_rect.y - PANEL_HEADER,
|
||||||
width = panel_rect.width + PANEL_HEADER,
|
width = panel_rect.width - 15,
|
||||||
height = f32(len(sim.disasm)) * LINE_HEIGHT
|
height = f32(len(sim.disasm)) * LINE_HEIGHT,
|
||||||
}
|
}
|
||||||
|
|
||||||
view: rl.Rectangle
|
view: rl.Rectangle
|
||||||
rl.GuiScrollPanel(panel_rect, nil, content_rect, &sim.disasm_scroll, &view)
|
rl.GuiScrollPanel(panel_rect, nil, content_rect, &sim.disasm_scroll, &view)
|
||||||
|
|
||||||
rl.BeginScissorMode(i32(view.x), i32(view.y), i32(view.width), i32(view.height))
|
rl.BeginScissorMode(i32(view.x), i32(view.y), i32(view.width), i32(view.height))
|
||||||
defer rl.EndScissorMode()
|
defer rl.EndScissorMode()
|
||||||
|
|
||||||
|
index_x := panel_rect.x + PADDING_X
|
||||||
|
disasm_x := index_x + 70
|
||||||
|
|
||||||
for entry, i in sim.disasm[:sim.disasm_count] {
|
for entry, i in sim.disasm[:sim.disasm_count] {
|
||||||
y_pos := panel_rect.y + (f32(i) * LINE_HEIGHT) + sim.disasm_scroll.y
|
y_pos := panel_rect.y + (f32(i) * LINE_HEIGHT) + sim.disasm_scroll.y
|
||||||
|
is_active := entry.address == sim.machine.pc
|
||||||
|
color := rl.WHITE
|
||||||
|
|
||||||
txt := fmt.tprintf("%d : %s", i, entry.str)
|
if is_active {
|
||||||
bg_color := rl.DARKGRAY if entry.address != sim.machine.pc else rl.BLACK
|
|
||||||
txt_color := rl.WHITE
|
|
||||||
|
|
||||||
rl.DrawRectangleV(
|
rl.DrawRectangleV(
|
||||||
{panel_rect.x + sim.disasm_scroll.x, y_pos},
|
{panel_rect.x + sim.disasm_scroll.x, y_pos},
|
||||||
{panel_rect.width, LINE_HEIGHT},
|
{panel_rect.width, LINE_HEIGHT},
|
||||||
bg_color,
|
rl.BLACK,
|
||||||
)
|
|
||||||
rl.DrawTextEx(
|
|
||||||
sim.font,
|
|
||||||
strings.clone_to_cstring(txt, context.temp_allocator),
|
|
||||||
{panel_rect.x + PADDING_X + sim.disasm_scroll.x, y_pos},
|
|
||||||
18, 1,
|
|
||||||
txt_color,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txt_index := fmt.ctprintf("0x%04X", entry.address)
|
||||||
|
txt_disasm := fmt.ctprintf(": %s", entry.str)
|
||||||
|
|
||||||
|
rl.DrawTextEx(sim.font, txt_index, {index_x + sim.disasm_scroll.x, y_pos}, 18, 1, color)
|
||||||
|
rl.DrawTextEx(sim.font, txt_disasm, {disasm_x + sim.disasm_scroll.x, y_pos}, 18, 1, color)
|
||||||
|
}
|
||||||
|
|
||||||
if sim.disasm_follow {
|
if sim.disasm_follow {
|
||||||
for entry, i in sim.disasm[:sim.disasm_count] {
|
for entry, i in sim.disasm[:sim.disasm_count] {
|
||||||
if entry.address == sim.machine.pc {
|
if entry.address == sim.machine.pc {
|
||||||
target_y := f32(i) * LINE_HEIGHT
|
target_y := f32(i) * LINE_HEIGHT
|
||||||
visible_height := panel_rect.height
|
visible_height := panel_rect.height
|
||||||
|
|
||||||
// Center the active instruction in the panel
|
|
||||||
sim.disasm_scroll.y = -(target_y - visible_height / 2)
|
sim.disasm_scroll.y = -(target_y - visible_height / 2)
|
||||||
|
|
||||||
// Clamp so we don't scroll past the content
|
|
||||||
max_scroll := -(f32(sim.disasm_count) * LINE_HEIGHT - visible_height)
|
max_scroll := -(f32(sim.disasm_count) * LINE_HEIGHT - visible_height)
|
||||||
sim.disasm_scroll.y = clamp(sim.disasm_scroll.y, max_scroll, 0)
|
sim.disasm_scroll.y = clamp(sim.disasm_scroll.y, max_scroll, 0)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ gui_tab_memory :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
|||||||
|
|
||||||
content_rect := rl.Rectangle{
|
content_rect := rl.Rectangle{
|
||||||
0, 0,
|
0, 0,
|
||||||
rect.width - 12,
|
rect.width - 15,
|
||||||
f32(MEM_VIRTUAL_ROWS) * MEM_ROW_H,
|
f32(MEM_VIRTUAL_ROWS) * MEM_ROW_H,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package simulator
|
||||||
|
import "core:fmt"
|
||||||
|
import rl "vendor:raylib"
|
||||||
|
|
||||||
|
gui_tab_stack :: proc(rect: rl.Rectangle, sim: ^Simulator) {
|
||||||
|
// Panel below header
|
||||||
|
panel_rect := rl.Rectangle{
|
||||||
|
rect.x,
|
||||||
|
rect.y + PANEL_HEADER,
|
||||||
|
rect.width,
|
||||||
|
rect.height - PANEL_HEADER,
|
||||||
|
}
|
||||||
|
rl.GuiPanel(panel_rect, nil)
|
||||||
|
|
||||||
|
// Header background
|
||||||
|
rl.DrawRectangle(i32(rect.x), i32(rect.y), i32(rect.width), i32(PANEL_HEADER), rl.BLACK)
|
||||||
|
rl.DrawTextEx(sim.font, "Stack", {rect.x + 4, rect.y + 4}, 18, 1, rl.WHITE)
|
||||||
|
|
||||||
|
// SP indicator in header
|
||||||
|
sp_label := fmt.ctprintf("SP: %d", sim.machine.sp)
|
||||||
|
sp_size := rl.MeasureTextEx(sim.font, sp_label, 18, 1)
|
||||||
|
rl.DrawTextEx(sim.font, sp_label, {rect.x + rect.width - sp_size.x - 8, rect.y + 4}, 18, 1, rl.WHITE)
|
||||||
|
|
||||||
|
// Use full panel height so empty slots fill the space
|
||||||
|
total_height := max(f32(16) * LINE_HEIGHT, panel_rect.height)
|
||||||
|
content_rect := rl.Rectangle{
|
||||||
|
x = panel_rect.x,
|
||||||
|
y = panel_rect.y - PANEL_HEADER,
|
||||||
|
width = panel_rect.width - 15,
|
||||||
|
height = total_height,
|
||||||
|
}
|
||||||
|
view: rl.Rectangle
|
||||||
|
rl.GuiScrollPanel(panel_rect, nil, content_rect, &sim.stack_scroll, &view)
|
||||||
|
rl.BeginScissorMode(i32(view.x), i32(view.y), i32(view.width), i32(view.height))
|
||||||
|
defer rl.EndScissorMode()
|
||||||
|
|
||||||
|
index_x := panel_rect.x + PADDING_X
|
||||||
|
colon_x := index_x + 30
|
||||||
|
|
||||||
|
for i in 0..<16 {
|
||||||
|
y_pos := panel_rect.y + (f32(i) * LINE_HEIGHT) + sim.stack_scroll.y
|
||||||
|
is_active := i < int(sim.machine.sp)
|
||||||
|
is_top := i == int(sim.machine.sp) - 1
|
||||||
|
// Only draw a background for active slots
|
||||||
|
if is_active {
|
||||||
|
rl.DrawRectangleV(
|
||||||
|
{panel_rect.x + sim.stack_scroll.x, y_pos},
|
||||||
|
{panel_rect.width, LINE_HEIGHT},
|
||||||
|
rl.BLACK,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sp_marker := ""
|
||||||
|
if is_top do sp_marker = " <- SP"
|
||||||
|
|
||||||
|
color := rl.WHITE if is_top else (rl.BLACK if is_active else rl.WHITE)
|
||||||
|
|
||||||
|
txt_index := fmt.ctprintf("%02d", i)
|
||||||
|
txt_value := fmt.ctprintf(": 0x%04X%s", sim.machine.stack[i], sp_marker)
|
||||||
|
|
||||||
|
rl.DrawTextEx(sim.font, txt_index, {index_x + sim.stack_scroll.x, y_pos}, 18, 1, color)
|
||||||
|
rl.DrawTextEx(sim.font, txt_value, {colon_x + sim.stack_scroll.x, y_pos}, 18, 1, color)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,10 @@ roms := #load_directory("../roms")
|
|||||||
// CHIP-8 ROM can be at most 3584 bytes (4096 - 0x200 reserved)
|
// CHIP-8 ROM can be at most 3584 bytes (4096 - 0x200 reserved)
|
||||||
// Each instruction is 2 bytes, 3584 / 2 = 1792 instructions.
|
// Each instruction is 2 bytes, 3584 / 2 = 1792 instructions.
|
||||||
MAX_INSTRUCTIONS :: 1792
|
MAX_INSTRUCTIONS :: 1792
|
||||||
|
SIM_FPS :: 60
|
||||||
|
DEFAULT_CPU_HZ :: 700
|
||||||
|
MIN_HZ :: 100
|
||||||
|
MAX_HZ :: 1500
|
||||||
|
|
||||||
Instruction :: struct {
|
Instruction :: struct {
|
||||||
address: u16,
|
address: u16,
|
||||||
@@ -22,14 +26,16 @@ Simulator :: struct {
|
|||||||
rom_loaded: bool,
|
rom_loaded: bool,
|
||||||
paused: bool,
|
paused: bool,
|
||||||
step: bool,
|
step: bool,
|
||||||
cycles_per_second: int,
|
cpu_hz: f32,
|
||||||
speed_value: f32,
|
info_box: bool,
|
||||||
// GUI
|
// GUI
|
||||||
font: rl.Font,
|
font: rl.Font,
|
||||||
active_tab: i32,
|
active_tab: i32,
|
||||||
mem_scroll: rl.Vector2,
|
mem_scroll: rl.Vector2,
|
||||||
rompick_scroll: rl.Vector2,
|
rompick_scroll: rl.Vector2,
|
||||||
selected_rom: string,
|
selected_rom: string,
|
||||||
|
// stack props
|
||||||
|
stack_scroll: rl.Vector2,
|
||||||
// disassembly props
|
// disassembly props
|
||||||
disasm: [MAX_INSTRUCTIONS]Instruction,
|
disasm: [MAX_INSTRUCTIONS]Instruction,
|
||||||
disasm_follow: bool,
|
disasm_follow: bool,
|
||||||
@@ -44,8 +50,8 @@ run_simulator :: proc(s: ^emu.System) {
|
|||||||
rom_loaded = false,
|
rom_loaded = false,
|
||||||
paused = true,
|
paused = true,
|
||||||
step = false,
|
step = false,
|
||||||
cycles_per_second = 12,
|
cpu_hz = 700,
|
||||||
disasm_follow = true
|
disasm_follow = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
run_gui(&sim)
|
run_gui(&sim)
|
||||||
|
|||||||
Reference in New Issue
Block a user