Continued adding next instructions

This commit is contained in:
2026-05-20 21:42:09 +02:00
parent ac19813b4c
commit b3ed78097c
+91 -16
View File
@@ -30,10 +30,19 @@ cycle :: proc(s: ^System) {
case 0x0:
switch opcode {
case 0x00E0: op_cls(s)
case 0x00EE: op_ret(s, opcode)
}
case 0x1: op_jp_add(s, opcode)
case 0x2: op_call_add(s, opcode)
case 0x3: op_skip_on_condition(s, opcode, true)
case 0x4: op_skip_on_condition(s, opcode, false)
case 0x5: op_skip_reg_condition(s, opcode, true)
case 0x6: op_ld(s, opcode)
case 0x7: op_add(s, opcode)
// todo 0x8 with last bit for ALU
case 0x9: op_skip_reg_condition(s, opcode, false)
case 0xA: op_set(s, opcode)
case 0xD: op_draw(s, opcode)
}
@@ -54,12 +63,68 @@ op_cls :: proc(s: ^System) {
s.display = {}
}
// RET: Return from a subroutine.
op_ret :: proc(s: ^System, opcode: u16) {
// decrement sp to the previous used slot
// current sp will always be empty
s.sp -= 1
// restore the pc from where we called from
s.pc = s.stack[s.sp]
}
// JP addr: Jump to location nnn
op_jp_add :: proc(s: ^System, opcode: u16) {
addr := (opcode & 0x0FFF)
s.pc = addr
}
// Call addr: Call subroutine at nnn.
op_call_add :: proc(s: ^System, opcode: u16) {
addr := (opcode & 0x0FFF)
// Save current pc to stack for return location
s.stack[s.sp] = s.pc
// advance sp for next free slot
s.sp += 1
s.pc = addr
}
// SE: Skip next instruction if Vx = kk.
// SNE: Skip next instruction if Vx != kk.
op_skip_on_condition :: proc(s: ^System, opcode: u16, condition: bool) {
// Extract the register indices to get values
vx_index := (opcode & 0x0F00) >> 8
register_val := s.v[vx_index]
// Extract value to compare
op_val := u8(opcode & 0x00FF)
if (register_val == op_val) == condition {
s.pc += 2
}
}
// SE Vx, Vy: Skip next instruction if Vx = Vy
// SNE Vx, Vy: Skip next instruction if Vx != Vy.
op_skip_reg_condition :: proc(s: ^System, opcode: u16, condition: bool) {
// Extract the register indices
vx_index := (opcode & 0x0F00) >> 8
vy_index := (opcode & 0x00F0) >> 4
// Read the actual value from the registers.
rx := s.v[vx_index]
ry := s.v[vy_index]
if (rx == ry) == condition {
s.pc += 2
}
}
// continue Bnnn
// LD: Load value kk into x register
op_ld :: proc(s: ^System, opcode: u16) {
register := (opcode & 0x0F00) >> 8
@@ -83,34 +148,44 @@ op_set :: proc(s: ^System, opcode: u16) {
// DRAW: Display n-byte sprite starting at memory location I at (Vx, Vy), set VF = collision.
op_draw :: proc(s: ^System, opcode: u16) {
x_register := (opcode & 0x0F00) >> 8
y_register := (opcode & 0x00F0) >> 4
// Extract the register indices that hold the sprite's X and Y screen position
vx_index := (opcode & 0x0F00) >> 8
vy_index := (opcode & 0x00F0) >> 4
// Handle wrapping
x_coord := (s.v[x_register] & 0x03F)
y_coord := (s.v[y_register] & 0x1F)
// Read the actual coordinates from those registers.
// Wrap to screen bounds: 64 wide (0x3F mask), 32 tall (0x1F mask)
screen_x := s.v[vx_index] & 0x3F
screen_y := s.v[vy_index] & 0x1F
// VF is the collision flag — clear it before drawing
s.v[0xF] = 0
n_bytes := (opcode & 0x000F)
// Number of rows in the sprite (1 byte per row, each byte = 8 pixels)
sprite_height := opcode & 0x000F
for row in 0..<n_bytes {
sprite_row := s.memory[s.i + row]
// log.debugf("sr: 0x%X", sprite_row)
for row in 0..<sprite_height {
// Each byte in memory is one row of 8 pixels, MSB is the leftmost pixel
sprite_row_bits := s.memory[s.i + row]
for col in 0..<8 {
mask := u8(0x80) >> u8(col)
// Shift a 1 from the MSB right to isolate the bit at this column
bit_mask := u8(0x80) >> u8(col)
if sprite_row & mask != 0 {
// this bit is set Xor the pixel
y_pos := ((y_coord + u8(row)) % 32)
x_pos := ((x_coord + u8(col)) % 64)
// Only draw if this bit in the sprite is set
if sprite_row_bits & bit_mask != 0 {
// Wrap the draw position if the sprite goes off-screen
pixel_x := (screen_x + u8(col)) % 64
pixel_y := (screen_y + u8(row)) % 32
pixel := &s.display[y_pos][x_pos]
pixel := &s.display[pixel_y][pixel_x]
// CHIP-8 XORs pixels — if we're about to unset a lit pixel, that's a collision
if pixel^ == 1 {
s.v[0xF] = 1
}
pixel^ = pixel^ ~ 1
// XOR the pixel: toggles it on if off, off if on
pixel^ ~= 1
}
}
}