module Tchipi8::Opcodes

Extended Modules

Defined in:

opcodes.cr

Constant Summary

ADD = define_opcode(32767.to_u16, "add", 45) do |chip8, instruction| x = (instruction & 3840) >> 8 k = instruction & 255 chip8.v[x] = ((chip8.v[x].to_u16 + k) & 255).to_u8 end

Add k to register vX

ADDI = define_opcode(65310.to_u16, "addi", 86) do |chip8, instruction| x = (instruction & 3840) >> 8 chip8.i = chip8.i &+ chip8.v[x] end

Add vX to I

ADDV = define_opcode(36852.to_u16, "addv", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 result = chip8.v[x].to_u16 + chip8.v[y] chip8.v[x] = (result & 255).to_u8 chip8.v[15] = (result > 255 ? 1 : 0).to_u8 end

Set vX to result of vX + vY, setting vF to 0 or 1 if overflow or not even if X == F

AND = define_opcode(36850.to_u16, "and", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 __temp_51 = x __temp_52 = chip8.v __temp_52[__temp_51] = __temp_52[__temp_51] & chip8.v[y] chip8.v[15] = 0 end

Set vX to result of vX & vY

CALL = define_opcode(12287.to_u16, "call", 105) do |chip8, instruction| chip8.stack.push(chip8.pc) chip8.pc = instruction & 4095 Log.debug do "Jumped to #{chip8.pc.to_s(16)}" end end

Push current address onto stack and call subroutine

CLS = define_opcode(224.to_u16, "cls", 109) do |chip8, instruction| (0...chip8.pixels.size).each do |row| (0...chip8.pixels[row].size).each do |col| chip8.pixels[row][col] = 0 end end chip8.io.clear_pixels end

Clear screen

COPY = define_opcode(36848.to_u16, "copy", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 chip8.v[x] = chip8.v[y] end

Copy value from register vY into vX

DRAW = define_opcode(57343.to_u16, "draw", 8333) do |chip8, instruction| x = (3840 & instruction) >> 8 y = (240 & instruction) >> 4 n = 15 & instruction dirty_pixels = [] of Tuple(Int32, Int32) has_unset_pixel = false start_x = (chip8.v[x] % IO::CHIP8_DISPLAY_WIDTH).to_i32 start_y = (chip8.v[y] % IO::CHIP8_DISPLAY_HEIGHT).to_i32 (0...n).each do |row| pixmap = chip8.memory[chip8.i + row] (0...8).each do |col| pixel = (pixmap >> ((8 - col) - 1)) & 1 adjusted_col = start_x + col adjusted_row = start_y + row if adjusted_row >= chip8.pixels.size || adjusted_col >= chip8.pixels[0].size Log.warn do "Attempted to write out of bounds: (#{adjusted_col}, #{adjusted_row})" end break end if (pixel == 1) && (chip8.pixels[adjusted_row][adjusted_col] == 1) has_unset_pixel = true end __temp_55 = adjusted_col __temp_56 = chip8.pixels[adjusted_row] __temp_56[__temp_55] = __temp_56[__temp_55] ^ pixel dirty_pixels << {adjusted_col, adjusted_row} end end if has_unset_pixel chip8.v[15] = 1 end dirty_pixels.each do |col, row| chip8.io.set_pixel(col, row, chip8.pixels[row][col].zero? ? IO::PixelState::Off : IO::PixelState::On) end end

Draw sprite at position [vX, vY] using sprite data from location I[0..N]

JMP = define_opcode(8191.to_u16, "jmp", 105) do |chip8, instruction| chip8.pc = instruction & 4095 Log.debug do "Jumped to #{chip8.pc.to_s(16)}" end end

Jump to address

JMPNAS = define_opcode(4095.to_u16, "jmpnas", 105) do |chip8, instruction| end

Jump to native assembler subroutine

JMPREL = define_opcode(49151.to_u16, "jmprel", 105) do |chip8, instruction| n = instruction & 4095 chip8.pc = chip8.v[0].to_u16 + n end

Jump to v0 + k

LSHIFT = define_opcode(36862.to_u16, "lshift", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 shifted_out = (chip8.v[y] & 128) >> 7 chip8.v[x] = chip8.v[y] << 1 chip8.v[15] = shifted_out end

Set vX to result of vY << 1, setting vF to shifted out bit even if X == F

MOV = define_opcode(65381.to_u16, "mov", 605) do |chip8, instruction| x = (instruction & 3840) >> 8 (0..x).each do |i| if (chip8.i + i) >= chip8.memory.size break end chip8.v[i] = chip8.memory[chip8.i + i] end end

Copy I[0,X] to v[0,X]

MOVM = define_opcode(65365.to_u16, "movm", 605) do |chip8, instruction| x = (instruction & 3840) >> 8 (0..x).each do |i| if (chip8.i + i) >= chip8.memory.size break end chip8.memory[chip8.i + i] = chip8.v[i] end end

Copy v[0,X] to I[0,X]

MOVMBCD = define_opcode(65331.to_u16, "movmbcd", 927) do |chip8, instruction| x = (instruction & 3840) >> 8 rem = chip8.v[x] if chip8.i < chip8.memory.size chip8.memory[chip8.i], rem = rem.divmod(100) end if (chip8.i + 1) < chip8.memory.size chip8.memory[chip8.i + 1], rem = rem.divmod(10) end if (chip8.i + 2) < chip8.memory.size chip8.memory[chip8.i + 2] = rem % 10 end end

Copy vX as BCD to I[0,2]

OR = define_opcode(36849.to_u16, "or", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 __temp_49 = x __temp_50 = chip8.v __temp_50[__temp_49] = __temp_50[__temp_49] | chip8.v[y] chip8.v[15] = 0 end

Set vX to result of vX | vY

RAND = define_opcode(53247.to_u16, "rand", 164) do |chip8, instruction| x = (instruction & 3840) >> 8 n = instruction & 255 chip8.v[x] = ((Random.new.rand(255)) & n).to_u8 end

Set vX to random value AND-ed with k (byte)

READKEY = define_opcode(65290.to_u16, "readkey", 0) do |chip8, instruction| if chip8.hault else chip8.pc = chip8.pc - 2 chip8.hault = true chip8.custom_flags[:key_read] = false end key = chip8.io.read_key if key && key[:state].released? x = (3840 & instruction) >> 8 chip8.v[x] = key[:key] chip8.custom_flags[:key_read] = true chip8.sound_timer = 1 else if chip8.custom_flags[:key_read] && (chip8.sound_timer == 0) chip8.hault = false chip8.pc = chip8.pc + 2 chip8.custom_flags.delete(:key_read) end end end

Read next key pressed, write it to vX (clear screen in Megachip mode)

RET = define_opcode(238.to_u16, "ret", 105) do |chip8, instruction| chip8.pc = chip8.stack.pop end

Return from subroutine

RSHIFT = define_opcode(36854.to_u16, "rshift", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 shifted_out = chip8.v[y] & 1 chip8.v[x] = chip8.v[y] >> 1 chip8.v[15] = shifted_out end

Set vX to result of vY >> 1, setting vF to shifted out bit even if X == F

RSUBV = define_opcode(36855.to_u16, "rsub", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 is_underflowing = chip8.v[y] < chip8.v[x] chip8.v[x] = chip8.v[y] &- chip8.v[x] chip8.v[15] = (is_underflowing ? 0 : 1).to_u8 end

Set vX to result of vY - vX, setting vF to 0 or 1 if underflow or not even if X == F

SET = define_opcode(28671.to_u16, "set", 27) do |chip8, instruction| x = (instruction & 3840) >> 8 chip8.v[x] = (instruction & 255).to_u8 end

Set register vX to k

SETDV = define_opcode(65301.to_u16, "setdv", 45) do |chip8, instruction| x = (instruction & 3840) >> 8 chip8.delay_timer = chip8.v[x] end

Set delay timer from vX

SETI = define_opcode(45055.to_u16, "seti", 55) do |chip8, instruction| chip8.i = 4095.to_u16 & instruction end

Set register I to k

SETIV = define_opcode(65321.to_u16, "setiv", 91) do |chip8, instruction| x = (instruction & 3840) >> 8 chip8.i = 15.to_u16 & chip8.v[x] end

Copy vX's low nibble to I

SETSV = define_opcode(65304.to_u16, "setsv", 45) do |chip8, instruction| x = (instruction & 3840) >> 8 chip8.sound_timer = chip8.v[x] end

Set sound timer from vX (beep as long as sound timer > 0)

SETVD = define_opcode(65287.to_u16, "setvd", 45) do |chip8, instruction| x = (instruction & 3840) >> 8 chip8.v[x] = chip8.delay_timer end

Copy delay timer value to vX

SKIPIFEQ = define_opcode(16383.to_u16, "skipifeq", 55) do |chip8, instruction| x = (instruction & 3840) >> 8 k = instruction & 255 if chip8.v[x] == k chip8.pc = chip8.pc + 2 end end

Skip next opcode if vX register is equal to k

SKIPIFEQV = define_opcode(24560.to_u16, "skipifeqv", 73) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 if chip8.v[x] == chip8.v[y] chip8.pc = chip8.pc + 2 end end

Skip next opcode if register vX == vY

SKIPIFKEY = define_opcode(61342.to_u16, "skipifkey", 73) do |chip8, instruction| x = (3840 & instruction) >> 8 chip8.io.read_key.try do |key| if (key[:key] == (chip8.v[x] & 15)) && key[:state].pressed? chip8.pc = chip8.pc + 2 end end end

Skip next opcode if key pressed matches lower 4 bits of vX

SKIPIFNEQ = define_opcode(20479.to_u16, "skipifneq", 55) do |chip8, instruction| x = (instruction & 3840) >> 8 k = instruction & 255 if chip8.v[x] != k chip8.pc = chip8.pc + 2 end end

Skip next opcode if vX is not equal to k

SKIPIFNEQV = define_opcode(40944.to_u16, "skipifneqv", 73) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 if chip8.v[x] != chip8.v[y] chip8.pc = chip8.pc + 2 end end

Skip next opcode if vX != vY

SKIPIFNKEY = define_opcode(61345.to_u16, "skipifnkey", 73) do |chip8, instruction| x = (3840 & instruction) >> 8 key = chip8.io.read_key if key.nil? || ((key[:key] != (chip8.v[x] & 15)) && key[:state].pressed?) chip8.pc = chip8.pc + 2 end end

Skip next opcode if lower 4 bits of vX don't match key pressed

SUBV = define_opcode(36853.to_u16, "sub", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 is_underflowing = chip8.v[x] < chip8.v[y] chip8.v[x] = chip8.v[x] &- chip8.v[y] chip8.v[15] = (is_underflowing ? 0 : 1).to_u8 end

Set vX to result of vX - vY, setting vF to 0 or 1 if underflow or not even if X == F

XOR = define_opcode(36851.to_u16, "xor", 200) do |chip8, instruction| x = (instruction & 3840) >> 8 y = (instruction & 240) >> 4 __temp_53 = x __temp_54 = chip8.v __temp_54[__temp_53] = __temp_54[__temp_53] ^ chip8.v[y] chip8.v[15] = 0 end

Set vX to result of vX ^ vY

Instance Method Summary

Instance Method Detail

def define_opcode(hex_code : UInt16, name : String, micros : Int32, &operation : Chip8, UInt16 -> Nil) #

[View source]