module Tchipi8::Opcodes
Extended Modules
Defined in:
opcodes.crConstant 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