Refactor disassembled instructions to be fixed arr

Updated code to make disassembled instructions a fixed array since we
know the cap at runtime, Also added toggle switch to follow the current
instruction
This commit is contained in:
2026-06-19 12:35:12 +02:00
parent 0b5006f985
commit 356ed2408a
2 changed files with 76 additions and 51 deletions
+53 -50
View File
@@ -42,12 +42,8 @@ gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) {
// @TODO: update status bar here // @TODO: update status bar here
panic("failed to load rom!") panic("failed to load rom!")
} }
sim.rom_loaded = true sim.rom_loaded = true
sim.disasm_count = disassemble_rom_n(sim.machine.memory[:], 0x200, 0x200 + u16(rom_size), sim.disasm[:])
// Free old instructions on sim
delete(sim.disasm)
sim.disasm = disassemble_rom(sim.machine.memory[:], 0x200, 0x200 + u16(rom_size))
} }
// drop-zone occupies the panel's content area, minus space for the button // drop-zone occupies the panel's content area, minus space for the button
@@ -102,12 +98,14 @@ gui_file_loader :: proc(rect: rl.Rectangle, sim: ^Simulator) {
rl.GuiButton(bottom_btn_rect, "Open ROM Folder") rl.GuiButton(bottom_btn_rect, "Open ROM Folder")
} }
disassemble_rom :: proc(memory: []u8, start: u16, end_addr: u16) -> []Instruction { disassemble_rom_n :: proc(memory: []u8, start_addr: u16, end_addr: u16, out: []Instruction) -> int {
entries := make([dynamic]Instruction) count := 0
i := start_addr
i := start
for i < end_addr { for i < end_addr {
if int(i) + 1 >= len(memory) do break if int(i) + 1 >= len(memory) do break
if count >= len(out) do break
addr := i addr := i
high_byte := memory[i] high_byte := memory[i]
low_byte := memory[i + 1] low_byte := memory[i + 1]
@@ -124,63 +122,68 @@ disassemble_rom :: proc(memory: []u8, start: u16, end_addr: u16) -> []Instructio
kk := u8(opcode & 0x00FF) // An 8-bit value, the lowest 8 bits of the instruction kk := u8(opcode & 0x00FF) // An 8-bit value, the lowest 8 bits of the instruction
nnn := (opcode & 0x0FFF) // A 12-bit value, the lowest 12 bits of the instruction nnn := (opcode & 0x0FFF) // A 12-bit value, the lowest 12 bits of the instruction
str: string
instruction := &out[count]
instruction.address = addr
instruction.raw = opcode
switch first_nibble { switch first_nibble {
case 0x0: case 0x0:
switch opcode { switch opcode {
case 0x00E0: str = "CLS" //case 0x00E0: str = "CLS"
case 0x00EE: str = "RET" case 0x00E0: fmt.bprintf(instruction.str[:], "CLS")
case: str = fmt.tprintf("DATA 0x%04X", opcode) case 0x00EE: fmt.bprintf(instruction.str[:], "RET")
case: fmt.bprintf(instruction.str[:], "DATA 0x%04X", opcode)
} }
case 0x1: str = fmt.tprintf("JP 0x%03X", nnn) case 0x1: fmt.bprintf(instruction.str[:], "JP 0x%03X", nnn)
case 0x2: str = fmt.tprintf("CALL 0x%03X", nnn) case 0x2: fmt.bprintf(instruction.str[:], "CALL 0x%03X", nnn)
case 0x3: str = fmt.tprintf("SE V%X, 0x%02X", vx, kk) case 0x3: fmt.bprintf(instruction.str[:], "SE V%X, 0x%02X", vx, kk)
case 0x4: str = fmt.tprintf("SNE V%X, 0x%02X", vx, kk) case 0x4: fmt.bprintf(instruction.str[:], "SNE V%X, 0x%02X", vx, kk)
case 0x5: str = fmt.tprintf("SE V%X, V%X", vx, vy) case 0x5: fmt.bprintf(instruction.str[:], "SE V%X, V%X", vx, vy)
case 0x6: str = fmt.tprintf("LD V%X, 0x%02X", vx, kk) case 0x6: fmt.bprintf(instruction.str[:], "LD V%X, 0x%02X", vx, kk)
case 0x7: str = fmt.tprintf("ADD V%X, 0x%02X", vx, kk) case 0x7: fmt.bprintf(instruction.str[:], "ADD V%X, 0x%02X", vx, kk)
case 0x8: case 0x8:
switch last_nibble { switch last_nibble {
case 0x0: str = fmt.tprintf("LD V%X, V%X", vx, vy) case 0x0: fmt.bprintf(instruction.str[:], "LD V%X, V%X", vx, vy)
case 0x1: str = fmt.tprintf("OR V%X, V%X", vx, vy) case 0x1: fmt.bprintf(instruction.str[:], "OR V%X, V%X", vx, vy)
case 0x2: str = fmt.tprintf("AND V%X, V%X", vx, vy) case 0x2: fmt.bprintf(instruction.str[:], "AND V%X, V%X", vx, vy)
case 0x3: str = fmt.tprintf("XOR V%X, V%X", vx, vy) case 0x3: fmt.bprintf(instruction.str[:], "XOR V%X, V%X", vx, vy)
case 0x4: str = fmt.tprintf("ADD V%X, V%X", vx, vy) case 0x4: fmt.bprintf(instruction.str[:], "ADD V%X, V%X", vx, vy)
case 0x5: str = fmt.tprintf("SUB V%X, V%X", vx, vy) case 0x5: fmt.bprintf(instruction.str[:], "SUB V%X, V%X", vx, vy)
case 0x6: str = fmt.tprintf("SHR V%X", vx) case 0x6: fmt.bprintf(instruction.str[:], "SHR V%X", vx)
case 0x7: str = fmt.tprintf("SUBN V%X, V%X", vx, vy) case 0x7: fmt.bprintf(instruction.str[:], "SUBN V%X, V%X", vx, vy)
case 0xE: str = fmt.tprintf("SHL V%X", vx) case 0xE: fmt.bprintf(instruction.str[:], "SHL V%X", vx)
case: str = fmt.tprintf("DATA 0x%04X", opcode) case: fmt.bprintf(instruction.str[:], "DATA 0x%04X", opcode)
} }
case 0x9: str = fmt.tprintf("SNE V%X, V%X", vx, vy) case 0x9: fmt.bprintf(instruction.str[:], "SNE V%X, V%X", vx, vy)
case 0xA: str = fmt.tprintf("LD I, 0x%03X", nnn) case 0xA: fmt.bprintf(instruction.str[:], "LD I, 0x%03X", nnn)
case 0xB: str = fmt.tprintf("JP V0, 0x%03X", nnn) case 0xB: fmt.bprintf(instruction.str[:], "JP V0, 0x%03X", nnn)
case 0xC: str = fmt.tprintf("RND V%X, 0x%02X", vx, kk) case 0xC: fmt.bprintf(instruction.str[:], "RND V%X, 0x%02X", vx, kk)
case 0xD: str = fmt.tprintf("DRW V%X, V%X, %X", vx, vy, last_nibble) case 0xD: fmt.bprintf(instruction.str[:], "DRW V%X, V%X, %X", vx, vy, last_nibble)
case 0xE: case 0xE:
switch kk { switch kk {
case 0x9E: str = fmt.tprintf("SKP V%X", vx) case 0x9E: fmt.bprintf(instruction.str[:], "SKP V%X", vx)
case 0xA1: str = fmt.tprintf("SKNP V%X", vx) case 0xA1: fmt.bprintf(instruction.str[:], "SKNP V%X", vx)
case: str = fmt.tprintf("DATA 0x%04X", opcode) case: fmt.bprintf(instruction.str[:], "DATA 0x%04X", opcode)
} }
case 0xF: case 0xF:
switch kk { switch kk {
case 0x07: str = fmt.tprintf("LD V%X, DT", vx) case 0x07: fmt.bprintf(instruction.str[:], "LD V%X, DT", vx)
case 0x0A: str = fmt.tprintf("LD V%X, K", vx) case 0x0A: fmt.bprintf(instruction.str[:], "LD V%X, K", vx)
case 0x15: str = fmt.tprintf("LD DT, V%X", vx) case 0x15: fmt.bprintf(instruction.str[:], "LD DT, V%X", vx)
case 0x18: str = fmt.tprintf("LD ST, V%X", vx) case 0x18: fmt.bprintf(instruction.str[:], "LD ST, V%X", vx)
case 0x1E: str = fmt.tprintf("ADD I, V%X", vx) case 0x1E: fmt.bprintf(instruction.str[:], "ADD I, V%X", vx)
case 0x29: str = fmt.tprintf("LD F, V%X", vx) case 0x29: fmt.bprintf(instruction.str[:], "LD F, V%X", vx)
case 0x33: str = fmt.tprintf("LD B, V%X", vx) case 0x33: fmt.bprintf(instruction.str[:], "LD B, V%X", vx)
case 0x55: str = fmt.tprintf("LD [I], V%X", vx) case 0x55: fmt.bprintf(instruction.str[:], "LD [I], V%X", vx)
case 0x65: str = fmt.tprintf("LD V%X, [I]", vx) case 0x65: fmt.bprintf(instruction.str[:], "LD V%X, [I]", vx)
case: str = fmt.tprintf("DATA 0x%04X", opcode) case: fmt.bprintf(instruction.str[:], "DATA 0x%04X", opcode)
} }
case: str = fmt.tprintf("DATA 0x%04X", opcode) case: fmt.bprintf(instruction.str[:], "DATA 0x%04X", opcode)
} }
append(&entries, Instruction{address = addr, raw = opcode, str = str}) count += 1
} }
return entries[:] return count
} }
+23 -1
View File
@@ -12,6 +12,11 @@ gui_tab_disasm :: proc(rect: rl.Rectangle, sim: ^Simulator) {
// Header: Address label // 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_rect := rl.Rectangle{rect.x + rect.width - 110, rect.y + 4, 100, 20}
if rl.GuiButton(follow_rect, follow_label) {
sim.disasm_follow = !sim.disasm_follow
}
// Scroll panel area (below header) // Scroll panel area (below header)
panel_rect := rl.Rectangle{ panel_rect := rl.Rectangle{
@@ -38,7 +43,7 @@ gui_tab_disasm :: proc(rect: rl.Rectangle, sim: ^Simulator) {
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()
for entry, i in sim.disasm { 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
txt := fmt.tprintf("%d : %s", i, entry.str) txt := fmt.tprintf("%d : %s", i, entry.str)
@@ -58,4 +63,21 @@ gui_tab_disasm :: proc(rect: rl.Rectangle, sim: ^Simulator) {
txt_color, txt_color,
) )
} }
if sim.disasm_follow {
for entry, i in sim.disasm[:sim.disasm_count] {
if entry.address == sim.machine.pc {
target_y := f32(i) * LINE_HEIGHT
visible_height := panel_rect.height
// Center the active instruction in the panel
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)
sim.disasm_scroll.y = clamp(sim.disasm_scroll.y, max_scroll, 0)
break
}
}
}
} }