├── 48.ROM ├── LICENSE.md ├── README.md ├── display.lua ├── file_format ├── loader.lua ├── sna.lua ├── tap.lua └── z80.lua ├── logger.lua ├── machine.lua ├── machine └── spectrum_48.lua ├── main.lua ├── opcodes ├── cb.lua ├── common.lua ├── daa.lua ├── dd.lua ├── ddcb.lua ├── ed.lua ├── fd.lua └── fdcb.lua ├── port.lua └── z80.lua /48.ROM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ignacio/luagleck/bd342a920bc67de48764327c9e881d3e15bc3a4d/48.ROM -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Ignacio Burgueño 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # luagleck 2 | A ZX Spectrum emulator written in Lua 5.3. 3 | 4 | 5 | ## Usage 6 | `lua53 main.lua` 7 | 8 | Or `lua53 main.lua filename` to load an existing snapshot or tape file. 9 | -------------------------------------------------------------------------------- /display.lua: -------------------------------------------------------------------------------- 1 | local logger = require "logger" 2 | local SDL = require "SDL" 3 | 4 | 5 | -- Calculo tablas para acelerar el acceso al video del Spectrum 6 | -- arrays de words 7 | 8 | -- Given the vertical coordinate of a pixel, gives the starting memory address for the pixels of the corresponding 9 | -- pixel row. 10 | local D_PixelAddressArray = {} 11 | for y = 0, 191 do 12 | D_PixelAddressArray[y] = 0x4000 + ((y >> 6) << 11) + (((y >> 3) & 0x07) << 5) + ((y & 0x07) << 8) 13 | end 14 | 15 | -- Given the vertical coordinate of a pixel, gives the starting memory address for the attributes of the corresponding 16 | -- character row. 17 | local D_AttribArray = {} 18 | for y = 0, 191 do 19 | D_AttribArray[y] = 0x5800 + ((y >> 3) << 5) 20 | end 21 | 22 | -- Attribute matrix [32,24] 23 | local D_Atributos = {} 24 | for i = 0,31 do 25 | D_Atributos[i] = {} 26 | end 27 | 28 | --BYTE D_Atributos[32][24]; 29 | -- hack para saber si algo cambio en la pantalla, muy berreta 30 | local dirty_pixels = {} 31 | local dirty_attributes = {} 32 | for i = 0, 191 do 33 | dirty_attributes[i] = {} 34 | end 35 | 36 | 37 | --- 38 | -- TODO: Move this to a 'model' module. This values change with the machine type 39 | -- 40 | local M_lineasBordeSup = 64 41 | local M_lineasBordeInf = 56 42 | local M_anchoBordeDer = 48 43 | local M_anchoBordeIzq = 48 44 | 45 | 46 | 47 | 48 | -- 24 bit colours 49 | -- BRIGHT disabled 50 | local colours_bright_off = {} 51 | colours_bright_off[0] = (0x00000000); 52 | colours_bright_off[1] = 159; 53 | colours_bright_off[2] = (223<<16); 54 | colours_bright_off[3] = ((224<<16)|(176)); 55 | colours_bright_off[4] = (208<<8); 56 | colours_bright_off[5] = ((208<<8)|(208)); 57 | colours_bright_off[6] = ((207<<16)|(207<<8)); 58 | colours_bright_off[7] = ((192<<16)|(199<<8)|(192)); 59 | 60 | -- BRIGHT enabled 61 | local colours_bright_on = {} 62 | colours_bright_on[0] = (0x00000000); 63 | colours_bright_on[1] = 175; 64 | colours_bright_on[2] = (239<<16); 65 | colours_bright_on[3] = ((255<<16)|(223)); 66 | colours_bright_on[4] = (239<<8); 67 | colours_bright_on[5] = ((248<<8)|(255)); 68 | colours_bright_on[6] = ((255<<16)|(248<<8)); 69 | colours_bright_on[7] = ((255<<16)|(248<<8)|(255)); 70 | 71 | 72 | local display = {} 73 | 74 | -- the one and only renderer 75 | local rdr 76 | 77 | display.flash_on = false 78 | display.flash_counter = 0 79 | display.machine = nil 80 | 81 | local function draw_entire_screen_no_border (cpu) 82 | 83 | local read_mem_byte_internal = display.machine.memory.read_mem_byte_internal 84 | 85 | local D_tinta, D_papel 86 | for y = 0, 23 do 87 | for x = 0, 31 do 88 | D_Atributos[x][y] = read_mem_byte_internal(cpu, x + D_AttribArray[y << 3]) 89 | end 90 | end 91 | 92 | for y = 0, 191 do 93 | local linea = y >> 3 94 | for x = 0, 31 do 95 | local D_Attrib = D_Atributos[x][linea] 96 | local D_PixelGroup = read_mem_byte_internal(cpu, x + D_PixelAddressArray[y]) 97 | 98 | if display.flash_on or (D_Attrib & 0x80 ~= 0) then -- flash? 99 | D_tinta = (D_Attrib & 0x38) >> 3 100 | D_papel = D_Attrib & 0x07 101 | else 102 | D_tinta = D_Attrib & 0x07 103 | D_papel = (D_Attrib & 0x38) >> 3 104 | end 105 | 106 | -- Bright ON ? 107 | local foreground, background 108 | if D_Attrib & 0x40 ~= 0 then 109 | foreground = colours_bright_on[D_tinta] 110 | background = colours_bright_on[D_papel] 111 | else 112 | foreground = colours_bright_off[D_tinta] 113 | background = colours_bright_off[D_papel] 114 | end 115 | 116 | -- If the pixels or the attributes of this 8x1 line have changed, repaint 117 | if dirty_pixels[x + D_PixelAddressArray[y]] ~= D_PixelGroup or 118 | dirty_attributes[x][y] ~= D_Attrib 119 | then 120 | dirty_pixels[x + D_PixelAddressArray[y]] = D_PixelGroup 121 | dirty_attributes[x][y] = D_Attrib 122 | 123 | for i = 7, 0, -1 do 124 | if D_PixelGroup & (1 << i) ~= 0 then 125 | rdr:setDrawColor(foreground) 126 | else 127 | rdr:setDrawColor(background) 128 | end 129 | rdr:drawPoint({x=x * 8 + 7 - i, y=y}) 130 | end 131 | end 132 | end 133 | end 134 | 135 | rdr:present() 136 | end 137 | 138 | 139 | local function draw_entire_screen_with_border (cpu) 140 | 141 | local color_borde = display.machine.ports.port_fe & 0x07 142 | local read_mem_byte_internal = display.machine.memory.read_mem_byte_internal 143 | 144 | rdr:setDrawColor(colours_bright_off[color_borde]) 145 | for y = 0, M_lineasBordeSup - 1 do 146 | rdr:drawLine({x1 = 0, y1 = y, x2 = M_anchoBordeIzq + 256 + M_anchoBordeDer, y2 = y}) 147 | end 148 | 149 | local D_tinta, D_papel 150 | for y = 0, 23 do 151 | for x = 0, 31 do 152 | D_Atributos[x][y] = read_mem_byte_internal(cpu, x + D_AttribArray[y << 3]) 153 | end 154 | end 155 | 156 | for y = 0, 191 do 157 | local linea = y >> 3 158 | 159 | rdr:setDrawColor(colours_bright_off[color_borde]) 160 | rdr:drawLine({x1 = 0, y1 = y + M_lineasBordeSup, x2 = M_anchoBordeIzq - 1, y2 = y + M_lineasBordeSup}) 161 | 162 | for x = 0, 31 do 163 | local D_Attrib = D_Atributos[x][linea] 164 | local D_PixelGroup = read_mem_byte_internal(cpu, x + D_PixelAddressArray[y]) 165 | 166 | -- TODO: flash does not work with the dirty attributes stuff 167 | if display.flash_on and (D_Attrib & 0x80 ~= 0) then -- flash? 168 | D_tinta = (D_Attrib & 0x38) >> 3 169 | D_papel = D_Attrib & 0x07 170 | else 171 | D_tinta = D_Attrib & 0x07 172 | D_papel = (D_Attrib & 0x38) >> 3 173 | end 174 | 175 | -- Bright ON ? 176 | local foreground, background 177 | if D_Attrib & 0x40 ~= 0 then 178 | foreground = colours_bright_on[D_tinta] 179 | background = colours_bright_on[D_papel] 180 | else 181 | foreground = colours_bright_off[D_tinta] 182 | background = colours_bright_off[D_papel] 183 | end 184 | 185 | -- If the pixels or the attributes of this 8x1 line have changed, repaint 186 | if dirty_pixels[x + D_PixelAddressArray[y] ] ~= D_PixelGroup or 187 | dirty_attributes[x][y] ~= D_Attrib 188 | then 189 | dirty_pixels[x + D_PixelAddressArray[y] ] = D_PixelGroup 190 | dirty_attributes[x][y] = D_Attrib 191 | 192 | -- draw the background 193 | rdr:setDrawColor(background) 194 | rdr:drawLine({x1 = x * 8 + M_anchoBordeIzq, y1 = y + M_lineasBordeSup, 195 | x2 = x * 8 + 7 + M_anchoBordeIzq, y2 = y + M_lineasBordeSup}) 196 | -- plot the foreground 197 | local points = {} 198 | rdr:setDrawColor(foreground) 199 | for i = 7, 0, -1 do 200 | if D_PixelGroup & (1 << i) ~= 0 then 201 | points[#points + 1] = {x = x * 8 + 7 - i + M_anchoBordeIzq, y = y + M_lineasBordeSup} 202 | else 203 | end 204 | end 205 | rdr:drawPoints(points) 206 | end 207 | end 208 | 209 | rdr:setDrawColor(colours_bright_off[color_borde]) 210 | rdr:drawLine({x1 = M_anchoBordeIzq + 256, y1 = y + M_lineasBordeSup, x2 = M_anchoBordeIzq + 256 + M_anchoBordeDer, y2 = y + M_lineasBordeSup}) 211 | end 212 | 213 | rdr:setDrawColor(colours_bright_off[color_borde]) 214 | for y = 0, M_lineasBordeInf do 215 | local offset = M_lineasBordeSup + 192 216 | rdr:drawLine({x1 = 0, y1 = offset + y, x2 = M_anchoBordeIzq + 256 + M_anchoBordeDer, y2 = offset + y}) 217 | end 218 | 219 | rdr:present() 220 | end 221 | 222 | 223 | 224 | --display.draw_screen = draw_entire_screen_no_border 225 | display.draw_screen = draw_entire_screen_with_border 226 | 227 | 228 | 229 | --- 230 | -- 231 | function display.initialize (win) 232 | local err 233 | rdr, err = SDL.createRenderer(win, 0, 1) 234 | if not rdr then 235 | error(err) 236 | end 237 | end 238 | 239 | 240 | --- 241 | -- Signal that attributes needs to be reversed. 242 | function display.toggle_flash () 243 | dirty_pixels = {} 244 | display.flash_on = not display.flash_on 245 | end 246 | 247 | function display.set_machine (machine) 248 | display.machine = machine 249 | end 250 | 251 | return display 252 | -------------------------------------------------------------------------------- /file_format/loader.lua: -------------------------------------------------------------------------------- 1 | local logger = require "logger" 2 | 3 | local module = {} 4 | 5 | --- 6 | -- Given a file name, try to guess the format and load it 7 | -- 8 | function module.load (machine, file_name) 9 | print(file_name) 10 | -- We're lazy and rely on the file extension 11 | local ext = file_name:match("%.(%w%w%w)$") 12 | if not ext then 13 | logger.info("Can't recognize file '%s'", file_name) 14 | return false 15 | end 16 | 17 | local f, err = io.open(file_name, "rb") 18 | if not f then 19 | logger.error("%s", err) 20 | return false 21 | end 22 | local data = f:read("*a") 23 | f:close() 24 | 25 | local ok, handler = pcall(require, "file_format."..ext:lower()) 26 | if not ok then 27 | logger.info("Can't load '%s' files", ext) 28 | return false 29 | end 30 | 31 | return handler.load(machine, data) 32 | end 33 | 34 | return module 35 | -------------------------------------------------------------------------------- /file_format/sna.lua: -------------------------------------------------------------------------------- 1 | local logger = require "logger" 2 | 3 | local RETN = require ("opcodes.ed")[0x45] -- grab the RETN function 4 | 5 | local sna = {} 6 | 7 | local function high_low (value) 8 | return (value & 0xff00) >> 8, value & 0x00ff 9 | end 10 | 11 | -- TODO: Move get_locals and parse to a another module, so we can reuse them. 12 | local function get_locals (level) 13 | level = (level + 1) or 2 14 | 15 | local t, i = {}, 1 16 | local name = debug.getlocal(level, i) 17 | while name and name:sub(1,1) ~= "(" do 18 | t[name] = i 19 | i = i + 1 20 | name = debug.getlocal(level, i) 21 | end 22 | return t 23 | end 24 | 25 | local function parse (pattern, data) 26 | local locs, options = {}, {} 27 | 28 | for option, loc in pattern:gmatch("([%p%w]-)%s*%->%s*([%w%p]-)\n") do 29 | table.insert(options, option) 30 | table.insert(locs, loc) 31 | end 32 | local parent_locals = get_locals(2) -- Get the locals of the caller 33 | local matches = { string.unpack(table.concat(options), data) } 34 | matches[#matches] = nil -- Remove unneeded last value from unpack (first unread byte) 35 | for i, match in ipairs(matches) do 36 | local l_name = locs[i] 37 | debug.setlocal(2, parent_locals[l_name], match) 38 | end 39 | end 40 | 41 | local function load48 (machine, data) 42 | machine.cpu:reset() 43 | 44 | local I, HLp, DEp, BCp, AFp, HL, DE, BC, IY, IX, IFF2, R, F, A, SP, int_mode, FE, bank1, bank2, bank3 45 | parse([[ 46 | I 47 | I2 -> HLp 48 | I2 -> DEp 49 | I2 -> BCp 50 | I2 -> AFp 51 | I2 -> HL 52 | I2 -> DE 53 | I2 -> BC 54 | I2 -> IY 55 | I2 -> IX 56 | B -> IFF2 57 | B -> R 58 | B -> F 59 | B -> A 60 | I2 -> SP 61 | B -> int_mode 62 | B -> FE 63 | c16384 -> bank1 64 | c16384 -> bank2 65 | c16384 -> bank3 66 | ]], 67 | data) 68 | 69 | local cpu = machine.cpu 70 | local memory = machine.memory 71 | local ports = machine.ports 72 | 73 | memory.set_bank(1, bank1) 74 | memory.set_bank(2, bank2) 75 | memory.set_bank(3, bank3) 76 | 77 | cpu.A = A 78 | cpu.F = F 79 | cpu.H, cpu.L = high_low(HL) 80 | 81 | cpu.B, cpu.C = high_low(BC) 82 | cpu.D, cpu.E = high_low(DE) 83 | cpu.IX = IX 84 | cpu.IY = IY 85 | 86 | if IFF2 & 0x04 ~= 0 then 87 | cpu.iff1, cpu.iff2 = 1, 1 88 | else 89 | cpu.iff1, cpu.iff2 = 0, 0 90 | end 91 | cpu.I = I 92 | cpu.int_mode = int_mode 93 | cpu.SP = SP 94 | cpu.R = R 95 | cpu.tstates = 0 96 | cpu.halted = false 97 | ports.port_fe = FE 98 | 99 | cpu.Ap, cpu.Fp = high_low(AFp) 100 | cpu.Hp, cpu.Lp = high_low(HLp) 101 | cpu.Bp, cpu.Cp = high_low(BCp) 102 | cpu.Dp, cpu.Ep = high_low(DEp) 103 | 104 | -- I should redraw the screen first 105 | RETN(cpu) 106 | 107 | return true 108 | end 109 | 110 | function sna.load (machine, data) 111 | 112 | if #data == 49179 then 113 | -- 48K snapshot 114 | return load48(machine, data) 115 | 116 | elseif #data == 131103 then 117 | error("128K snapshots are not supported") 118 | end 119 | end 120 | 121 | return sna 122 | -------------------------------------------------------------------------------- /file_format/tap.lua: -------------------------------------------------------------------------------- 1 | local logger = require "logger" 2 | local tap = {} 3 | 4 | local FLAG_C = 1 5 | local FLAG_C_OFF = 254 6 | 7 | local blocks -- move this into a tap table 8 | local current_block 9 | 10 | 11 | local function compute_checksum (data, length) 12 | local checksum = 0 13 | for i = 1, length do 14 | checksum = checksum ~ data:byte(i) 15 | end 16 | return checksum 17 | end 18 | 19 | 20 | --- 21 | -- Loads and stoes in the memory a block of data. Also computes and returns the checksum. 22 | -- The checksum is computed xor'ing each byte of data. 23 | -- 24 | local function load_block_to_memory (machine, data, start_address, length) 25 | --logger.debug("[tap.load_block_to_memory] start_address: 0x%04x, length: %04x, data length: %04x", 26 | -- start_address, length, #data) 27 | 28 | local checksum = 0 29 | for i = 0, length - 1 do 30 | local byte = data:byte(i + 1) 31 | machine.memory.write_mem_byte_internal(machine.cpu, (start_address + i) & 0xffff, byte) 32 | checksum = checksum ~ byte 33 | end 34 | 35 | return checksum 36 | end 37 | 38 | 39 | --- 40 | -- block_id: byte 41 | -- start_address: word 42 | -- length: word 43 | -- 44 | local function load_block (machine, block_id, start_address, length) 45 | 46 | if not blocks then return false end 47 | local current = blocks[current_block] 48 | if not current then 49 | current_block = 1 50 | return false 51 | end 52 | 53 | while current.flag ~= block_id do 54 | current_block = current_block + 1 55 | current = blocks[current_block] 56 | if not current then 57 | -- wrapped around tape while looking for block 58 | current_block = 1 59 | return false 60 | end 61 | end 62 | 63 | local cpu = machine.cpu 64 | 65 | if length <= current.dwBlockLength then 66 | -- found a block with the appropiate length 67 | --logger.debug("right block") 68 | local checksum = load_block_to_memory(machine, current.data:sub(2), start_address, length) 69 | checksum = checksum ~ current.flag 70 | 71 | --logger.debug("checksum = %s, block checksum = %s", checksum, current.bChecksum) 72 | cpu.H = (checksum == current.bChecksum) and 0 or 255 73 | cpu.IX = (cpu.IX + length) & 0xffff 74 | cpu.D, cpu.E = 0, 0 75 | -- go to next block 76 | current_block = current_block + 1 77 | return true 78 | else 79 | -- the block is shorter than the one requested. 80 | -- read it anyway, but signal an error 81 | logger.debug("wrong block") 82 | 83 | local checksum = load_block_to_memory(machine, current.data, start_address, current.dwBlockLength) 84 | checksum = checksum ~ current.flag 85 | 86 | cpu.H = (checksum == current.bChecksum) and 0 or 255 87 | cpu.IX = (cpu.IX + length) & 0xffff 88 | cpu.D, cpu.E = 0, 0 89 | return false 90 | end 91 | end 92 | 93 | --- 94 | -- called when the machine needs to hook into the tape loading process 95 | -- 96 | function tap.load_hook (machine) 97 | 98 | local cpu = machine.cpu 99 | local DE = cpu.E | cpu.D << 8 100 | logger.debug("[tap.load_hook] Requested flag: %02x, destination: %04x, length: %04x", 101 | cpu.Ap, cpu.IX, DE) 102 | 103 | if not load_block(machine, cpu.Ap, cpu.IX, DE) then 104 | cpu.Fp = cpu.Fp & FLAG_C_OFF 105 | else 106 | cpu.F = cpu.F | FLAG_C 107 | end 108 | 109 | cpu.PC = 0x056b 110 | end 111 | 112 | 113 | --- 114 | -- Scans a TAP file, loading its blocks into memory. 115 | -- 116 | local function scan_tap (data) 117 | local block_number = 0 118 | local blocks = {} 119 | 120 | local tape_length = #data 121 | 122 | local i = 1 123 | while i <= tape_length do 124 | local block = {} 125 | block.block_number = block_number 126 | block.dwPosicion = i 127 | local len, flag, type = string.unpack("> 8, value & 0x00ff 9 | end 10 | 11 | --- 12 | -- TODO: Documentar que diablos hacia esto 13 | local function GetPaginaBloque (blocknum) 14 | if blocknum == 0 then 15 | -- ROM 16 | return 0--3 17 | elseif blocknum == 4 then 18 | -- 0x8000 - 0xbfff 19 | return 2--1 20 | elseif blocknum == 5 then 21 | -- 0xc000 - 0xffff 22 | return 3--2 23 | elseif blocknum == 8 then 24 | -- 0x4000 - 0x7fff 25 | return 1--0 26 | end 27 | 28 | return 0 29 | end 30 | 31 | --- 32 | -- Decompresses and loads into RAM a possibly RLE compressed block. 33 | -- 34 | local function uncompress_z80_block (machine, data, address, length) 35 | local offset = 0 36 | address = address or 0x4000 -- start at screem address by default 37 | length = length or #data 38 | 39 | while offset < length do 40 | --local ok, b1, b2, b3, b4 = pcall(string.unpack, "< B B B B", data, offset + 1) 41 | local b1, b2, b3, b4 = string.byte(data, offset + 1, offset + 5) 42 | -- if not ok then 43 | -- logger.error("#data= %s, offset + 1=%s,length=%s", #data, offset + 1, length) 44 | -- return 45 | -- end 46 | 47 | -- Check for '00eded00', the 'end of file' marker 48 | if b1 == 0 and b2 == 0xed and b3 == 0xed and b4 == 0 then 49 | return 50 | end 51 | 52 | if b1 == 0xed and b2 == 0xed then 53 | -- Found a compressed (RLE) block. It consists of four bytes: 54 | -- byte 0-1: ED, ED 55 | -- byte 2: block length (b3) 56 | -- byte 3: value (b4) 57 | -- So we write 'b3' times the value 'b4' to the memory 58 | local block_len = b3 59 | for off = 0, block_len - 1 do 60 | machine.memory.write_mem_byte_internal(machine.machine, (address + off) & 0xffff, b4) 61 | --memory.write_mem_byte_rom(cpu, (address + off) & 0xffff, b4) 62 | end 63 | --display.draw_screen(cpu) 64 | address = address + block_len 65 | offset = offset + 4 66 | 67 | else 68 | -- Found a regular value. 69 | machine.memory.write_mem_byte_internal(machine.cpu, address & 0xffff, b1) 70 | --memory.write_mem_byte_rom(cpu, address & 0xffff, b1) 71 | address = address + 1 72 | offset = offset + 1 73 | end 74 | end 75 | end 76 | 77 | 78 | --- 79 | -- 80 | local function load_z80_v2 (machine, data) 81 | local offset = 0 82 | local address 83 | 84 | while offset < #data do 85 | --display.draw_screen(cpu) 86 | local block_len, block_code = string.unpack("< I2 B", data, offset + 1) 87 | print("1:", offset, #data, block_code) 88 | offset = offset + 3 89 | --print("block_code", block_code) 90 | address = GetPaginaBloque(block_code) * 16384 -- TODO: that function belongs to a model 91 | if block_len == 0xffff then 92 | -- the block is 0x4000 bytes long and is not compressed 93 | error("ffff") 94 | else 95 | print("address", address, "block_len", block_len) 96 | uncompress_z80_block(machine, data:sub(offset + 1), address, block_len) 97 | offset = offset + block_len 98 | end 99 | end 100 | end 101 | 102 | 103 | --- 104 | -- 105 | local function load_z80_v3 (machine, data) 106 | error("load_z80_v3 not actually implemented") 107 | local offset = 0 108 | local address 109 | 110 | while offset < #data do 111 | --display.draw_screen(cpu) 112 | local block_len, block_code = string.unpack("< I2 B", data, offset + 1) 113 | print("1:", offset, #data, block_code) 114 | offset = offset + 3 115 | --print("block_code", block_code) 116 | address = GetPaginaBloque(block_code) * 16384 -- TODO: that function belongs to a model 117 | if block_len == 0xffff then 118 | -- the block is 0x4000 bytes long and is not compressed 119 | error("ffff") 120 | else 121 | print("address", address, "block_len", block_len) 122 | uncompress_z80_block(machine, data:sub(offset + 1), address, block_len) 123 | offset = offset + block_len 124 | end 125 | end 126 | end 127 | 128 | 129 | --- 130 | -- 131 | local function load_z80_v2_v3 (machine, data) 132 | -- header_len: //byte 30 y 31: largo de la cabecera (23 para v2, 54 para v3) 133 | -- PC: byte 32 y 33: PC 134 | -- model_type: /byte 34: modo de hardware 135 | -- out_7ffd: byte 35: ultimo OUT a puerto 7FFD 136 | -- byte 36,37: we don't handle them 137 | -- out_fffd: byte 38: ultimo OUT a puerto 7FFD 138 | -- ay_registers: bytes 39-54 state of each AY register 139 | 140 | local v2_v3_header = " the snapshot is compressed 250 | local compressed = (byte12 & 0x20 ~= 0) 251 | 252 | port.port_fe = (byte12 & 0x0e) >> 1 -- border colour 253 | -- bit 4 - 1 if SamROM switched in (we don't care about this!) 254 | 255 | cpu.A = A 256 | cpu.F = F 257 | cpu.H, cpu.L = high_low(HL) 258 | 259 | cpu.B, cpu.C = high_low(BC) 260 | cpu.D, cpu.E = high_low(DE) 261 | cpu.IX = IX 262 | cpu.IY = IY 263 | 264 | cpu.iff1 = iff1 ~= 0 265 | cpu.iff2 = iff2 ~= 0 266 | 267 | cpu.I = I 268 | cpu.int_mode = int_mode & 0x03 -- 0, 1, or 2 269 | cpu.SP = SP 270 | cpu.PC = PC 271 | cpu.R = R 272 | cpu.tstates = 0 273 | cpu.halted = false 274 | 275 | 276 | cpu.Ap, cpu.Fp = high_low(AFp) 277 | cpu.Hp, cpu.Lp = high_low(HLp) 278 | cpu.Bp, cpu.Cp = high_low(BCp) 279 | cpu.Dp, cpu.Ep = high_low(DEp) 280 | 281 | data = data:sub(31) 282 | 283 | if cpu.PC == 0 then 284 | load_z80_v2_v3(machine, data) 285 | else 286 | -- should set ROM to spectrum 48k 287 | if compressed then 288 | uncompress_z80_block(machine, data) 289 | else 290 | local bank1, bank2, bank3 = string.unpack("< c16384 c16384 c16384", data) 291 | machine.memory.set_bank(1, bank1) 292 | machine.memory.set_bank(2, bank2) 293 | machine.memory.set_bank(3, bank3) 294 | end 295 | end 296 | return true 297 | end 298 | 299 | return z80 300 | -------------------------------------------------------------------------------- /logger.lua: -------------------------------------------------------------------------------- 1 | local type, tostring, select = type, tostring, select 2 | local string_format = string.format 3 | local table_concat = table.concat 4 | local setmetatable = setmetatable 5 | local unpack = unpack or table.unpack 6 | 7 | local function LogArgumentsFormatter (...) 8 | local args = {...} 9 | for i = 1, select("#", ...) do 10 | local arg = args[i] 11 | local arg_type = type(arg) 12 | if arg_type ~= "string" and arg_type ~= "number" then 13 | args[i] = tostring(arg) 14 | end 15 | end 16 | return unpack(args) 17 | end 18 | 19 | local function ArgumentsToStrings (t, ...) 20 | for i = 1, select("#", ...) do 21 | local arg = select(i, ...) 22 | local arg_type = type(arg) 23 | if arg_type ~= "string" and arg_type ~= "number" then 24 | t[#t + 1] = tostring(arg) 25 | else 26 | t[#t + 1] = arg 27 | end 28 | end 29 | return t 30 | end 31 | 32 | local function BuildMessage (fmt, ...) 33 | local msg 34 | if type(fmt) ~= "string" then 35 | msg = { tostring(fmt) } 36 | ArgumentsToStrings(msg, ...) 37 | msg = table_concat(msg, "\t") 38 | else 39 | if fmt:find("%%") then 40 | msg = string_format(fmt, LogArgumentsFormatter(...)) 41 | else 42 | msg = { fmt } 43 | ArgumentsToStrings(msg, ...) 44 | msg = table_concat(msg, "\t") 45 | end 46 | end 47 | return msg 48 | end 49 | 50 | local function MakeLogger () 51 | local t = {} 52 | t.debug = function(fmt, ...) 53 | local msg = BuildMessage(fmt, ...) 54 | print("[DEBUG] " .. msg) 55 | return msg 56 | end 57 | 58 | t.info = function(fmt, ...) 59 | local msg = BuildMessage(fmt, ...) 60 | print("[INFO ] " .. msg) 61 | return msg 62 | end 63 | 64 | t.warning = function(fmt, ...) 65 | local msg = BuildMessage(fmt, ...) 66 | print("[WARN ] " .. msg) 67 | return msg 68 | end 69 | 70 | t.error = function(fmt, ...) 71 | local msg = BuildMessage(fmt, ...) 72 | print("[ERROR] " .. msg) 73 | return msg 74 | end 75 | 76 | t.fatal = function(fmt, ...) 77 | local msg = BuildMessage(fmt, ...) 78 | print("[FATAL] " .. msg) 79 | return msg 80 | end 81 | 82 | t.profile = function(fmt, ...) 83 | local msg = BuildMessage(fmt, ...) 84 | print("[PROFI] " .. msg) 85 | return msg 86 | end 87 | 88 | t.__tostring = function() 89 | return tostring(logger) 90 | end 91 | 92 | setmetatable(t, t) 93 | return t 94 | end 95 | 96 | return MakeLogger() 97 | -------------------------------------------------------------------------------- /machine.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- A machine represents a given model. A combination of a cpu, memory, a given ROM,. 3 | -- Each model has certain properties, like its timings, the frequency of the cpu, 4 | -- how it deals with contended memory, etc. 5 | 6 | local display = require "display" 7 | 8 | local machine = {} 9 | 10 | 11 | function machine.initialize (model_type) 12 | if model_type == "spectrum_48k" then 13 | local model = require("machine.spectrum_48") 14 | local m = model.initialize() 15 | display.set_machine(m) 16 | return m 17 | end 18 | end 19 | 20 | 21 | return machine 22 | -------------------------------------------------------------------------------- /machine/spectrum_48.lua: -------------------------------------------------------------------------------- 1 | local logger = require "logger" 2 | local z80 = require "z80" 3 | 4 | local display = require "display" 5 | local SDL = require "SDL" 6 | 7 | local port_handlers = require "port" 8 | 9 | -- helpers 10 | local function high_low (value) 11 | return (value & 0xff00) >> 8, value & 0x00ff 12 | end 13 | 14 | 15 | 16 | local lines_per_frame = 312 17 | local lines_upper_border = 64 18 | local cycles_left_border = 24 19 | local cycles_right_border = 24 20 | local cycles_per_line = 128 21 | local cycles_horizontal_retrace = 48 22 | local cycles_per_whole_line = cycles_per_line + cycles_right_border + cycles_horizontal_retrace + cycles_left_border 23 | local tstates_per_frame = lines_per_frame * cycles_per_whole_line 24 | 25 | 26 | local keyboard_issue = 3 27 | local testVal = 0x18 -- a byte, to determine whether is issue 2 or 3 28 | local issue = 0xff 29 | 30 | 31 | ---- 32 | -- Memory I/O 33 | local memory = {} 34 | 35 | local ram 36 | 37 | function memory.set_ram (_ram) 38 | ram = _ram 39 | end 40 | 41 | --- 42 | -- Copies 16K of data in the given bank 43 | function memory.set_bank (bank, data) 44 | local start = 16384 * bank 45 | for i = 0, 16383 do 46 | ram[start + i] = assert(string.byte(data:sub(i+1,i+1))) 47 | end 48 | end 49 | 50 | function memory.reset_bank (bank) 51 | local start = 16384 * bank 52 | for i = 0, 16383 do 53 | ram[start + i] = 0 54 | end 55 | end 56 | 57 | function memory.contend (cpu, address, tstates) -- (es una lectura) 58 | if address > 0xffff or address < 0 then error("contend: unclamped address: " .. address) end 59 | cpu.tstates = cpu.tstates + tstates 60 | end 61 | 62 | function memory.contend_read_no_mreq (cpu, address, tstates) 63 | if address > 0xffff or address < 0 then error("contend_read_no_mreq: unclamped address") end 64 | cpu.tstates = cpu.tstates + tstates 65 | end 66 | 67 | function memory.contend_write_no_mreq (cpu, address, tstates) 68 | if address > 0xffff or address < 0 then error("contend_write_no_mreq: unclamped address") end 69 | cpu.tstates = cpu.tstates + tstates 70 | end 71 | 72 | -- esta funcion luego va a depender del modelo 73 | function memory.read_mem_byte_internal (cpu, address) 74 | if address > 0xffff or address < 0 then error("read_mem_byte_internal: unclamped address") end 75 | return assert(ram[address], "ram at address "..address.. " is nil") 76 | end 77 | 78 | -- esta funcion luego va a depender del modelo 79 | function memory.read_mem_byte (cpu, address) 80 | memory.contend(cpu, address, 3) 81 | return memory.read_mem_byte_internal(cpu, address) 82 | end 83 | 84 | -- cuidado con direcciones cerca del fin de la memoria 85 | -- puedo leer un byte de $ffff y el siguiente de $0000 (contemplar ese caso, y en 86 | -- la escritura tambien) 87 | function memory.read_mem_word_internal (cpu, address) 88 | --logger.debug("read_mem_word_internal: address = 0x%04x", address) 89 | if address > 0xffff or address < 0 then error("read_mem_word_internal: unclamped address") end 90 | if address + 1 > 0xffff or address + 1 < 0 then error("read_mem_word_internal: unclamped address") end 91 | --logger.debug( ram[address + 1], ram[address]) 92 | --logger.debug( (ram[address + 1] << 8) + ram[address] ) 93 | return (ram[address + 1] << 8) + ram[address] 94 | end 95 | 96 | 97 | function memory.read_mem_word (cpu, address) 98 | local high, low 99 | memory.contend(cpu, address, 3) 100 | low = memory.read_mem_byte_internal(cpu, address) 101 | memory.contend(cpu, address + 1, 3) 102 | high = memory.read_mem_byte_internal(cpu, address + 1) 103 | return low | (high << 8) 104 | --return memory.read_mem_word_internal(address) 105 | end 106 | 107 | function memory.write_mem_byte_internal (cpu, address, value) 108 | assert(value) 109 | if address < 0x4000 then return end -- do not write on ROM 110 | if address > 0xffff then error("write_mem_byte_internal: unclamped address") end 111 | 112 | ram[address] = value 113 | end 114 | 115 | function memory.write_mem_byte (cpu, address, value) 116 | memory.contend(cpu, address, 3) 117 | return memory.write_mem_byte_internal(cpu, address, value) 118 | end 119 | 120 | -- this allows writes on rom. used in tests 121 | function memory.write_mem_byte_rom (cpu, address, value) 122 | assert(type(address) == "number") 123 | assert(type(value) == "number") 124 | if address > 0xffff then error("unclamped address") end 125 | 126 | --logger.info("write_mem_byte_rom", address, value) 127 | ram[address] = value 128 | end 129 | 130 | function memory.write_mem_word_internal (cpu, address, value) 131 | if address > 0xffff or address < 0 then error("unclamped address") end 132 | if address + 1 > 0xffff or address + 1 < 0 then error("unclamped address") end 133 | if address < 0x4000 then return end -- do not write on ROM 134 | ram[address + 1] = (value & 0xff00) >> 8 135 | ram[address] = value & 0x00ff 136 | end 137 | 138 | function memory.write_mem_word (cpu, address, value) 139 | memory.contend(cpu, address, 3) 140 | memory.write_mem_byte_internal(cpu, address, value & 0xff) 141 | memory.contend(cpu, address + 1, 3) 142 | memory.write_mem_byte_internal(cpu, address + 1, (value & 0xff00) >> 8) 143 | end 144 | 145 | -- 146 | --- 147 | 148 | --- 149 | -- Ports I/O 150 | 151 | local ports = {} 152 | 153 | ports.port_fe = 0 -- a default value for port FE 154 | ports.ear_bit = 0 155 | 156 | -- esta funcion luego va a depender del modelo 157 | -- port is a 16 bit value 158 | function ports.contend_io (cpu, port, pre) 159 | assert(port) 160 | if port > 0xffff then error("unclamped port") end 161 | 162 | if pre then 163 | --if port & 0xc000 == 0x4000 then 164 | -- cpu.tstates = cpu.tstates + tstates 165 | --end 166 | cpu.tstates = cpu.tstates + 1 167 | else 168 | if port & 0x0001 ~= 0 then 169 | cpu.tstates = cpu.tstates + 3 170 | else 171 | cpu.tstates = cpu.tstates + 3 172 | end 173 | end 174 | end 175 | 176 | -- esta funcion luego va a depender del modelo 177 | -- port is a 16 bit value 178 | function ports.read_port (cpu, port) 179 | if port > 0xffff then error("unclamped port") end 180 | 181 | ports.contend_io(cpu, port, true) 182 | 183 | local high, low = (port & 0xff00) >> 8, port & 0x00ff 184 | local read = port_handlers.decode_port(cpu, high, low) 185 | 186 | ports.contend_io(cpu, port) 187 | return read 188 | end 189 | 190 | -- esta funcion luego va a depender del modelo 191 | -- port is a 16 bit value 192 | -- data is a 8 bit value 193 | function ports.write_port (cpu, port, data) 194 | --logger.info("write_port: %04x %02x tstates %s", port, data, cpu.tstates) 195 | if port > 0xffff then error("unclamped port") end 196 | 197 | ports.contend_io(cpu, port, true) 198 | 199 | ports.contend_io(cpu, port) 200 | 201 | -- port FE? 202 | if port & 0x01 == 0 then 203 | ports.port_fe = data 204 | ports.ear_bit = data & 0x10 ~= 0 205 | 206 | -- Emulate Issue 3 and 2 207 | if data & testVal ~= 0 then 208 | issue = issue | 0x40 209 | else 210 | issue = issue & 0xbf 211 | end 212 | end 213 | end 214 | 215 | -- 216 | --- 217 | 218 | 219 | 220 | local function handle_interrupt (cpu) 221 | --print("handle interrupt", i) 222 | --beep(cpu) 223 | cpu:handle_interrupt(tstates_per_frame) 224 | 225 | display.flash_counter = display.flash_counter + 1 226 | if display.flash_counter == 16 then 227 | -- 25/50 = half second 228 | --display.toggle_flash() 229 | display.flash_counter = 0 230 | end 231 | 232 | --i = i + 1 233 | --if i == 2 then 234 | display.draw_screen(cpu) 235 | --i = 0 236 | --end 237 | --[[ 238 | i = i + 1 239 | if i >= 115 then 240 | local f = io.open("out.scr", "wb") 241 | for j = 16384, 16384 + 6911 do 242 | local byte = memory.read_mem_byte_internal(cpu, j) 243 | f:write(string.char(byte)) 244 | end 245 | os.exit() 246 | end 247 | --]] 248 | end 249 | 250 | 251 | 252 | local function run (machine, count_tstates) 253 | 254 | local cpu = assert(machine.cpu) 255 | local opcodes = cpu.opcodes 256 | 257 | --print("run for "..count_tstates .. " tstates") 258 | while cpu.tstates < count_tstates do 259 | 260 | -- opcode fetch (apply contention) 261 | memory.contend(cpu, cpu.PC, 4) 262 | -- Increment R register, without modifying the most significant bit 263 | cpu.R = (cpu.R & 0x80) | ( (cpu.R + 1) & 0x7f) 264 | -- R = (R & 0x80) | (R + 1 & 0x7f); //Incremento R, sin modificar el bit más significativo 265 | local opcode = memory.read_mem_byte_internal(cpu, cpu.PC) 266 | -- increment PC before executing instruction 267 | cpu.PC = (cpu.PC + 1) & 0xffff 268 | local f = opcodes[opcode] 269 | if not f then 270 | logger.fatal("Opcode 0x%0x (%d) not found", opcode, opcode) 271 | break 272 | end 273 | -- 274 | f(cpu) 275 | --logger.info("$%04x", cpu.PC) 276 | --if cpu.PC == 0x9854 then stop = true end 277 | --if cpu.PC < 1000 then 278 | --dump_registers(cpu) 279 | --os.execute("pause") 280 | --end 281 | 282 | if cpu.tstates >= tstates_per_frame then 283 | --print("handle interrupt", os.time()) 284 | handle_interrupt(cpu) 285 | 286 | SDL.pumpEvents() 287 | local keys = SDL.getKeyboardState() 288 | if keys[SDL.scancode.Escape] then 289 | return 290 | end 291 | end 292 | end 293 | end 294 | 295 | 296 | 297 | local patch 298 | local function patch_rom_48k (cpu) 299 | patch = memory.read_mem_word_internal(cpu, 0x0569) 300 | 301 | memory.write_mem_byte_rom(cpu, 0x0569, 0xdd) 302 | memory.write_mem_byte_rom(cpu, 0x056A, 0xff) 303 | end 304 | 305 | local function unpatch_rom_48k (cpu) 306 | local high, low = high_low(patch) 307 | memory.write_mem_byte_rom(cpu, 0x0569, low) 308 | memory.write_mem_byte_rom(cpu, 0x056A, high) 309 | end 310 | 311 | 312 | 313 | 314 | local function handle_tape (machine) 315 | require("file_format.tap").load_hook(machine) 316 | end 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | local machine = {} 325 | 326 | function machine.initialize () 327 | 328 | logger.info("Loading Spectrum 48K ROM") 329 | local rom 330 | do 331 | local f = assert(io.open("48.ROM", "rb")) 332 | rom = f:read("*a") 333 | f:close() 334 | end 335 | 336 | local ram = {} 337 | logger.info("Copying ROM to RAM") 338 | for i = 0, 16383 do 339 | ram[i] = string.byte(rom:sub(i+1,i+1)) 340 | end 341 | 342 | logger.info("Clearing the rest of the RAM") 343 | for i = 16384, 65535 do 344 | --ram[i] = 0 345 | ram[i] = math.random(0,255) 346 | end 347 | assert(ram[16384]) 348 | 349 | memory.set_ram(ram) 350 | 351 | patch_rom_48k(z80) 352 | 353 | -- set functions to perform I/O to the cpu 354 | z80.opcodes.bind_io({ 355 | memory = { 356 | contend = assert(memory.contend), 357 | contend_read_no_mreq = assert(memory.contend_read_no_mreq), 358 | contend_write_no_mreq = assert(memory.contend_write_no_mreq), 359 | read_mem_byte = assert(memory.read_mem_byte), 360 | read_mem_byte_internal = assert(memory.read_mem_byte_internal), 361 | read_mem_word = assert(memory.read_mem_word), 362 | write_mem_byte = assert(memory.write_mem_byte), 363 | write_mem_word = assert(memory.write_mem_word) 364 | }, 365 | ports = { 366 | write_port = assert(ports.write_port), 367 | read_port = assert(ports.read_port) 368 | } 369 | }) 370 | 371 | local machine_instance = { 372 | cpu = z80, 373 | run = run, 374 | ports = ports, 375 | memory = { 376 | read_mem_byte_internal = memory.read_mem_byte_internal, 377 | write_mem_byte_internal = memory.write_mem_byte_internal, 378 | set_bank = memory.set_bank, 379 | reset_bank = memory.reset_bank 380 | } 381 | } 382 | 383 | local opcodes_dd = require "opcodes.dd" 384 | opcodes_dd[0xff] = function(cpu) 385 | handle_tape(machine_instance) 386 | unpatch_rom_48k(cpu) 387 | machine_instance:run(2) 388 | patch_rom_48k(cpu) 389 | end 390 | 391 | return machine_instance 392 | end 393 | 394 | return machine 395 | -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | local logger = require "logger" 2 | local port = require "port" 3 | local display = require "display" 4 | local machine = require "machine" 5 | 6 | local loader = require "file_format.loader" 7 | 8 | local SDL = require "SDL" 9 | 10 | local FLAG_S = 128 11 | local FLAG_Z = 64 12 | local FLAG_B5 = 32 13 | local FLAG_H = 16 14 | local FLAG_B3 = 8 15 | local FLAG_PV = 4 16 | local FLAG_N = 2 17 | local FLAG_C = 1 18 | 19 | 20 | --- 21 | -- helpers for troubleshooting 22 | function dump_registers (cpu) 23 | logger.info([[dumping registers 24 | Program counter, stack pointer 25 | PC: $%04x SP: $%04x 26 | General registers 27 | AF: $%04x AF': $%04x 28 | BC: $%04x BC': $%04x 29 | DE: $%04x DE': $%04x 30 | HL: $%04x HL': $%04x 31 | IX: $%04x IY: $%04x 32 | Flags (F) 33 | S Z 5 H 3 V N C 34 | %s %s %s %s %s %s %s %s 35 | Interrupts, memory refresh 36 | IR: $%04x IM: %d (%s) 37 | ]], 38 | cpu.PC, cpu.SP, 39 | cpu.F | cpu.A << 8, cpu.Fp | cpu.Ap << 8, 40 | cpu.C | cpu.B << 8, cpu.Cp | cpu.Bp << 8, 41 | cpu.E | cpu.D << 8, cpu.Ep | cpu.Dp << 8, 42 | cpu.L | cpu.H << 8, cpu.Lp | cpu.Hp << 8, 43 | cpu.IX, cpu.IY, 44 | (cpu.F & FLAG_S ~= 0) and "x" or " ", 45 | (cpu.F & FLAG_Z ~= 0) and "x" or " ", 46 | (cpu.F & FLAG_B5 ~= 0) and "x" or " ", 47 | (cpu.F & FLAG_H ~= 0) and "x" or " ", 48 | (cpu.F & FLAG_B3 ~= 0) and "x" or " ", 49 | (cpu.F & FLAG_PV~= 0) and "x" or " ", 50 | (cpu.F & FLAG_N ~= 0) and "x" or " ", 51 | (cpu.F & FLAG_C ~= 0) and "x" or " ", 52 | cpu.R | cpu.I << 8, cpu.int_mode, (cpu.iff1 ~= 0 and cpu.iff2 ~= 0) and "EI" or "DI" 53 | ) 54 | end 55 | 56 | function pause () 57 | os.execute("pause") 58 | end 59 | 60 | 61 | port.initialize_ports() 62 | 63 | --- 64 | -- Initialize SDL. Create the main window and initialize the display 65 | -- 66 | SDL.init({ SDL.flags.Video, SDL.flags.Events }) 67 | 68 | -- screen without borders 69 | --local win, err = SDL.createWindow({ title = "LuaGleck", height = 192, width = 256 }) 70 | 71 | -- screen with borders 72 | local win, err = SDL.createWindow({ title = "LuaGleck", height = 192 + 64 + 56, width = 256 + 48 + 48, 73 | --flags = { SDL.window.Resizable } 74 | --flags = { SDL.flags.OpenGL, SDL.window.Resizable } 75 | }) 76 | if not win then 77 | error(err) 78 | end 79 | 80 | display.initialize(win) 81 | 82 | 83 | local machine_instance = machine.initialize("spectrum_48k") 84 | 85 | if arg[1] then 86 | if not loader.load(machine_instance, arg[1]) then 87 | print("failed") 88 | return 89 | end 90 | end 91 | 92 | print("Press ESC to quit...") 93 | machine_instance:run(math.huge) 94 | 95 | print "\nQuitting" 96 | -------------------------------------------------------------------------------- /opcodes/cb.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- CBxx opcodes 3 | -- 4 | 5 | local logger = require "logger" 6 | local common_ops = require "opcodes.common" 7 | 8 | local BIT = common_ops.BIT 9 | local SET = common_ops.SET 10 | local RES = common_ops.RES 11 | 12 | local RL = common_ops.RL 13 | local RLC = common_ops.RLC 14 | local RR = common_ops.RR 15 | local RRC = common_ops.RRC 16 | local SLA = common_ops.SLA 17 | local SLL = common_ops.SLL 18 | local SRA = common_ops.SRA 19 | local SRL = common_ops.SRL 20 | 21 | -- locals for faster access (maybe remove this later) 22 | local contend, read_mem_byte, write_mem_byte 23 | 24 | 25 | local FLAG_S = 128 26 | local FLAG_Z = 64 27 | local FLAG_B5 = 32 28 | local FLAG_H = 16 29 | local FLAG_B3 = 8 30 | local FLAG_PV = 4 31 | local FLAG_N = 2 32 | local FLAG_C = 1 33 | 34 | local FLAG_N_OFF = 253 35 | local FLAG_PV_OFF = 251 36 | local FLAG_Z_OFF = 191 37 | local FLAG_H_OFF = 239 38 | local FLAG_S_OFF = 127 39 | local FLAG_C_OFF = 254 40 | 41 | 42 | 43 | 44 | 45 | --- 46 | -- Templates for opcodes creation: RL, RR, SLA, SRA, etc 47 | local regular_pattern = [[ 48 | local %s, logger = ... 49 | return function (cpu) 50 | --logger.debug("%s %s") 51 | cpu.%s = %s(cpu, cpu.%s) 52 | cpu.PC = (cpu.PC + 1) & 0xffff 53 | end 54 | ]] 55 | 56 | -- Variant of the opcode where (HL) is used 57 | local hl_pattern = [[ 58 | local %s, logger, read_mem_byte, contend, write_mem_byte = ... 59 | return function (cpu) 60 | --logger.debug("%s (HL)") 61 | local HL = cpu.L | cpu.H << 8 62 | local byte = read_mem_byte(cpu, HL) 63 | contend(cpu, HL, 1) 64 | byte = %s(cpu, byte) 65 | write_mem_byte(cpu, HL, byte) 66 | cpu.PC = (cpu.PC + 1) & 0xffff 67 | end 68 | ]] 69 | 70 | 71 | local function generate_opcodes (opcodes, base, operation_name, operation) 72 | local variants = { "B", "C", "D", "E", "H", "L", "(HL)", "A" } 73 | for i, variant in ipairs(variants) do 74 | if variant == "(HL)" then 75 | local source = hl_pattern:format(operation_name, operation_name, operation_name) 76 | opcodes[base + i - 1] = load(source, source, "t", {})(operation, logger, read_mem_byte, contend, write_mem_byte) 77 | else 78 | local source = regular_pattern:format(operation_name, operation_name, variant, variant, operation_name, variant) 79 | opcodes[base + i - 1] = load(source, source, "t", {})(operation, logger) 80 | end 81 | end 82 | end 83 | 84 | local function generate_bit_opcodes (opcodes, base, regular_pattern, hl_pattern) 85 | local i = 0 86 | local variants = { "B", "C", "D", "E", "H", "L", "(HL)", "A" } 87 | for bit = 0, 7 do 88 | for _, variant in ipairs(variants) do 89 | if variant == "(HL)" then 90 | local source = hl_pattern:format(bit, variant, bit, variant) 91 | opcodes[base + i] = load(source, source, "t", {})(BIT, logger, read_mem_byte, contend, write_mem_byte) 92 | else 93 | local source = regular_pattern:format(bit, variant, bit, variant) 94 | opcodes[base + i] = load(source, source, "t", {})(BIT, logger) 95 | end 96 | i = i + 1 97 | end 98 | end 99 | end 100 | 101 | 102 | -- operation is either RES or SET 103 | local function generate_res_set_opcodes (opcodes, base, regular_pattern, hl_pattern, operation) 104 | local i = 0 105 | local variants = { "B", "C", "D", "E", "H", "L", "(HL)", "A" } 106 | for bit = 0, 7 do 107 | for _, variant in ipairs(variants) do 108 | if variant == "(HL)" then 109 | local source = hl_pattern:format(bit, bit) 110 | opcodes[base + i] = load(source, source, "t", {})(operation, logger, read_mem_byte, contend, write_mem_byte) 111 | else 112 | local source = regular_pattern:format(bit, variant, variant, bit, variant) 113 | opcodes[base + i] = load(source, source, "t", {})(operation, logger) 114 | end 115 | i = i + 1 116 | end 117 | end 118 | end 119 | 120 | 121 | 122 | local opcodes = {} 123 | 124 | function opcodes.bind_io (binds) 125 | read_mem_byte = assert(binds.memory.read_mem_byte) 126 | write_mem_byte = assert(binds.memory.write_mem_byte) 127 | contend = assert(binds.memory.contend) 128 | 129 | -- Generate opcodes for RLC: RLC B, RLC C, RLC D, RLC E, RLC H, RLC L, RLC (HL), RLC A 130 | generate_opcodes(opcodes, 0x00, "RLC", RLC) 131 | 132 | -- Generate opcodes for RRC: RRC B, RRC C, RRC D, RRC E, RRC H, RRC L, RRC (HL), RRC A 133 | generate_opcodes(opcodes, 0x08, "RRC", RRC) 134 | 135 | -- Generate opcodes for RL: RL B, RL C, RL D, RL E, RL H, RL L, RL (HL), RL A 136 | generate_opcodes(opcodes, 0x10, "RL", RL) 137 | 138 | -- Generate opcodes for RR: RR B, RR C, RR D, RR E, RR H, RR L, RR (HL), RR A 139 | generate_opcodes(opcodes, 0x18, "RR", RR) 140 | 141 | -- Generate opcodes for SLA: SLA B, SLA C, SLA D, SLA E, SLA H, SLA L, SLA (HL), SLA A 142 | generate_opcodes(opcodes, 0x20, "SLA", SLA) 143 | 144 | -- Generate opcodes for SRA: SRA B, SRA C, SRA D, SRA E, SRA H, SRA L, SRA (HL), SRA A 145 | generate_opcodes(opcodes, 0x28, "SRA", SRA) 146 | 147 | -- Generate opcodes for SLL: SLL B, SLL C, SLL D, SLL E, SLL H, SLL L, SLL (HL), SLL A 148 | generate_opcodes(opcodes, 0x30, "SLL", SLL) 149 | 150 | -- Generate opcodes for SRL: SRL B, SRL C, SRL D, SRL E, SRL H, SRL L, SRL (HL), SRL A 151 | generate_opcodes(opcodes, 0x38, "SRL", SRL) 152 | 153 | -- Generate opcodes for BIT operations: BIT 0,B ... BIT 1,B ... ... BIT 7,A 154 | generate_bit_opcodes(opcodes, 0x40, [[ 155 | local BIT, logger = ... 156 | return function (cpu) 157 | --logger.debug("BIT %s,%s") 158 | BIT(cpu, %s, cpu.%s) 159 | cpu.PC = (cpu.PC + 1) & 0xffff 160 | end 161 | ]], 162 | [[ 163 | local BIT, logger, read_mem_byte, contend, write_mem_byte = ... 164 | return function (cpu) 165 | --logger.debug("BIT %s,(HL)", cpu.PC) 166 | local HL = cpu.L | cpu.H << 8 167 | local byte = read_mem_byte(cpu, HL) 168 | --logger.debug("(HL)=%s", byte) 169 | BIT(cpu, %s, byte) 170 | contend(cpu, HL, 1) 171 | cpu.PC = (cpu.PC + 1) & 0xffff 172 | end 173 | ]]) 174 | 175 | 176 | -- Generate opcodes for RES operations: RES 0,B ... RES 1,B ... ... RES 7,A 177 | generate_res_set_opcodes(opcodes, 0x80, [[ 178 | local RES, logger = ... 179 | return function (cpu) 180 | --logger.debug("RES %s,%s") 181 | cpu.%s = RES(cpu, %s, cpu.%s) 182 | cpu.PC = (cpu.PC + 1) & 0xffff 183 | end 184 | ]], 185 | [[ 186 | local RES, logger, read_mem_byte, contend, write_mem_byte = ... 187 | return function (cpu) 188 | --logger.debug("RES %s,(HL)") 189 | local HL = cpu.L | cpu.H << 8 190 | local byte = read_mem_byte(cpu, HL) 191 | byte = RES(cpu, %s, byte) 192 | contend(cpu, HL, 1) 193 | write_mem_byte(cpu, HL, byte) 194 | cpu.PC = (cpu.PC + 1) & 0xffff 195 | end 196 | ]], RES) 197 | 198 | 199 | -- Generate opcodes for SET operations: SET 0,B ... SET 1,B ... ... SET 7,A 200 | generate_res_set_opcodes(opcodes, 0xc0, [[ 201 | local SET, logger = ... 202 | return function (cpu) 203 | --logger.debug("SET %s,%s") 204 | cpu.%s = SET(cpu, %s, cpu.%s) 205 | cpu.PC = (cpu.PC + 1) & 0xffff 206 | end 207 | ]], 208 | [[ 209 | local SET, logger, read_mem_byte, contend, write_mem_byte = ... 210 | return function (cpu) 211 | --logger.debug("SET %s,(HL)") 212 | local HL = cpu.L | cpu.H << 8 213 | local byte = read_mem_byte(cpu, HL) 214 | byte = SET(cpu, %s, byte) 215 | contend(cpu, HL, 1) 216 | write_mem_byte(cpu, HL, byte) 217 | cpu.PC = (cpu.PC + 1) & 0xffff 218 | end 219 | ]], SET) 220 | 221 | end 222 | 223 | return opcodes 224 | -------------------------------------------------------------------------------- /opcodes/common.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- Common logical operations 3 | -- 4 | 5 | --- 6 | -- Will be bound to the actual functions to be called later in bind_io 7 | -- 8 | local contend_read_no_mreq 9 | 10 | local FLAG_S = 128 11 | local FLAG_Z = 64 12 | local FLAG_B5 = 32 13 | local FLAG_H = 16 14 | local FLAG_B3 = 8 15 | local FLAG_PV = 4 16 | local FLAG_N = 2 17 | local FLAG_C = 1 18 | 19 | local FLAG_N_OFF = 253 20 | local FLAG_PV_OFF = 251 21 | local FLAG_Z_OFF = 191 22 | local FLAG_H_OFF = 239 23 | local FLAG_S_OFF = 127 24 | local FLAG_C_OFF = 254 25 | 26 | 27 | local sz53_table = { [0] = 0 } 28 | local parity_table = { [0] = 0 } 29 | local sz53p_table = { [0] = 0 } 30 | 31 | -- 32 | -- Whether a half carry occurred or not can be determined by looking at 33 | -- the 3rd bit of the two arguments and the result; these are hashed 34 | -- into this table in the form r12, where r is the 3rd bit of the 35 | -- result, 1 is the 3rd bit of the 1st argument and 2 is the 36 | -- third bit of the 2nd argument; the tables differ for add and subtract 37 | -- operations 38 | local halfcarry_add_table = { [0] = 0, FLAG_H, FLAG_H, FLAG_H, 0, 0, 0, FLAG_H } 39 | local halfcarry_sub_table = { [0] = 0, 0, FLAG_H, 0, FLAG_H, 0, FLAG_H, FLAG_H } 40 | 41 | -- Similarly, overflow can be determined by looking at the 7th bits; again 42 | -- the hash into this table is r12 43 | local overflow_add_table = { [0] = 0, 0, 0, FLAG_PV, FLAG_PV, 0, 0, 0 } 44 | local overflow_sub_table = { [0] = 0, FLAG_PV, 0, 0, 0, 0, FLAG_PV, 0 } 45 | 46 | local function init_tables () 47 | 48 | for i = 0, 0x100 do 49 | sz53_table[i] = i & ( FLAG_B3 | FLAG_B5 | FLAG_S ) 50 | local j = i 51 | local parity = 0 52 | for k = 0, 7 do 53 | parity = parity ~ (j & 1) 54 | j = j >> 1 55 | end 56 | parity_table[i] = ( parity ~= 0 and 0 or FLAG_PV ) 57 | sz53p_table[i] = sz53_table[i] | parity_table[i] 58 | end 59 | 60 | sz53_table[0] = sz53_table[0] | FLAG_Z 61 | sz53p_table[0] = sz53p_table[0] | FLAG_Z 62 | end 63 | 64 | init_tables() 65 | 66 | 67 | local function BIT (cpu, bit, operand) 68 | -- TODO: Revisar. Difiere respecto a Spectaculator y Fuse 69 | --[[ 70 | local testBit = 1 << bit -- 2 a la bit 71 | cpu.F = cpu.F & FLAG_C -- enmascaro el flag C para conservarlo 72 | if operand & testBit ~= 0 then -- ¿el bit es 1? 73 | if bit == 7 then -- ¿Estoy testeando el bit 7? 74 | cpu.F = cpu.F | FLAG_S -- Si, entonces prendo el flag S 75 | end 76 | if bit == 5 then -- ¿Estoy testeando el bit 5? 77 | cpu.F = cpu.F | FLAG_B5 -- Si, entonces prendo el flag 5 78 | end 79 | if bit == 3 then -- ¿Estoy testeando el bit 3? 80 | cpu.F = cpu.F | FLAG_B3 -- Si, entonces prendo el flag 3 81 | end 82 | cpu.F = cpu.F | FLAG_H -- Prendo el flag H 83 | else 84 | -- entonces, es cero -> prendo los flags Z, H y PV 85 | cpu.F = cpu.F | FLAG_Z | FLAG_H | FLAG_PV 86 | end 87 | --]] 88 | cpu.F = ( cpu.F & FLAG_C ) | FLAG_H | ( operand & ( FLAG_B3 | FLAG_B5 ) ) 89 | if ( operand & ( 0x01 << bit ) ) == 0 then 90 | cpu.F = cpu.F | FLAG_PV | FLAG_Z 91 | end 92 | if bit == 7 and operand & 0x80 ~= 0 then 93 | cpu.F = cpu.F | FLAG_S 94 | end 95 | end 96 | 97 | local function BIT_INDEX (cpu, bit, operand, address) 98 | cpu.F = ( cpu.F & FLAG_C ) | FLAG_H | ( (address >> 8) & ( FLAG_B3 | FLAG_B5 ) ) 99 | if ( operand & ( 0x01 << bit ) ) == 0 then 100 | cpu.F = cpu.F | FLAG_PV | FLAG_Z 101 | end 102 | if bit == 7 and operand & 0x80 ~= 0 then 103 | cpu.F = cpu.F | FLAG_S 104 | end 105 | end 106 | 107 | 108 | local function RES (cpu, bit, byte) 109 | bit = 1 << bit -- 2^bit 110 | bit = bit ~ 0xff -- invert 111 | return byte & bit -- turn it off 112 | end 113 | 114 | 115 | local function SET (cpu, bit, byte) 116 | bit = 1 << bit -- 2^bit 117 | return byte | bit 118 | end 119 | 120 | 121 | local function ADD_16 (cpu, value1, value2)--, reg_low, reg_high) 122 | local add16temp = value1 + value2 123 | local lookup = ( ( value1 & 0x0800 ) >> 11 ) | 124 | ( ( value2 & 0x0800 ) >> 10 ) | 125 | ( ( add16temp & 0x0800 ) >> 9 ) 126 | local I_high = cpu.I << 8 127 | for i = 1, 7 do 128 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 129 | end 130 | --cpu[reg_high], cpu[reg_low] = high_low(add16temp) 131 | cpu.F = ( cpu.F & ( FLAG_PV | FLAG_Z | FLAG_S ) ) | 132 | ( add16temp & 0x10000 ~= 0 and FLAG_C or 0 ) | 133 | ( ( add16temp >> 8 ) & ( FLAG_B3 | FLAG_B5 ) ) | 134 | halfcarry_add_table[lookup] 135 | return add16temp & 0xffff 136 | end 137 | 138 | 139 | local function ADD_8 (cpu, value) 140 | local add = cpu.A + value 141 | local lookup = ( ( cpu.A & 0x88 ) >> 3 ) | 142 | ( ( value & 0x88 ) >> 2 ) | 143 | ( ( add & 0x88 ) >> 1 ) 144 | cpu.A = add & 0xff 145 | cpu.F = ( add & 0x100 ~= 0 and FLAG_C or 0 ) | 146 | halfcarry_add_table[lookup & 0x07] | overflow_add_table[lookup >> 4] | 147 | sz53_table[cpu.A] 148 | end 149 | 150 | local function ADC_8 (cpu, value) 151 | local temp = cpu.A + value + ( cpu.F & FLAG_C ) 152 | local lookup = ( ( cpu.A & 0x88 ) >> 3 ) | 153 | ( ( value & 0x88 ) >> 2 ) | 154 | ( ( temp & 0x88 ) >> 1 ) 155 | cpu.A = temp & 0xff 156 | cpu.F = ( temp & 0x100 ~= 0 and FLAG_C or 0 ) | 157 | halfcarry_add_table[lookup & 0x07] | overflow_add_table[lookup >> 4] | 158 | sz53_table[cpu.A] 159 | end 160 | 161 | 162 | local function SUB (cpu, value) 163 | local sub = cpu.A - value 164 | local lookup = ( ( cpu.A & 0x88 ) >> 3 ) | 165 | ( ( value & 0x88 ) >> 2 ) | 166 | ( ( sub & 0x88 ) >> 1 ) 167 | cpu.A = sub & 0xff 168 | cpu.F = ( (sub & 0x100 ~= 0) and FLAG_C or 0 ) | 169 | FLAG_N | 170 | halfcarry_sub_table[lookup & 0x07] | 171 | overflow_sub_table[lookup >> 4] | 172 | sz53_table[cpu.A] 173 | end 174 | 175 | 176 | local function SBC (cpu, value) 177 | local temp = cpu.A - value - ( cpu.F & FLAG_C ) 178 | local lookup = ( ( cpu.A & 0x88 ) >> 3 ) | 179 | ( ( value & 0x88 ) >> 2 ) | 180 | ( ( temp & 0x88 ) >> 1 ) 181 | cpu.A = temp & 0xff 182 | cpu.F = ( temp & 0x100 ~= 0 and FLAG_C or 0 ) | 183 | FLAG_N | 184 | halfcarry_sub_table[lookup & 0x07] | 185 | overflow_sub_table[lookup >> 4] | 186 | sz53_table[cpu.A] 187 | end 188 | 189 | 190 | local function AND (cpu, value) 191 | cpu.A = cpu.A & value 192 | cpu.F = FLAG_H | sz53p_table[cpu.A] 193 | end 194 | 195 | local function OR (cpu, value) 196 | cpu.A = cpu.A | value 197 | cpu.F = sz53p_table[cpu.A] 198 | end 199 | 200 | local function XOR (cpu, value) 201 | cpu.A = cpu.A ~ value 202 | cpu.F = sz53p_table[cpu.A] 203 | end 204 | 205 | 206 | local function INC (cpu, byte) 207 | assert(byte) 208 | 209 | byte = (byte + 1) & 0xff 210 | cpu.F = ( cpu.F & FLAG_C ) | ( byte == 0x80 and FLAG_PV or 0 ) | 211 | ( (byte & 0x0f ~= 0) and 0 or FLAG_H ) | sz53_table[byte] 212 | return byte 213 | end 214 | 215 | local function DEC (cpu, byte) 216 | assert(byte) 217 | cpu.F = (cpu.F & FLAG_C) | ( ((byte & 0x0f) ~= 0) and 0 or FLAG_H ) | FLAG_N 218 | byte = (byte - 1) & 0xff 219 | cpu.F = cpu.F | ( byte == 0x7f and FLAG_PV or 0 ) | sz53_table[byte] 220 | return byte 221 | end 222 | 223 | -- Comparison instructions 224 | local function CP (cpu, value) 225 | local cptemp = cpu.A - value 226 | local lookup = ( ( cpu.A & 0x88 ) >> 3 ) | 227 | ( ( (value) & 0x88 ) >> 2 ) | 228 | ( ( cptemp & 0x88 ) >> 1 ) 229 | 230 | if cptemp & 0x1000 ~= 0 then 231 | cpu.F = FLAG_C 232 | else 233 | if cptemp ~= 0 then 234 | cpu.F = 0 235 | else 236 | cpu.F = FLAG_Z 237 | end 238 | end 239 | 240 | cpu.F = cpu.F | FLAG_N | 241 | halfcarry_sub_table[lookup & 0x07] | 242 | overflow_sub_table[lookup >> 4] | 243 | ( value & ( FLAG_B3 | FLAG_B5 ) ) | 244 | ( cptemp & FLAG_S ) 245 | end 246 | 247 | -- Rotation instructions 248 | local function RL (cpu, value) 249 | local rltemp = value 250 | value = ( value << 1 ) | ( cpu.F & FLAG_C ) 251 | value = value & 0xff 252 | cpu.F = ( rltemp >> 7 ) | sz53p_table[value] 253 | return value 254 | end 255 | 256 | local function RLC (cpu, value) 257 | value = ( (value & 0x7f) << 1 ) | ( value >> 7 ) 258 | cpu.F = ( value & FLAG_C ) | sz53p_table[value] 259 | return value 260 | end 261 | 262 | local function RR (cpu, value) 263 | local temp = value 264 | value = ( value >> 1 ) | ( (cpu.F & 0x01) << 7 ) 265 | cpu.F = ( temp & FLAG_C ) | sz53p_table[value] 266 | return value 267 | end 268 | 269 | local function RRC (cpu, value) 270 | cpu.F = value & FLAG_C 271 | value = ( value >> 1 ) | ( (value & 0x01) << 7 ) 272 | cpu.F = cpu.F | sz53p_table[value] 273 | return value 274 | end 275 | 276 | local function SLA (cpu, value) 277 | cpu.F = value >> 7 278 | value = value << 1 279 | value = value & 0xff 280 | cpu.F = cpu.F | sz53p_table[value] 281 | return value 282 | end 283 | 284 | local function SLL (cpu, value) 285 | cpu.F = value >> 7 286 | value = ( value << 1 ) | 0x01 287 | value = value & 0xff 288 | cpu.F = cpu.F | sz53p_table[value] 289 | return value 290 | end 291 | 292 | local function SRA (cpu, value) 293 | cpu.F = value & FLAG_C 294 | value = ( value & 0x80 ) | ( value >> 1 ) 295 | cpu.F = cpu.F | sz53p_table[value] 296 | return value 297 | end 298 | 299 | local function SRL (cpu, value) 300 | cpu.F = value & FLAG_C 301 | value = value >> 1 302 | cpu.F = cpu.F | sz53p_table[value] 303 | return value 304 | end 305 | 306 | 307 | local function bind_io (binds) 308 | contend_read_no_mreq = assert(binds.memory.contend_read_no_mreq) 309 | end 310 | 311 | 312 | return { 313 | bind_io = bind_io, 314 | BIT = BIT, 315 | BIT_INDEX = BIT_INDEX, 316 | RES = RES, 317 | SET = SET, 318 | ADD_16 = ADD_16, 319 | ADD_8 = ADD_8, 320 | ADC_8 = ADC_8, 321 | AND = AND, 322 | OR = OR, 323 | XOR = XOR, 324 | 325 | INC = INC, 326 | DEC = DEC, 327 | 328 | SUB = SUB, 329 | SBC = SBC, 330 | CP = CP, 331 | 332 | RL = RL, 333 | RLC = RLC, 334 | RR = RR, 335 | RRC = RRC, 336 | SLA = SLA, 337 | SLL = SLL, 338 | SRA = SRA, 339 | SRL = SRL, 340 | 341 | tables = { 342 | overflow_add_table = overflow_add_table, 343 | overflow_sub_table = overflow_sub_table, 344 | halfcarry_add_table = halfcarry_add_table, 345 | halfcarry_sub_table = halfcarry_sub_table, 346 | sz53p_table = sz53p_table, 347 | sz53_table = sz53_table, 348 | parity_table = parity_table 349 | } 350 | } -------------------------------------------------------------------------------- /opcodes/daa.lua: -------------------------------------------------------------------------------- 1 | --- 2 | -- Precomputed values for DAA instruction 3 | 4 | -- 2048 5 | local DAATable = { 6 | [0] = 68, 7 | 256, 8 | 512, 9 | 772, 10 | 1024, 11 | 1284, 12 | 1540, 13 | 1792, 14 | 2056, 15 | 2316, 16 | 4112, 17 | 4372, 18 | 4628, 19 | 4880, 20 | 5140, 21 | 5392, 22 | 4096, 23 | 4356, 24 | 4612, 25 | 4864, 26 | 5124, 27 | 5376, 28 | 5632, 29 | 5892, 30 | 6156, 31 | 6408, 32 | 8240, 33 | 8500, 34 | 8756, 35 | 9008, 36 | 9268, 37 | 9520, 38 | 8224, 39 | 8484, 40 | 8740, 41 | 8992, 42 | 9252, 43 | 9504, 44 | 9760, 45 | 10020, 46 | 10284, 47 | 10536, 48 | 12340, 49 | 12592, 50 | 12848, 51 | 13108, 52 | 13360, 53 | 13620, 54 | 12324, 55 | 12576, 56 | 12832, 57 | 13092, 58 | 13344, 59 | 13604, 60 | 13860, 61 | 14112, 62 | 14376, 63 | 14636, 64 | 16400, 65 | 16660, 66 | 16916, 67 | 17168, 68 | 17428, 69 | 17680, 70 | 16384, 71 | 16644, 72 | 16900, 73 | 17152, 74 | 17412, 75 | 17664, 76 | 17920, 77 | 18180, 78 | 18444, 79 | 18696, 80 | 20500, 81 | 20752, 82 | 21008, 83 | 21268, 84 | 21520, 85 | 21780, 86 | 20484, 87 | 20736, 88 | 20992, 89 | 21252, 90 | 21504, 91 | 21764, 92 | 22020, 93 | 22272, 94 | 22536, 95 | 22796, 96 | 24628, 97 | 24880, 98 | 25136, 99 | 25396, 100 | 25648, 101 | 25908, 102 | 24612, 103 | 24864, 104 | 25120, 105 | 25380, 106 | 25632, 107 | 25892, 108 | 26148, 109 | 26400, 110 | 26664, 111 | 26924, 112 | 28720, 113 | 28980, 114 | 29236, 115 | 29488, 116 | 29748, 117 | 30000, 118 | 28704, 119 | 28964, 120 | 29220, 121 | 29472, 122 | 29732, 123 | 29984, 124 | 30240, 125 | 30500, 126 | 30764, 127 | 31016, 128 | -32624, 129 | -32364, 130 | -32108, 131 | -31856, 132 | -31596, 133 | -31344, 134 | -32640, 135 | -32380, 136 | -32124, 137 | -31872, 138 | -31612, 139 | -31360, 140 | -31104, 141 | -30844, 142 | -30580, 143 | -30328, 144 | -28524, 145 | -28272, 146 | -28016, 147 | -27756, 148 | -27504, 149 | -27244, 150 | -28540, 151 | -28288, 152 | -28032, 153 | -27772, 154 | -27520, 155 | -27260, 156 | -27004, 157 | -26752, 158 | -26488, 159 | -26228, 160 | 85, 161 | 273, 162 | 529, 163 | 789, 164 | 1041, 165 | 1301, 166 | 69, 167 | 257, 168 | 513, 169 | 773, 170 | 1025, 171 | 1285, 172 | 1541, 173 | 1793, 174 | 2057, 175 | 2317, 176 | 4113, 177 | 4373, 178 | 4629, 179 | 4881, 180 | 5141, 181 | 5393, 182 | 4097, 183 | 4357, 184 | 4613, 185 | 4865, 186 | 5125, 187 | 5377, 188 | 5633, 189 | 5893, 190 | 6157, 191 | 6409, 192 | 8241, 193 | 8501, 194 | 8757, 195 | 9009, 196 | 9269, 197 | 9521, 198 | 8225, 199 | 8485, 200 | 8741, 201 | 8993, 202 | 9253, 203 | 9505, 204 | 9761, 205 | 10021, 206 | 10285, 207 | 10537, 208 | 12341, 209 | 12593, 210 | 12849, 211 | 13109, 212 | 13361, 213 | 13621, 214 | 12325, 215 | 12577, 216 | 12833, 217 | 13093, 218 | 13345, 219 | 13605, 220 | 13861, 221 | 14113, 222 | 14377, 223 | 14637, 224 | 16401, 225 | 16661, 226 | 16917, 227 | 17169, 228 | 17429, 229 | 17681, 230 | 16385, 231 | 16645, 232 | 16901, 233 | 17153, 234 | 17413, 235 | 17665, 236 | 17921, 237 | 18181, 238 | 18445, 239 | 18697, 240 | 20501, 241 | 20753, 242 | 21009, 243 | 21269, 244 | 21521, 245 | 21781, 246 | 20485, 247 | 20737, 248 | 20993, 249 | 21253, 250 | 21505, 251 | 21765, 252 | 22021, 253 | 22273, 254 | 22537, 255 | 22797, 256 | 24629, 257 | 24881, 258 | 25137, 259 | 25397, 260 | 25649, 261 | 25909, 262 | 24613, 263 | 24865, 264 | 25121, 265 | 25381, 266 | 25633, 267 | 25893, 268 | 26149, 269 | 26401, 270 | 26665, 271 | 26925, 272 | 28721, 273 | 28981, 274 | 29237, 275 | 29489, 276 | 29749, 277 | 30001, 278 | 28705, 279 | 28965, 280 | 29221, 281 | 29473, 282 | 29733, 283 | 29985, 284 | 30241, 285 | 30501, 286 | 30765, 287 | 31017, 288 | -32623, 289 | -32363, 290 | -32107, 291 | -31855, 292 | -31595, 293 | -31343, 294 | -32639, 295 | -32379, 296 | -32123, 297 | -31871, 298 | -31611, 299 | -31359, 300 | -31103, 301 | -30843, 302 | -30579, 303 | -30327, 304 | -28523, 305 | -28271, 306 | -28015, 307 | -27755, 308 | -27503, 309 | -27243, 310 | -28539, 311 | -28287, 312 | -28031, 313 | -27771, 314 | -27519, 315 | -27259, 316 | -27003, 317 | -26751, 318 | -26487, 319 | -26227, 320 | -24395, 321 | -24143, 322 | -23887, 323 | -23627, 324 | -23375, 325 | -23115, 326 | -24411, 327 | -24159, 328 | -23903, 329 | -23643, 330 | -23391, 331 | -23131, 332 | -22875, 333 | -22623, 334 | -22359, 335 | -22099, 336 | -20303, 337 | -20043, 338 | -19787, 339 | -19535, 340 | -19275, 341 | -19023, 342 | -20319, 343 | -20059, 344 | -19803, 345 | -19551, 346 | -19291, 347 | -19039, 348 | -18783, 349 | -18523, 350 | -18259, 351 | -18007, 352 | -16235, 353 | -15983, 354 | -15727, 355 | -15467, 356 | -15215, 357 | -14955, 358 | -16251, 359 | -15999, 360 | -15743, 361 | -15483, 362 | -15231, 363 | -14971, 364 | -14715, 365 | -14463, 366 | -14199, 367 | -13939, 368 | -12143, 369 | -11883, 370 | -11627, 371 | -11375, 372 | -11115, 373 | -10863, 374 | -12159, 375 | -11899, 376 | -11643, 377 | -11391, 378 | -11131, 379 | -10879, 380 | -10623, 381 | -10363, 382 | -10099, 383 | -9847, 384 | -8015, 385 | -7755, 386 | -7499, 387 | -7247, 388 | -6987, 389 | -6735, 390 | -8031, 391 | -7771, 392 | -7515, 393 | -7263, 394 | -7003, 395 | -6751, 396 | -6495, 397 | -6235, 398 | -5971, 399 | -5719, 400 | -3915, 401 | -3663, 402 | -3407, 403 | -3147, 404 | -2895, 405 | -2635, 406 | -3931, 407 | -3679, 408 | -3423, 409 | -3163, 410 | -2911, 411 | -2651, 412 | -2395, 413 | -2143, 414 | -1879, 415 | -1619, 416 | 85, 417 | 273, 418 | 529, 419 | 789, 420 | 1041, 421 | 1301, 422 | 69, 423 | 257, 424 | 513, 425 | 773, 426 | 1025, 427 | 1285, 428 | 1541, 429 | 1793, 430 | 2057, 431 | 2317, 432 | 4113, 433 | 4373, 434 | 4629, 435 | 4881, 436 | 5141, 437 | 5393, 438 | 4097, 439 | 4357, 440 | 4613, 441 | 4865, 442 | 5125, 443 | 5377, 444 | 5633, 445 | 5893, 446 | 6157, 447 | 6409, 448 | 8241, 449 | 8501, 450 | 8757, 451 | 9009, 452 | 9269, 453 | 9521, 454 | 8225, 455 | 8485, 456 | 8741, 457 | 8993, 458 | 9253, 459 | 9505, 460 | 9761, 461 | 10021, 462 | 10285, 463 | 10537, 464 | 12341, 465 | 12593, 466 | 12849, 467 | 13109, 468 | 13361, 469 | 13621, 470 | 12325, 471 | 12577, 472 | 12833, 473 | 13093, 474 | 13345, 475 | 13605, 476 | 13861, 477 | 14113, 478 | 14377, 479 | 14637, 480 | 16401, 481 | 16661, 482 | 16917, 483 | 17169, 484 | 17429, 485 | 17681, 486 | 16385, 487 | 16645, 488 | 16901, 489 | 17153, 490 | 17413, 491 | 17665, 492 | 17921, 493 | 18181, 494 | 18445, 495 | 18697, 496 | 20501, 497 | 20753, 498 | 21009, 499 | 21269, 500 | 21521, 501 | 21781, 502 | 20485, 503 | 20737, 504 | 20993, 505 | 21253, 506 | 21505, 507 | 21765, 508 | 22021, 509 | 22273, 510 | 22537, 511 | 22797, 512 | 24629, 513 | 24881, 514 | 25137, 515 | 25397, 516 | 25649, 517 | 25909, 518 | 1540, 519 | 1792, 520 | 2056, 521 | 2316, 522 | 2572, 523 | 2824, 524 | 3084, 525 | 3336, 526 | 3592, 527 | 3852, 528 | 4112, 529 | 4372, 530 | 4628, 531 | 4880, 532 | 5140, 533 | 5392, 534 | 5632, 535 | 5892, 536 | 6156, 537 | 6408, 538 | 6664, 539 | 6924, 540 | 7176, 541 | 7436, 542 | 7692, 543 | 7944, 544 | 8240, 545 | 8500, 546 | 8756, 547 | 9008, 548 | 9268, 549 | 9520, 550 | 9760, 551 | 10020, 552 | 10284, 553 | 10536, 554 | 10792, 555 | 11052, 556 | 11304, 557 | 11564, 558 | 11820, 559 | 12072, 560 | 12340, 561 | 12592, 562 | 12848, 563 | 13108, 564 | 13360, 565 | 13620, 566 | 13860, 567 | 14112, 568 | 14376, 569 | 14636, 570 | 14892, 571 | 15144, 572 | 15404, 573 | 15656, 574 | 15912, 575 | 16172, 576 | 16400, 577 | 16660, 578 | 16916, 579 | 17168, 580 | 17428, 581 | 17680, 582 | 17920, 583 | 18180, 584 | 18444, 585 | 18696, 586 | 18952, 587 | 19212, 588 | 19464, 589 | 19724, 590 | 19980, 591 | 20232, 592 | 20500, 593 | 20752, 594 | 21008, 595 | 21268, 596 | 21520, 597 | 21780, 598 | 22020, 599 | 22272, 600 | 22536, 601 | 22796, 602 | 23052, 603 | 23304, 604 | 23564, 605 | 23816, 606 | 24072, 607 | 24332, 608 | 24628, 609 | 24880, 610 | 25136, 611 | 25396, 612 | 25648, 613 | 25908, 614 | 26148, 615 | 26400, 616 | 26664, 617 | 26924, 618 | 27180, 619 | 27432, 620 | 27692, 621 | 27944, 622 | 28200, 623 | 28460, 624 | 28720, 625 | 28980, 626 | 29236, 627 | 29488, 628 | 29748, 629 | 30000, 630 | 30240, 631 | 30500, 632 | 30764, 633 | 31016, 634 | 31272, 635 | 31532, 636 | 31784, 637 | 32044, 638 | 32300, 639 | 32552, 640 | -32624, 641 | -32364, 642 | -32108, 643 | -31856, 644 | -31596, 645 | -31344, 646 | -31104, 647 | -30844, 648 | -30580, 649 | -30328, 650 | -30072, 651 | -29812, 652 | -29560, 653 | -29300, 654 | -29044, 655 | -28792, 656 | -28524, 657 | -28272, 658 | -28016, 659 | -27756, 660 | -27504, 661 | -27244, 662 | -27004, 663 | -26752, 664 | -26488, 665 | -26228, 666 | -25972, 667 | -25720, 668 | -25460, 669 | -25208, 670 | -24952, 671 | -24692, 672 | 85, 673 | 273, 674 | 529, 675 | 789, 676 | 1041, 677 | 1301, 678 | 1541, 679 | 1793, 680 | 2057, 681 | 2317, 682 | 2573, 683 | 2825, 684 | 3085, 685 | 3337, 686 | 3593, 687 | 3853, 688 | 4113, 689 | 4373, 690 | 4629, 691 | 4881, 692 | 5141, 693 | 5393, 694 | 5633, 695 | 5893, 696 | 6157, 697 | 6409, 698 | 6665, 699 | 6925, 700 | 7177, 701 | 7437, 702 | 7693, 703 | 7945, 704 | 8241, 705 | 8501, 706 | 8757, 707 | 9009, 708 | 9269, 709 | 9521, 710 | 9761, 711 | 10021, 712 | 10285, 713 | 10537, 714 | 10793, 715 | 11053, 716 | 11305, 717 | 11565, 718 | 11821, 719 | 12073, 720 | 12341, 721 | 12593, 722 | 12849, 723 | 13109, 724 | 13361, 725 | 13621, 726 | 13861, 727 | 14113, 728 | 14377, 729 | 14637, 730 | 14893, 731 | 15145, 732 | 15405, 733 | 15657, 734 | 15913, 735 | 16173, 736 | 16401, 737 | 16661, 738 | 16917, 739 | 17169, 740 | 17429, 741 | 17681, 742 | 17921, 743 | 18181, 744 | 18445, 745 | 18697, 746 | 18953, 747 | 19213, 748 | 19465, 749 | 19725, 750 | 19981, 751 | 20233, 752 | 20501, 753 | 20753, 754 | 21009, 755 | 21269, 756 | 21521, 757 | 21781, 758 | 22021, 759 | 22273, 760 | 22537, 761 | 22797, 762 | 23053, 763 | 23305, 764 | 23565, 765 | 23817, 766 | 24073, 767 | 24333, 768 | 24629, 769 | 24881, 770 | 25137, 771 | 25397, 772 | 25649, 773 | 25909, 774 | 26149, 775 | 26401, 776 | 26665, 777 | 26925, 778 | 27181, 779 | 27433, 780 | 27693, 781 | 27945, 782 | 28201, 783 | 28461, 784 | 28721, 785 | 28981, 786 | 29237, 787 | 29489, 788 | 29749, 789 | 30001, 790 | 30241, 791 | 30501, 792 | 30765, 793 | 31017, 794 | 31273, 795 | 31533, 796 | 31785, 797 | 32045, 798 | 32301, 799 | 32553, 800 | -32623, 801 | -32363, 802 | -32107, 803 | -31855, 804 | -31595, 805 | -31343, 806 | -31103, 807 | -30843, 808 | -30579, 809 | -30327, 810 | -30071, 811 | -29811, 812 | -29559, 813 | -29299, 814 | -29043, 815 | -28791, 816 | -28523, 817 | -28271, 818 | -28015, 819 | -27755, 820 | -27503, 821 | -27243, 822 | -27003, 823 | -26751, 824 | -26487, 825 | -26227, 826 | -25971, 827 | -25719, 828 | -25459, 829 | -25207, 830 | -24951, 831 | -24691, 832 | -24395, 833 | -24143, 834 | -23887, 835 | -23627, 836 | -23375, 837 | -23115, 838 | -22875, 839 | -22623, 840 | -22359, 841 | -22099, 842 | -21843, 843 | -21591, 844 | -21331, 845 | -21079, 846 | -20823, 847 | -20563, 848 | -20303, 849 | -20043, 850 | -19787, 851 | -19535, 852 | -19275, 853 | -19023, 854 | -18783, 855 | -18523, 856 | -18259, 857 | -18007, 858 | -17751, 859 | -17491, 860 | -17239, 861 | -16979, 862 | -16723, 863 | -16471, 864 | -16235, 865 | -15983, 866 | -15727, 867 | -15467, 868 | -15215, 869 | -14955, 870 | -14715, 871 | -14463, 872 | -14199, 873 | -13939, 874 | -13683, 875 | -13431, 876 | -13171, 877 | -12919, 878 | -12663, 879 | -12403, 880 | -12143, 881 | -11883, 882 | -11627, 883 | -11375, 884 | -11115, 885 | -10863, 886 | -10623, 887 | -10363, 888 | -10099, 889 | -9847, 890 | -9591, 891 | -9331, 892 | -9079, 893 | -8819, 894 | -8563, 895 | -8311, 896 | -8015, 897 | -7755, 898 | -7499, 899 | -7247, 900 | -6987, 901 | -6735, 902 | -6495, 903 | -6235, 904 | -5971, 905 | -5719, 906 | -5463, 907 | -5203, 908 | -4951, 909 | -4691, 910 | -4435, 911 | -4183, 912 | -3915, 913 | -3663, 914 | -3407, 915 | -3147, 916 | -2895, 917 | -2635, 918 | -2395, 919 | -2143, 920 | -1879, 921 | -1619, 922 | -1363, 923 | -1111, 924 | -851, 925 | -599, 926 | -343, 927 | -83, 928 | 85, 929 | 273, 930 | 529, 931 | 789, 932 | 1041, 933 | 1301, 934 | 1541, 935 | 1793, 936 | 2057, 937 | 2317, 938 | 2573, 939 | 2825, 940 | 3085, 941 | 3337, 942 | 3593, 943 | 3853, 944 | 4113, 945 | 4373, 946 | 4629, 947 | 4881, 948 | 5141, 949 | 5393, 950 | 5633, 951 | 5893, 952 | 6157, 953 | 6409, 954 | 6665, 955 | 6925, 956 | 7177, 957 | 7437, 958 | 7693, 959 | 7945, 960 | 8241, 961 | 8501, 962 | 8757, 963 | 9009, 964 | 9269, 965 | 9521, 966 | 9761, 967 | 10021, 968 | 10285, 969 | 10537, 970 | 10793, 971 | 11053, 972 | 11305, 973 | 11565, 974 | 11821, 975 | 12073, 976 | 12341, 977 | 12593, 978 | 12849, 979 | 13109, 980 | 13361, 981 | 13621, 982 | 13861, 983 | 14113, 984 | 14377, 985 | 14637, 986 | 14893, 987 | 15145, 988 | 15405, 989 | 15657, 990 | 15913, 991 | 16173, 992 | 16401, 993 | 16661, 994 | 16917, 995 | 17169, 996 | 17429, 997 | 17681, 998 | 17921, 999 | 18181, 1000 | 18445, 1001 | 18697, 1002 | 18953, 1003 | 19213, 1004 | 19465, 1005 | 19725, 1006 | 19981, 1007 | 20233, 1008 | 20501, 1009 | 20753, 1010 | 21009, 1011 | 21269, 1012 | 21521, 1013 | 21781, 1014 | 22021, 1015 | 22273, 1016 | 22537, 1017 | 22797, 1018 | 23053, 1019 | 23305, 1020 | 23565, 1021 | 23817, 1022 | 24073, 1023 | 24333, 1024 | 24629, 1025 | 24881, 1026 | 25137, 1027 | 25397, 1028 | 25649, 1029 | 25909, 1030 | 70, 1031 | 258, 1032 | 514, 1033 | 774, 1034 | 1026, 1035 | 1286, 1036 | 1542, 1037 | 1794, 1038 | 2058, 1039 | 2318, 1040 | 1026, 1041 | 1286, 1042 | 1542, 1043 | 1794, 1044 | 2058, 1045 | 2318, 1046 | 4098, 1047 | 4358, 1048 | 4614, 1049 | 4866, 1050 | 5126, 1051 | 5378, 1052 | 5634, 1053 | 5894, 1054 | 6158, 1055 | 6410, 1056 | 5126, 1057 | 5378, 1058 | 5634, 1059 | 5894, 1060 | 6158, 1061 | 6410, 1062 | 8226, 1063 | 8486, 1064 | 8742, 1065 | 8994, 1066 | 9254, 1067 | 9506, 1068 | 9762, 1069 | 10022, 1070 | 10286, 1071 | 10538, 1072 | 9254, 1073 | 9506, 1074 | 9762, 1075 | 10022, 1076 | 10286, 1077 | 10538, 1078 | 12326, 1079 | 12578, 1080 | 12834, 1081 | 13094, 1082 | 13346, 1083 | 13606, 1084 | 13862, 1085 | 14114, 1086 | 14378, 1087 | 14638, 1088 | 13346, 1089 | 13606, 1090 | 13862, 1091 | 14114, 1092 | 14378, 1093 | 14638, 1094 | 16386, 1095 | 16646, 1096 | 16902, 1097 | 17154, 1098 | 17414, 1099 | 17666, 1100 | 17922, 1101 | 18182, 1102 | 18446, 1103 | 18698, 1104 | 17414, 1105 | 17666, 1106 | 17922, 1107 | 18182, 1108 | 18446, 1109 | 18698, 1110 | 20486, 1111 | 20738, 1112 | 20994, 1113 | 21254, 1114 | 21506, 1115 | 21766, 1116 | 22022, 1117 | 22274, 1118 | 22538, 1119 | 22798, 1120 | 21506, 1121 | 21766, 1122 | 22022, 1123 | 22274, 1124 | 22538, 1125 | 22798, 1126 | 24614, 1127 | 24866, 1128 | 25122, 1129 | 25382, 1130 | 25634, 1131 | 25894, 1132 | 26150, 1133 | 26402, 1134 | 26666, 1135 | 26926, 1136 | 25634, 1137 | 25894, 1138 | 26150, 1139 | 26402, 1140 | 26666, 1141 | 26926, 1142 | 28706, 1143 | 28966, 1144 | 29222, 1145 | 29474, 1146 | 29734, 1147 | 29986, 1148 | 30242, 1149 | 30502, 1150 | 30766, 1151 | 31018, 1152 | 29734, 1153 | 29986, 1154 | 30242, 1155 | 30502, 1156 | 30766, 1157 | 31018, 1158 | -32638, 1159 | -32378, 1160 | -32122, 1161 | -31870, 1162 | -31610, 1163 | -31358, 1164 | -31102, 1165 | -30842, 1166 | -30578, 1167 | -30326, 1168 | -31610, 1169 | -31358, 1170 | -31102, 1171 | -30842, 1172 | -30578, 1173 | -30326, 1174 | -28538, 1175 | -28286, 1176 | -28030, 1177 | -27770, 1178 | -27518, 1179 | -27258, 1180 | -27002, 1181 | -26750, 1182 | -26486, 1183 | -26226, 1184 | 13347, 1185 | 13607, 1186 | 13863, 1187 | 14115, 1188 | 14379, 1189 | 14639, 1190 | 16387, 1191 | 16647, 1192 | 16903, 1193 | 17155, 1194 | 17415, 1195 | 17667, 1196 | 17923, 1197 | 18183, 1198 | 18447, 1199 | 18699, 1200 | 17415, 1201 | 17667, 1202 | 17923, 1203 | 18183, 1204 | 18447, 1205 | 18699, 1206 | 20487, 1207 | 20739, 1208 | 20995, 1209 | 21255, 1210 | 21507, 1211 | 21767, 1212 | 22023, 1213 | 22275, 1214 | 22539, 1215 | 22799, 1216 | 21507, 1217 | 21767, 1218 | 22023, 1219 | 22275, 1220 | 22539, 1221 | 22799, 1222 | 24615, 1223 | 24867, 1224 | 25123, 1225 | 25383, 1226 | 25635, 1227 | 25895, 1228 | 26151, 1229 | 26403, 1230 | 26667, 1231 | 26927, 1232 | 25635, 1233 | 25895, 1234 | 26151, 1235 | 26403, 1236 | 26667, 1237 | 26927, 1238 | 28707, 1239 | 28967, 1240 | 29223, 1241 | 29475, 1242 | 29735, 1243 | 29987, 1244 | 30243, 1245 | 30503, 1246 | 30767, 1247 | 31019, 1248 | 29735, 1249 | 29987, 1250 | 30243, 1251 | 30503, 1252 | 30767, 1253 | 31019, 1254 | -32637, 1255 | -32377, 1256 | -32121, 1257 | -31869, 1258 | -31609, 1259 | -31357, 1260 | -31101, 1261 | -30841, 1262 | -30577, 1263 | -30325, 1264 | -31609, 1265 | -31357, 1266 | -31101, 1267 | -30841, 1268 | -30577, 1269 | -30325, 1270 | -28537, 1271 | -28285, 1272 | -28029, 1273 | -27769, 1274 | -27517, 1275 | -27257, 1276 | -27001, 1277 | -26749, 1278 | -26485, 1279 | -26225, 1280 | -27517, 1281 | -27257, 1282 | -27001, 1283 | -26749, 1284 | -26485, 1285 | -26225, 1286 | -24409, 1287 | -24157, 1288 | -23901, 1289 | -23641, 1290 | -23389, 1291 | -23129, 1292 | -22873, 1293 | -22621, 1294 | -22357, 1295 | -22097, 1296 | -23389, 1297 | -23129, 1298 | -22873, 1299 | -22621, 1300 | -22357, 1301 | -22097, 1302 | -20317, 1303 | -20057, 1304 | -19801, 1305 | -19549, 1306 | -19289, 1307 | -19037, 1308 | -18781, 1309 | -18521, 1310 | -18257, 1311 | -18005, 1312 | -19289, 1313 | -19037, 1314 | -18781, 1315 | -18521, 1316 | -18257, 1317 | -18005, 1318 | -16249, 1319 | -15997, 1320 | -15741, 1321 | -15481, 1322 | -15229, 1323 | -14969, 1324 | -14713, 1325 | -14461, 1326 | -14197, 1327 | -13937, 1328 | -15229, 1329 | -14969, 1330 | -14713, 1331 | -14461, 1332 | -14197, 1333 | -13937, 1334 | -12157, 1335 | -11897, 1336 | -11641, 1337 | -11389, 1338 | -11129, 1339 | -10877, 1340 | -10621, 1341 | -10361, 1342 | -10097, 1343 | -9845, 1344 | -11129, 1345 | -10877, 1346 | -10621, 1347 | -10361, 1348 | -10097, 1349 | -9845, 1350 | -8029, 1351 | -7769, 1352 | -7513, 1353 | -7261, 1354 | -7001, 1355 | -6749, 1356 | -6493, 1357 | -6233, 1358 | -5969, 1359 | -5717, 1360 | -7001, 1361 | -6749, 1362 | -6493, 1363 | -6233, 1364 | -5969, 1365 | -5717, 1366 | -3929, 1367 | -3677, 1368 | -3421, 1369 | -3161, 1370 | -2909, 1371 | -2649, 1372 | -2393, 1373 | -2141, 1374 | -1877, 1375 | -1617, 1376 | -2909, 1377 | -2649, 1378 | -2393, 1379 | -2141, 1380 | -1877, 1381 | -1617, 1382 | 71, 1383 | 259, 1384 | 515, 1385 | 775, 1386 | 1027, 1387 | 1287, 1388 | 1543, 1389 | 1795, 1390 | 2059, 1391 | 2319, 1392 | 1027, 1393 | 1287, 1394 | 1543, 1395 | 1795, 1396 | 2059, 1397 | 2319, 1398 | 4099, 1399 | 4359, 1400 | 4615, 1401 | 4867, 1402 | 5127, 1403 | 5379, 1404 | 5635, 1405 | 5895, 1406 | 6159, 1407 | 6411, 1408 | 5127, 1409 | 5379, 1410 | 5635, 1411 | 5895, 1412 | 6159, 1413 | 6411, 1414 | 8227, 1415 | 8487, 1416 | 8743, 1417 | 8995, 1418 | 9255, 1419 | 9507, 1420 | 9763, 1421 | 10023, 1422 | 10287, 1423 | 10539, 1424 | 9255, 1425 | 9507, 1426 | 9763, 1427 | 10023, 1428 | 10287, 1429 | 10539, 1430 | 12327, 1431 | 12579, 1432 | 12835, 1433 | 13095, 1434 | 13347, 1435 | 13607, 1436 | 13863, 1437 | 14115, 1438 | 14379, 1439 | 14639, 1440 | 13347, 1441 | 13607, 1442 | 13863, 1443 | 14115, 1444 | 14379, 1445 | 14639, 1446 | 16387, 1447 | 16647, 1448 | 16903, 1449 | 17155, 1450 | 17415, 1451 | 17667, 1452 | 17923, 1453 | 18183, 1454 | 18447, 1455 | 18699, 1456 | 17415, 1457 | 17667, 1458 | 17923, 1459 | 18183, 1460 | 18447, 1461 | 18699, 1462 | 20487, 1463 | 20739, 1464 | 20995, 1465 | 21255, 1466 | 21507, 1467 | 21767, 1468 | 22023, 1469 | 22275, 1470 | 22539, 1471 | 22799, 1472 | 21507, 1473 | 21767, 1474 | 22023, 1475 | 22275, 1476 | 22539, 1477 | 22799, 1478 | 24615, 1479 | 24867, 1480 | 25123, 1481 | 25383, 1482 | 25635, 1483 | 25895, 1484 | 26151, 1485 | 26403, 1486 | 26667, 1487 | 26927, 1488 | 25635, 1489 | 25895, 1490 | 26151, 1491 | 26403, 1492 | 26667, 1493 | 26927, 1494 | 28707, 1495 | 28967, 1496 | 29223, 1497 | 29475, 1498 | 29735, 1499 | 29987, 1500 | 30243, 1501 | 30503, 1502 | 30767, 1503 | 31019, 1504 | 29735, 1505 | 29987, 1506 | 30243, 1507 | 30503, 1508 | 30767, 1509 | 31019, 1510 | -32637, 1511 | -32377, 1512 | -32121, 1513 | -31869, 1514 | -31609, 1515 | -31357, 1516 | -31101, 1517 | -30841, 1518 | -30577, 1519 | -30325, 1520 | -31609, 1521 | -31357, 1522 | -31101, 1523 | -30841, 1524 | -30577, 1525 | -30325, 1526 | -28537, 1527 | -28285, 1528 | -28029, 1529 | -27769, 1530 | -27517, 1531 | -27257, 1532 | -27001, 1533 | -26749, 1534 | -26485, 1535 | -26225, 1536 | -27517, 1537 | -27257, 1538 | -27001, 1539 | -26749, 1540 | -26485, 1541 | -26225, 1542 | -1346, 1543 | -1094, 1544 | -834, 1545 | -582, 1546 | -326, 1547 | -66, 1548 | 70, 1549 | 258, 1550 | 514, 1551 | 774, 1552 | 1026, 1553 | 1286, 1554 | 1542, 1555 | 1794, 1556 | 2058, 1557 | 2318, 1558 | 2590, 1559 | 2842, 1560 | 3102, 1561 | 3354, 1562 | 3610, 1563 | 3870, 1564 | 4098, 1565 | 4358, 1566 | 4614, 1567 | 4866, 1568 | 5126, 1569 | 5378, 1570 | 5634, 1571 | 5894, 1572 | 6158, 1573 | 6410, 1574 | 6682, 1575 | 6942, 1576 | 7194, 1577 | 7454, 1578 | 7710, 1579 | 7962, 1580 | 8226, 1581 | 8486, 1582 | 8742, 1583 | 8994, 1584 | 9254, 1585 | 9506, 1586 | 9762, 1587 | 10022, 1588 | 10286, 1589 | 10538, 1590 | 10810, 1591 | 11070, 1592 | 11322, 1593 | 11582, 1594 | 11838, 1595 | 12090, 1596 | 12326, 1597 | 12578, 1598 | 12834, 1599 | 13094, 1600 | 13346, 1601 | 13606, 1602 | 13862, 1603 | 14114, 1604 | 14378, 1605 | 14638, 1606 | 14910, 1607 | 15162, 1608 | 15422, 1609 | 15674, 1610 | 15930, 1611 | 16190, 1612 | 16386, 1613 | 16646, 1614 | 16902, 1615 | 17154, 1616 | 17414, 1617 | 17666, 1618 | 17922, 1619 | 18182, 1620 | 18446, 1621 | 18698, 1622 | 18970, 1623 | 19230, 1624 | 19482, 1625 | 19742, 1626 | 19998, 1627 | 20250, 1628 | 20486, 1629 | 20738, 1630 | 20994, 1631 | 21254, 1632 | 21506, 1633 | 21766, 1634 | 22022, 1635 | 22274, 1636 | 22538, 1637 | 22798, 1638 | 23070, 1639 | 23322, 1640 | 23582, 1641 | 23834, 1642 | 24090, 1643 | 24350, 1644 | 24614, 1645 | 24866, 1646 | 25122, 1647 | 25382, 1648 | 25634, 1649 | 25894, 1650 | 26150, 1651 | 26402, 1652 | 26666, 1653 | 26926, 1654 | 27198, 1655 | 27450, 1656 | 27710, 1657 | 27962, 1658 | 28218, 1659 | 28478, 1660 | 28706, 1661 | 28966, 1662 | 29222, 1663 | 29474, 1664 | 29734, 1665 | 29986, 1666 | 30242, 1667 | 30502, 1668 | 30766, 1669 | 31018, 1670 | 31290, 1671 | 31550, 1672 | 31802, 1673 | 32062, 1674 | 32318, 1675 | 32570, 1676 | -32638, 1677 | -32378, 1678 | -32122, 1679 | -31870, 1680 | -31610, 1681 | -31358, 1682 | -31102, 1683 | -30842, 1684 | -30578, 1685 | -30326, 1686 | -30054, 1687 | -29794, 1688 | -29542, 1689 | -29282, 1690 | -29026, 1691 | -28774, 1692 | -28538, 1693 | -28286, 1694 | -28030, 1695 | -27770, 1696 | 13347, 1697 | 13607, 1698 | 13863, 1699 | 14115, 1700 | 14379, 1701 | 14639, 1702 | 14911, 1703 | 15163, 1704 | 15423, 1705 | 15675, 1706 | 15931, 1707 | 16191, 1708 | 16387, 1709 | 16647, 1710 | 16903, 1711 | 17155, 1712 | 17415, 1713 | 17667, 1714 | 17923, 1715 | 18183, 1716 | 18447, 1717 | 18699, 1718 | 18971, 1719 | 19231, 1720 | 19483, 1721 | 19743, 1722 | 19999, 1723 | 20251, 1724 | 20487, 1725 | 20739, 1726 | 20995, 1727 | 21255, 1728 | 21507, 1729 | 21767, 1730 | 22023, 1731 | 22275, 1732 | 22539, 1733 | 22799, 1734 | 23071, 1735 | 23323, 1736 | 23583, 1737 | 23835, 1738 | 24091, 1739 | 24351, 1740 | 24615, 1741 | 24867, 1742 | 25123, 1743 | 25383, 1744 | 25635, 1745 | 25895, 1746 | 26151, 1747 | 26403, 1748 | 26667, 1749 | 26927, 1750 | 27199, 1751 | 27451, 1752 | 27711, 1753 | 27963, 1754 | 28219, 1755 | 28479, 1756 | 28707, 1757 | 28967, 1758 | 29223, 1759 | 29475, 1760 | 29735, 1761 | 29987, 1762 | 30243, 1763 | 30503, 1764 | 30767, 1765 | 31019, 1766 | 31291, 1767 | 31551, 1768 | 31803, 1769 | 32063, 1770 | 32319, 1771 | 32571, 1772 | -32637, 1773 | -32377, 1774 | -32121, 1775 | -31869, 1776 | -31609, 1777 | -31357, 1778 | -31101, 1779 | -30841, 1780 | -30577, 1781 | -30325, 1782 | -30053, 1783 | -29793, 1784 | -29541, 1785 | -29281, 1786 | -29025, 1787 | -28773, 1788 | -28537, 1789 | -28285, 1790 | -28029, 1791 | -27769, 1792 | -27517, 1793 | -27257, 1794 | -27001, 1795 | -26749, 1796 | -26485, 1797 | -26225, 1798 | -25953, 1799 | -25701, 1800 | -25441, 1801 | -25189, 1802 | -24933, 1803 | -24673, 1804 | -24409, 1805 | -24157, 1806 | -23901, 1807 | -23641, 1808 | -23389, 1809 | -23129, 1810 | -22873, 1811 | -22621, 1812 | -22357, 1813 | -22097, 1814 | -21825, 1815 | -21573, 1816 | -21313, 1817 | -21061, 1818 | -20805, 1819 | -20545, 1820 | -20317, 1821 | -20057, 1822 | -19801, 1823 | -19549, 1824 | -19289, 1825 | -19037, 1826 | -18781, 1827 | -18521, 1828 | -18257, 1829 | -18005, 1830 | -17733, 1831 | -17473, 1832 | -17221, 1833 | -16961, 1834 | -16705, 1835 | -16453, 1836 | -16249, 1837 | -15997, 1838 | -15741, 1839 | -15481, 1840 | -15229, 1841 | -14969, 1842 | -14713, 1843 | -14461, 1844 | -14197, 1845 | -13937, 1846 | -13665, 1847 | -13413, 1848 | -13153, 1849 | -12901, 1850 | -12645, 1851 | -12385, 1852 | -12157, 1853 | -11897, 1854 | -11641, 1855 | -11389, 1856 | -11129, 1857 | -10877, 1858 | -10621, 1859 | -10361, 1860 | -10097, 1861 | -9845, 1862 | -9573, 1863 | -9313, 1864 | -9061, 1865 | -8801, 1866 | -8545, 1867 | -8293, 1868 | -8029, 1869 | -7769, 1870 | -7513, 1871 | -7261, 1872 | -7001, 1873 | -6749, 1874 | -6493, 1875 | -6233, 1876 | -5969, 1877 | -5717, 1878 | -5445, 1879 | -5185, 1880 | -4933, 1881 | -4673, 1882 | -4417, 1883 | -4165, 1884 | -3929, 1885 | -3677, 1886 | -3421, 1887 | -3161, 1888 | -2909, 1889 | -2649, 1890 | -2393, 1891 | -2141, 1892 | -1877, 1893 | -1617, 1894 | -1345, 1895 | -1093, 1896 | -833, 1897 | -581, 1898 | -325, 1899 | -65, 1900 | 71, 1901 | 259, 1902 | 515, 1903 | 775, 1904 | 1027, 1905 | 1287, 1906 | 1543, 1907 | 1795, 1908 | 2059, 1909 | 2319, 1910 | 2591, 1911 | 2843, 1912 | 3103, 1913 | 3355, 1914 | 3611, 1915 | 3871, 1916 | 4099, 1917 | 4359, 1918 | 4615, 1919 | 4867, 1920 | 5127, 1921 | 5379, 1922 | 5635, 1923 | 5895, 1924 | 6159, 1925 | 6411, 1926 | 6683, 1927 | 6943, 1928 | 7195, 1929 | 7455, 1930 | 7711, 1931 | 7963, 1932 | 8227, 1933 | 8487, 1934 | 8743, 1935 | 8995, 1936 | 9255, 1937 | 9507, 1938 | 9763, 1939 | 10023, 1940 | 10287, 1941 | 10539, 1942 | 10811, 1943 | 11071, 1944 | 11323, 1945 | 11583, 1946 | 11839, 1947 | 12091, 1948 | 12327, 1949 | 12579, 1950 | 12835, 1951 | 13095, 1952 | 13347, 1953 | 13607, 1954 | 13863, 1955 | 14115, 1956 | 14379, 1957 | 14639, 1958 | 14911, 1959 | 15163, 1960 | 15423, 1961 | 15675, 1962 | 15931, 1963 | 16191, 1964 | 16387, 1965 | 16647, 1966 | 16903, 1967 | 17155, 1968 | 17415, 1969 | 17667, 1970 | 17923, 1971 | 18183, 1972 | 18447, 1973 | 18699, 1974 | 18971, 1975 | 19231, 1976 | 19483, 1977 | 19743, 1978 | 19999, 1979 | 20251, 1980 | 20487, 1981 | 20739, 1982 | 20995, 1983 | 21255, 1984 | 21507, 1985 | 21767, 1986 | 22023, 1987 | 22275, 1988 | 22539, 1989 | 22799, 1990 | 23071, 1991 | 23323, 1992 | 23583, 1993 | 23835, 1994 | 24091, 1995 | 24351, 1996 | 24615, 1997 | 24867, 1998 | 25123, 1999 | 25383, 2000 | 25635, 2001 | 25895, 2002 | 26151, 2003 | 26403, 2004 | 26667, 2005 | 26927, 2006 | 27199, 2007 | 27451, 2008 | 27711, 2009 | 27963, 2010 | 28219, 2011 | 28479, 2012 | 28707, 2013 | 28967, 2014 | 29223, 2015 | 29475, 2016 | 29735, 2017 | 29987, 2018 | 30243, 2019 | 30503, 2020 | 30767, 2021 | 31019, 2022 | 31291, 2023 | 31551, 2024 | 31803, 2025 | 32063, 2026 | 32319, 2027 | 32571, 2028 | -32637, 2029 | -32377, 2030 | -32121, 2031 | -31869, 2032 | -31609, 2033 | -31357, 2034 | -31101, 2035 | -30841, 2036 | -30577, 2037 | -30325, 2038 | -30053, 2039 | -29793, 2040 | -29541, 2041 | -29281, 2042 | -29025, 2043 | -28773, 2044 | -28537, 2045 | -28285, 2046 | -28029, 2047 | -27769, 2048 | -27517, 2049 | -27257, 2050 | -27001, 2051 | -26749, 2052 | -26485, 2053 | -26225 2054 | } 2055 | 2056 | return DAATable 2057 | 2058 | -------------------------------------------------------------------------------- /opcodes/dd.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- FDxx opcodes 3 | -- 4 | 5 | local logger = require "logger" 6 | local common_ops = require "opcodes.common" 7 | 8 | 9 | local function sign_extend (v) 10 | return v < 128 and v or v - 256 11 | end 12 | 13 | local function high_low (value) 14 | return (value & 0xff00) >> 8, value & 0x00ff 15 | end 16 | 17 | local ADD_16 = common_ops.ADD_16 18 | local ADD_8 = common_ops.ADD_8 19 | local AND = common_ops.AND 20 | local XOR = common_ops.XOR 21 | local OR = common_ops.OR 22 | local CP = common_ops.CP 23 | local SBC = common_ops.SBC 24 | local SUB = common_ops.SUB 25 | local ADC_8 = common_ops.ADC_8 26 | local INC = common_ops.INC 27 | local DEC = common_ops.DEC 28 | 29 | local opcodes_ddcb = require "opcodes.ddcb" 30 | 31 | local FLAG_S = 128 32 | local FLAG_Z = 64 33 | local FLAG_B5 = 32 34 | local FLAG_H = 16 35 | local FLAG_B3 = 8 36 | local FLAG_PV = 4 37 | local FLAG_N = 2 38 | local FLAG_C = 1 39 | 40 | local FLAG_N_OFF = 253 41 | local FLAG_PV_OFF = 251 42 | local FLAG_Z_OFF = 191 43 | local FLAG_H_OFF = 239 44 | local FLAG_S_OFF = 127 45 | local FLAG_C_OFF = 254 46 | 47 | local opcodes = {} 48 | 49 | --- 50 | -- Will be bound to the actual functions to be called later in bind_io 51 | -- 52 | local contend_read_no_mreq 53 | local contend_write_no_mreq 54 | local read_mem_byte 55 | local read_mem_byte_internal 56 | local read_mem_word 57 | local write_mem_byte 58 | local write_mem_word 59 | 60 | function opcodes.bind_io (binds) 61 | contend_read_no_mreq = assert(binds.memory.contend_read_no_mreq) 62 | contend_write_no_mreq = assert(binds.memory.contend_write_no_mreq) 63 | read_mem_byte = assert(binds.memory.read_mem_byte) 64 | read_mem_byte_internal = assert(binds.memory.read_mem_byte_internal) 65 | read_mem_word = assert(binds.memory.read_mem_word) 66 | write_mem_byte = assert(binds.memory.write_mem_byte) 67 | write_mem_word = assert(binds.memory.write_mem_word) 68 | 69 | opcodes_ddcb.bind_io(binds) 70 | end 71 | 72 | 73 | -- TODO ESTO y FCCB.lua se duplican para IX e IX 74 | 75 | -- ADD IX,BC 76 | opcodes[0x09] = function (cpu) 77 | --logger.debug("ADD IX,BC") 78 | cpu.IX = ADD_16(cpu, cpu.IX, cpu.C | cpu.B << 8) 79 | cpu.PC = (cpu.PC + 1) & 0xffff 80 | end 81 | 82 | -- ADD IX,DE 83 | opcodes[0x19] = function (cpu) 84 | --logger.debug("ADD IX,DE") 85 | cpu.IX = ADD_16(cpu, cpu.IX, cpu.E | cpu.D << 8) 86 | cpu.PC = (cpu.PC + 1) & 0xffff 87 | end 88 | 89 | -- LD IX,nnnn 90 | opcodes[0x21] = function (cpu) 91 | local word = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 92 | --logger.debug("LD IX,$%04x", word) 93 | cpu.IX = word 94 | cpu.PC = (cpu.PC + 3) & 0xffff 95 | end 96 | 97 | -- LD (nnnn),IX 98 | opcodes[0x22] = function (cpu) 99 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 100 | --logger.debug("LD ($%04x),IX", address) 101 | write_mem_word(cpu, address, cpu.IX) 102 | cpu.PC = (cpu.PC + 3) & 0xffff 103 | end 104 | 105 | -- INC IX 106 | opcodes[0x23] = function (cpu) 107 | --logger.debug("INC IX") 108 | cpu.IX = (cpu.IX + 1) & 0xffff 109 | -- contend with IR register pair 110 | local I_high = cpu.I << 8 111 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 112 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 113 | cpu.PC = (cpu.PC + 1) & 0xffff 114 | end 115 | 116 | -- INC IXh 117 | opcodes[0x24] = function (cpu) 118 | --logger.debug("INC IXh") 119 | -- TODO: faltan los tstates 120 | local IXh, IXl = high_low(cpu.IX) 121 | IXh = INC(cpu, IXh) 122 | cpu.IX = IXl | IXh << 8 123 | cpu.PC = (cpu.PC + 1) & 0xffff 124 | end 125 | 126 | -- DEC 127 | opcodes[0x25] = function (cpu) 128 | --logger.debug("DEC IXh") 129 | local IXh, IXl = high_low(cpu.IX) 130 | IXh = DEC(cpu, IXh) 131 | cpu.IX = IXl | IXh << 8 132 | cpu.PC = (cpu.PC + 1) & 0xffff 133 | end 134 | 135 | -- LD IXh,nn 136 | opcodes[0x26] = function (cpu) 137 | --logger.debug("LD IXh,nn") 138 | local byte = read_mem_byte(cpu, (cpu.PC + 1) & 0xffff) 139 | cpu.IX = (byte << 8) | (cpu.IX & 0xff) 140 | cpu.PC = (cpu.PC + 2) & 0xffff 141 | end 142 | 143 | -- ADD IX,IX 144 | opcodes[0x29] = function (cpu) 145 | --logger.debug("ADD IX,IX") 146 | cpu.IX = ADD_16(cpu, cpu.IX, cpu.IX) 147 | cpu.PC = (cpu.PC + 1) & 0xffff 148 | end 149 | 150 | -- LD IX,(nnnn) 151 | opcodes[0x2a] = function (cpu) 152 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 153 | --logger.debug("LD IX,($%04x)", address) 154 | cpu.IX = read_mem_word(cpu, address) 155 | cpu.PC = (cpu.PC + 3) & 0xffff 156 | end 157 | 158 | -- DEC IX 159 | opcodes[0x2b] = function (cpu) 160 | --logger.debug("DEC IX") 161 | cpu.IX = (cpu.IX - 1) & 0xffff 162 | -- contend with IR register pair 163 | local I_high = cpu.I << 8 164 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 165 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 166 | cpu.PC = (cpu.PC + 1) & 0xffff 167 | end 168 | 169 | -- INC IXl 170 | opcodes[0x2c] = function (cpu) 171 | --logger.debug("INC IXl") 172 | -- TODO: faltan los tstates 173 | local IXh, IXl = high_low(cpu.IX) 174 | IXl = INC(cpu, IXl) 175 | cpu.IX = IXl | IXh << 8 176 | cpu.PC = (cpu.PC + 1) & 0xffff 177 | end 178 | 179 | -- DEC IXl 180 | opcodes[0x2d] = function (cpu) 181 | --logger.debug("DEC IXl") 182 | local IXh, IXl = high_low(cpu.IX) 183 | IXl = DEC(cpu, IXl) 184 | cpu.IX = IXl | IXh << 8 185 | cpu.PC = (cpu.PC + 1) & 0xffff 186 | end 187 | 188 | -- LD IXl,nn 189 | opcodes[0x2e] = function (cpu) 190 | --logger.debug("LD IXl,nn") 191 | local byte = read_mem_byte(cpu, (cpu.PC + 1) & 0xffff) 192 | cpu.IX = (cpu.IX & 0xff00) | byte 193 | cpu.PC = (cpu.PC + 2) & 0xffff 194 | end 195 | 196 | -- INC (IX+nn) 197 | opcodes[0x34] = function (cpu) 198 | --logger.debug("INC (IX+nn)") 199 | local offset = sign_extend(read_mem_byte(cpu, (cpu.PC + 1) & 0xffff)) 200 | for i=1,5 do 201 | contend_read_no_mreq(cpu, (cpu.PC + 1) & 0xffff, 1) 202 | end 203 | local byte = read_mem_byte(cpu, cpu.IX + offset) 204 | contend_read_no_mreq(cpu, cpu.IX + offset, 1) 205 | byte = INC(cpu, byte) 206 | write_mem_byte(cpu, cpu.IX + offset, byte) 207 | 208 | cpu.PC = (cpu.PC + 2) & 0xffff 209 | end 210 | 211 | -- DEC (IX+nn) 212 | opcodes[0x35] = function (cpu) 213 | --logger.debug("DEC (IX+nn)") 214 | local offset = sign_extend( read_mem_byte(cpu, (cpu.PC + 1) & 0xffff) ) 215 | 216 | for i=1,5 do 217 | contend_read_no_mreq(cpu, (cpu.PC + 1) & 0xffff, 1) 218 | end 219 | local byte = read_mem_byte(cpu, cpu.IX + offset) 220 | contend_read_no_mreq(cpu, cpu.IX + offset, 1) 221 | byte = DEC(cpu, byte) 222 | write_mem_byte(cpu, cpu.IX + offset, byte) 223 | 224 | cpu.PC = (cpu.PC + 2) & 0xffff 225 | end 226 | 227 | -- LD (IX+dd),nn 228 | opcodes[0x36] = function (cpu) 229 | --logger.debug("LD (IX+dd),nn") 230 | local offset = sign_extend( read_mem_byte(cpu, (cpu.PC + 1) & 0xffff) ) 231 | local byte = read_mem_byte(cpu, (cpu.PC + 2) & 0xffff) 232 | contend_read_no_mreq(cpu, (cpu.PC + 2) & 0xffff, 1) 233 | contend_read_no_mreq(cpu, (cpu.PC + 2) & 0xffff, 1) 234 | write_mem_byte(cpu, cpu.IX + offset, byte) 235 | cpu.PC = (cpu.PC + 3) & 0xffff 236 | end 237 | 238 | -- ADD IX,SP 239 | opcodes[0x39] = function (cpu) 240 | --logger.debug("ADD IX,SP") 241 | cpu.IX = ADD_16(cpu, cpu.IX, cpu.SP) 242 | cpu.PC = (cpu.PC + 1) & 0xffff 243 | end 244 | 245 | -- LD B,IXh 246 | opcodes[0x44] = function (cpu) 247 | --logger.debug("LD B,IXh") 248 | cpu.B = (cpu.IX & 0xff00) >> 8 249 | cpu.PC = (cpu.PC + 1) & 0xffff 250 | end 251 | 252 | -- LD B,IXl 253 | opcodes[0x45] = function (cpu) 254 | --logger.debug("LD B,IXl") 255 | cpu.B = cpu.IX & 0x00ff 256 | cpu.PC = (cpu.PC + 1) & 0xffff 257 | end 258 | 259 | -- LD B,(IX+nn) 260 | opcodes[0x46] = function (cpu) 261 | --logger.debug("LD B,(IX+nn)") 262 | local offset = sign_extend( read_mem_byte(cpu, (cpu.PC + 1) & 0xffff) ) 263 | for i=1,5 do 264 | contend_read_no_mreq(cpu, (cpu.PC + 1) & 0xffff, 1) 265 | end 266 | cpu.B = read_mem_byte(cpu, cpu.IX + offset) 267 | cpu.PC = (cpu.PC + 2) & 0xffff 268 | end 269 | 270 | -- LD C,IXh 271 | opcodes[0x4c] = function (cpu) 272 | --logger.debug("LD C,IXh") 273 | cpu.C = (cpu.IX & 0xff00) >> 8 274 | cpu.PC = (cpu.PC + 1) & 0xffff 275 | end 276 | 277 | -- LD C,IXl 278 | opcodes[0x4d] = function (cpu) 279 | --logger.debug("LD C,IXl") 280 | cpu.C = cpu.IX & 0x00ff 281 | cpu.PC = (cpu.PC + 1) & 0xffff 282 | end 283 | 284 | -- LD C,(IX+nn) 285 | opcodes[0x4e] = function (cpu) 286 | --logger.debug("LD C,(IX+nn)") 287 | local offset = sign_extend( read_mem_byte(cpu, (cpu.PC + 1) & 0xffff) ) 288 | for i=1,5 do 289 | contend_read_no_mreq(cpu, (cpu.PC + 1) & 0xffff, 1) 290 | end 291 | cpu.C = read_mem_byte(cpu, cpu.IX + offset) 292 | cpu.PC = (cpu.PC + 2) & 0xffff 293 | end 294 | 295 | -- LD D,IXh 296 | opcodes[0x54] = function (cpu) 297 | --logger.debug("LD D,IXh") 298 | cpu.D = (cpu.IX & 0xff00) >> 8 299 | cpu.PC = (cpu.PC + 1) & 0xffff 300 | end 301 | 302 | -- LD D,IXl 303 | opcodes[0x55] = function (cpu) 304 | --logger.debug("LD D,IXl") 305 | cpu.D = cpu.IX & 0x00ff 306 | cpu.PC = (cpu.PC + 1) & 0xffff 307 | end 308 | 309 | -- LD D,(IX+nn) 310 | opcodes[0x56] = function (cpu) 311 | --logger.debug("LD D,(IX+nn)") 312 | local offset = sign_extend( read_mem_byte(cpu, (cpu.PC + 1) & 0xffff) ) 313 | for i=1,5 do 314 | contend_read_no_mreq(cpu, (cpu.PC + 1) & 0xffff, 1) 315 | end 316 | cpu.D = read_mem_byte(cpu, cpu.IX + offset) 317 | cpu.PC = (cpu.PC + 2) & 0xffff 318 | end 319 | 320 | -- LD E,IXh 321 | opcodes[0x5c] = function (cpu) 322 | --logger.debug("LD E,IXh") 323 | cpu.E = (cpu.IX & 0xff00) >> 8 324 | cpu.PC = (cpu.PC + 1) & 0xffff 325 | end 326 | 327 | -- LD E,IXl 328 | opcodes[0x5d] = function (cpu) 329 | --logger.debug("LD E,IXl") 330 | cpu.E = cpu.IX & 0x00ff 331 | cpu.PC = (cpu.PC + 1) & 0xffff 332 | end 333 | 334 | -- LD E,(IX+nn) 335 | opcodes[0x5e] = function (cpu) 336 | --logger.debug("LD E,(IX+nn)") 337 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 338 | for i=1,5 do 339 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 340 | end 341 | cpu.E = read_mem_byte(cpu, cpu.IX + offset) 342 | cpu.PC = (cpu.PC + 2) & 0xffff 343 | end 344 | 345 | -- LD IXh,B 346 | opcodes[0x60] = function (cpu) 347 | --logger.debug("LD IXh,B") 348 | cpu.IX = (cpu.B << 8) | (cpu.IX & 0x00ff) 349 | cpu.PC = (cpu.PC + 1) & 0xffff 350 | end 351 | 352 | -- LD IXh,C 353 | opcodes[0x61] = function (cpu) 354 | --logger.debug("LD IXh,C") 355 | cpu.IX = (cpu.C << 8) | (cpu.IX & 0x00ff) 356 | cpu.PC = (cpu.PC + 1) & 0xffff 357 | end 358 | 359 | -- LD IXh,D 360 | opcodes[0x62] = function (cpu) 361 | --logger.debug("LD IXh,D") 362 | cpu.IX = (cpu.D << 8) | (cpu.IX & 0x00ff) 363 | cpu.PC = (cpu.PC + 1) & 0xffff 364 | end 365 | 366 | -- LD IXh,E 367 | opcodes[0x63] = function (cpu) 368 | --logger.debug("LD IXh,E") 369 | cpu.IX = (cpu.E << 8) | (cpu.IX & 0x00ff) 370 | cpu.PC = (cpu.PC + 1) & 0xffff 371 | end 372 | 373 | -- LD IXh,IXh 374 | opcodes[0x64] = function (cpu) 375 | --logger.debug("LD IXh,IXh") 376 | -- LD IXh,IXh 377 | cpu.PC = (cpu.PC + 1) & 0xffff 378 | end 379 | 380 | -- LD IXh,IXl 381 | opcodes[0x65] = function (cpu) 382 | --logger.debug("LD IXh,IXl") 383 | local IXl = cpu.IX & 0x00ff 384 | cpu.IX = IXl | (IXl << 8) 385 | cpu.PC = (cpu.PC + 1) & 0xffff 386 | end 387 | 388 | -- LD H,(IX+nn) 389 | opcodes[0x66] = function (cpu) 390 | --logger.debug("LD H,(IX+nn)") 391 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 392 | for i=1,5 do 393 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 394 | end 395 | cpu.H = read_mem_byte(cpu, cpu.IX + offset) 396 | cpu.PC = (cpu.PC + 2) & 0xffff 397 | end 398 | 399 | -- LD IXh,A 400 | opcodes[0x67] = function (cpu) 401 | --logger.debug("LD IXh,A") 402 | cpu.IX = (cpu.A << 8) | (cpu.IX & 0x00ff) 403 | cpu.PC = (cpu.PC + 1) & 0xffff 404 | end 405 | 406 | -- LD IXl,B 407 | opcodes[0x68] = function (cpu) 408 | --logger.debug("LD IXl,B") 409 | cpu.IX = (cpu.IX & 0xff00) | cpu.B 410 | cpu.PC = (cpu.PC + 1) & 0xffff 411 | end 412 | 413 | -- LD IXl,C 414 | opcodes[0x69] = function (cpu) 415 | --logger.debug("LD IXl,C") 416 | cpu.IX = (cpu.IX & 0xff00) | cpu.C 417 | cpu.PC = (cpu.PC + 1) & 0xffff 418 | end 419 | 420 | -- LD IXl,D 421 | opcodes[0x6a] = function (cpu) 422 | --logger.debug("LD IXl,D") 423 | cpu.IX = (cpu.IX & 0xff00) | cpu.D 424 | cpu.PC = (cpu.PC + 1) & 0xffff 425 | end 426 | 427 | -- LD IXl,E 428 | opcodes[0x6b] = function (cpu) 429 | --logger.debug("LD IXl,E") 430 | cpu.IX = (cpu.IX & 0xff00) | cpu.E 431 | cpu.PC = (cpu.PC + 1) & 0xffff 432 | end 433 | 434 | -- LD IXl,IXh 435 | opcodes[0x6c] = function (cpu) 436 | --logger.debug("LD IXl,IXh") 437 | local high, low = high_low(cpu.IX) 438 | cpu.IX = high | (high << 8) 439 | cpu.PC = (cpu.PC + 1) & 0xffff 440 | end 441 | 442 | -- LD IXl,IXl 443 | opcodes[0x6d] = function (cpu) 444 | --logger.debug("LD IXl,IXl") 445 | cpu.PC = (cpu.PC + 1) & 0xffff 446 | end 447 | 448 | -- LD L,IX+nn 449 | opcodes[0x6e] = function (cpu) 450 | --logger.debug("LD L,(IX+nn)") 451 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 452 | for i=1,5 do 453 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 454 | end 455 | cpu.L = read_mem_byte(cpu, cpu.IX + offset) 456 | cpu.PC = (cpu.PC + 2) & 0xffff 457 | end 458 | 459 | -- LD IXl,A 460 | opcodes[0x6f] = function (cpu) 461 | --logger.debug("LD IXl,A") 462 | cpu.IX = (cpu.IX & 0xff00) | cpu.A 463 | cpu.PC = (cpu.PC + 1) & 0xffff 464 | end 465 | 466 | -- LD (IX+nn),B 467 | opcodes[0x70] = function (cpu) 468 | --logger.debug("LD (IX+nn),B") 469 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 470 | for i=1,5 do 471 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 472 | end 473 | write_mem_byte(cpu, cpu.IX + offset, cpu.B) 474 | cpu.PC = (cpu.PC + 2) & 0xffff 475 | end 476 | 477 | -- LD (IX+nn),C 478 | opcodes[0x71] = function (cpu) 479 | --logger.debug("LD (IX+nn),C") 480 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 481 | for i=1,5 do 482 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 483 | end 484 | write_mem_byte(cpu, cpu.IX + offset, cpu.C) 485 | cpu.PC = (cpu.PC + 2) & 0xffff 486 | end 487 | 488 | -- LD (IX+nn),D 489 | opcodes[0x72] = function (cpu) 490 | --logger.debug("LD (IX+nn),D") 491 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 492 | for i=1,5 do 493 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 494 | end 495 | write_mem_byte(cpu, cpu.IX + offset, cpu.D) 496 | cpu.PC = (cpu.PC + 2) & 0xffff 497 | end 498 | 499 | -- LD (IX+nn),E 500 | opcodes[0x73] = function (cpu) 501 | --logger.debug("LD (IX+nn),E") 502 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 503 | for i=1,5 do 504 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 505 | end 506 | write_mem_byte(cpu, cpu.IX + offset, cpu.E) 507 | cpu.PC = (cpu.PC + 2) & 0xffff 508 | end 509 | 510 | -- LD (IX+nn),H 511 | opcodes[0x74] = function (cpu) 512 | --logger.debug("LD (IX+nn),H") 513 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 514 | for i=1,5 do 515 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 516 | end 517 | write_mem_byte(cpu, cpu.IX + offset, cpu.H) 518 | cpu.PC = (cpu.PC + 2) & 0xffff 519 | end 520 | 521 | -- LD (IX+nn),L 522 | opcodes[0x75] = function (cpu) 523 | --logger.debug("LD (IX+nn),L") 524 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 525 | for i=1,5 do 526 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 527 | end 528 | write_mem_byte(cpu, cpu.IX + offset, cpu.L) 529 | cpu.PC = (cpu.PC + 2) & 0xffff 530 | end 531 | 532 | -- LD (IX+nn),A 533 | opcodes[0x77] = function (cpu) 534 | --logger.debug("LD (IX+nn),A") 535 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 536 | for i=1,5 do 537 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 538 | end 539 | write_mem_byte(cpu, cpu.IX + offset, cpu.A) 540 | cpu.PC = (cpu.PC + 2) & 0xffff 541 | end 542 | 543 | -- LD A,IXh 544 | opcodes[0x7c] = function (cpu) 545 | --logger.debug("LD A,IXh") 546 | cpu.A = (cpu.IX & 0xff00) >> 8 547 | cpu.PC = (cpu.PC + 1) & 0xffff 548 | end 549 | 550 | -- LD A,IXl 551 | opcodes[0x7d] = function (cpu) 552 | --logger.debug("LD A,IXl") 553 | cpu.A = cpu.IX & 0x00ff 554 | cpu.PC = (cpu.PC + 1) & 0xffff 555 | end 556 | 557 | -- LD A,(IX+nn) 558 | opcodes[0x7e] = function (cpu) 559 | --logger.debug("LD A,(IX+nn)") 560 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 561 | for i=1,5 do 562 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 563 | end 564 | cpu.A = read_mem_byte(cpu, cpu.IX + offset) 565 | cpu.PC = (cpu.PC + 2) & 0xffff 566 | end 567 | 568 | -- ADD A,IXh 569 | opcodes[0x84] = function (cpu) 570 | --logger.debug("ADD A,IXh") 571 | ADD_8(cpu, (cpu.IX & 0xff00) >> 8) 572 | cpu.PC = (cpu.PC + 1) & 0xffff 573 | end 574 | 575 | -- ADD A,IXl 576 | opcodes[0x85] = function (cpu) 577 | --logger.debug("ADD A,IXl") 578 | ADD_8(cpu, cpu.IX & 0x00ff) 579 | cpu.PC = (cpu.PC + 1) & 0xffff 580 | end 581 | 582 | -- ADD A,(IX+nn) 583 | opcodes[0x86] = function (cpu) 584 | --logger.debug("ADD A,(IX+nn)") 585 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 586 | for i=1,5 do 587 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 588 | end 589 | local byte = read_mem_byte(cpu, cpu.IX + offset) 590 | ADD_8(cpu, byte) 591 | cpu.PC = (cpu.PC + 2) & 0xffff 592 | end 593 | 594 | -- ADC A,IXh 595 | opcodes[0x8c] = function (cpu) 596 | --logger.debug("ADC A,IXh") 597 | ADC_8(cpu, (cpu.IX & 0xff00) >> 8) 598 | cpu.PC = (cpu.PC + 1) & 0xffff 599 | end 600 | 601 | -- ADC A,IXl 602 | opcodes[0x8d] = function (cpu) 603 | --logger.debug("ADC A,IXl") 604 | ADC_8(cpu, cpu.IX & 0x00ff) 605 | cpu.PC = (cpu.PC + 1) & 0xffff 606 | end 607 | 608 | -- ADC A,(IX+nn) 609 | opcodes[0x8e] = function (cpu) 610 | --logger.debug("ADC A,(IX+nn)") 611 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 612 | for i=1,5 do 613 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 614 | end 615 | ADC_8(cpu, read_mem_byte(cpu, cpu.IX + offset)) 616 | cpu.PC = (cpu.PC + 2) & 0xffff 617 | end 618 | 619 | -- SUB IXh 620 | opcodes[0x94] = function (cpu) 621 | --logger.debug("SUB IXh") 622 | SUB(cpu, (cpu.IX & 0xff00) >> 8) 623 | cpu.PC = (cpu.PC + 1) & 0xffff 624 | end 625 | 626 | -- SUB IXl 627 | opcodes[0x95] = function (cpu) 628 | --logger.debug("SUB IXl") 629 | SUB(cpu, cpu.IX & 0x00ff) 630 | cpu.PC = (cpu.PC + 1) & 0xffff 631 | end 632 | 633 | -- SUB A,(IX+nn) 634 | opcodes[0x96] = function (cpu) 635 | --logger.debug("SUB A,(IX+nn)") 636 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 637 | for i=1,5 do 638 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 639 | end 640 | SUB(cpu, read_mem_byte(cpu, cpu.IX + offset)) 641 | cpu.PC = (cpu.PC + 2) & 0xffff 642 | end 643 | 644 | -- SBC A,IXh 645 | opcodes[0x9c] = function (cpu) 646 | --logger.debug("SBC A,IXh") 647 | SBC(cpu, (cpu.IX & 0xff00) >> 8) 648 | cpu.PC = (cpu.PC + 1) & 0xffff 649 | end 650 | 651 | -- SBC A,IXl 652 | opcodes[0x9d] = function (cpu) 653 | --logger.debug("SBC A,IXl") 654 | SBC(cpu, cpu.IX & 0x00ff) 655 | cpu.PC = (cpu.PC + 1) & 0xffff 656 | end 657 | 658 | -- SBC A,(IX+nn) 659 | opcodes[0x9e] = function (cpu) 660 | --logger.debug("SBC A,(IX+nn)") 661 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 662 | for i=1,5 do 663 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 664 | end 665 | SBC(cpu, read_mem_byte(cpu, cpu.IX + offset)) 666 | cpu.PC = (cpu.PC + 2) & 0xffff 667 | end 668 | 669 | -- AND IXh 670 | opcodes[0xa4] = function (cpu) 671 | --logger.debug("AND IXh") 672 | AND(cpu, (cpu.IX & 0xff00) >> 8) 673 | cpu.PC = (cpu.PC + 1) & 0xffff 674 | end 675 | 676 | -- AND IXl 677 | opcodes[0xa5] = function (cpu) 678 | --logger.debug("AND IXl") 679 | AND(cpu, cpu.IX & 0x00ff) 680 | cpu.PC = (cpu.PC + 1) & 0xffff 681 | end 682 | 683 | -- AND (IX+nn) 684 | opcodes[0xa6] = function (cpu) 685 | --logger.debug("AND (IX+nn)") 686 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 687 | for i=1,5 do 688 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 689 | end 690 | AND(cpu, read_mem_byte(cpu, cpu.IX + offset)) 691 | cpu.PC = (cpu.PC + 2) & 0xffff 692 | end 693 | 694 | -- XOR IXh 695 | opcodes[0xac] = function (cpu) 696 | --logger.debug("XOR IXh") 697 | XOR(cpu, (cpu.IX & 0xff00) >> 8) 698 | cpu.PC = (cpu.PC + 1) & 0xffff 699 | end 700 | 701 | -- XOR IXl 702 | opcodes[0xad] = function (cpu) 703 | --logger.debug("XOR IXl") 704 | XOR(cpu, cpu.IX & 0x00ff) 705 | cpu.PC = (cpu.PC + 1) & 0xffff 706 | end 707 | 708 | -- XOR (IX+nn) 709 | opcodes[0xae] = function (cpu) 710 | --logger.debug("XOR (IX+nn)") 711 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 712 | for i=1,5 do 713 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 714 | end 715 | XOR(cpu, read_mem_byte(cpu, cpu.IX + offset)) 716 | cpu.PC = (cpu.PC + 2) & 0xffff 717 | end 718 | 719 | -- OR IXh 720 | opcodes[0xb4] = function (cpu) 721 | --logger.debug("OR IXh") 722 | OR(cpu, (cpu.IX & 0xff00) >> 8) 723 | cpu.PC = (cpu.PC + 1) & 0xffff 724 | end 725 | 726 | -- OR IXl 727 | opcodes[0xb5] = function (cpu) 728 | --logger.debug("OR IXl") 729 | OR(cpu, cpu.IX & 0x00ff) 730 | cpu.PC = (cpu.PC + 1) & 0xffff 731 | end 732 | 733 | -- OR (IX+nn) 734 | opcodes[0xb6] = function (cpu) 735 | --logger.debug("OR (IX+nn)") 736 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 737 | for i=1,5 do 738 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 739 | end 740 | OR(cpu, read_mem_byte(cpu, cpu.IX + offset)) 741 | cpu.PC = (cpu.PC + 2) & 0xffff 742 | end 743 | 744 | -- CP IXh 745 | opcodes[0xbc] = function (cpu) 746 | --logger.debug("CP IXh") 747 | CP(cpu, (cpu.IX & 0xff00) >> 8) 748 | cpu.PC = (cpu.PC + 1) & 0xffff 749 | end 750 | 751 | -- CP IXl 752 | opcodes[0xbd] = function (cpu) 753 | --logger.debug("CP IXl") 754 | CP(cpu, cpu.IX & 0x00ff) 755 | cpu.PC = (cpu.PC + 1) & 0xffff 756 | end 757 | 758 | -- CP (IX+nn) 759 | opcodes[0xbe] = function (cpu) 760 | --logger.debug("CP (IX+nn)") 761 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 762 | for i=1,5 do 763 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 764 | end 765 | CP(cpu, read_mem_byte(cpu, cpu.IX + offset)) 766 | cpu.PC = (cpu.PC + 2) & 0xffff 767 | end 768 | 769 | -- 0xCB DDCB opcodes 770 | opcodes[0xcb] = function (cpu) 771 | --logger.warning("shifting DDCB") 772 | contend_read_no_mreq(cpu, cpu.PC + 1, 3) 773 | local offset = sign_extend( read_mem_byte_internal(cpu, cpu.PC + 1) ) 774 | contend_read_no_mreq(cpu, cpu.PC + 2, 3) 775 | local opcode = read_mem_byte_internal(cpu, cpu.PC + 2) 776 | contend_read_no_mreq(cpu, cpu.PC + 2, 1) 777 | contend_read_no_mreq(cpu, cpu.PC + 2, 1) 778 | local f = opcodes_ddcb[opcode] 779 | if not f then 780 | --logger.fatal("Opcode DDCB 0x%0x (%d) not found", opcode, opcode) 781 | error("") 782 | return 783 | end 784 | f(cpu, offset) 785 | cpu.PC = (cpu.PC + 3) & 0xffff 786 | end 787 | 788 | -- POP IX 789 | opcodes[0xe1] = function (cpu) 790 | --logger.debug("POP IX") 791 | local low = read_mem_byte(cpu, cpu.SP) 792 | local high = read_mem_byte(cpu, cpu.SP + 1) 793 | cpu.IX = low | (high << 8) 794 | cpu.SP = (cpu.SP + 2) & 0xffff 795 | cpu.PC = (cpu.PC + 1) & 0xffff 796 | end 797 | 798 | -- EX (SP),IX 799 | opcodes[0xe3] = function (cpu) 800 | --logger.debug("EX (SP),IX") 801 | local temp = cpu.IX 802 | cpu.IX = read_mem_word(cpu, cpu.SP) 803 | contend_read_no_mreq(cpu, cpu.SP + 1, 1) 804 | write_mem_byte(cpu, cpu.SP + 1, (temp & 0xff00) >> 8) 805 | write_mem_byte(cpu, cpu.SP, temp & 0xff) 806 | contend_write_no_mreq(cpu, cpu.SP, 1) 807 | contend_write_no_mreq(cpu, cpu.SP, 1) 808 | cpu.PC = (cpu.PC + 1) & 0xffff 809 | end 810 | 811 | -- PUSH IX 812 | opcodes[0xe5] = function (cpu) 813 | --logger.debug("PUSH IX") 814 | -- contend with IR register pair 815 | local I_high = cpu.I << 8 816 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 817 | 818 | cpu.SP = (cpu.SP - 2) & 0xffff 819 | write_mem_byte(cpu, cpu.SP + 1, (cpu.IX & 0xff00) >> 8) 820 | write_mem_byte(cpu, cpu.SP, cpu.IX & 0xff) 821 | cpu.PC = (cpu.PC + 1) & 0xffff 822 | end 823 | 824 | -- JP IX 825 | opcodes[0xe9] = function (cpu) 826 | --logger.debug("JP IX") 827 | cpu.PC = cpu.IX 828 | end 829 | 830 | -- LD SP,IX 831 | opcodes[0xf9] = function (cpu) 832 | --logger.debug("LD SP,IX") 833 | cpu.SP = cpu.IX 834 | -- contend with IR register pair 835 | local I_high = cpu.I << 8 836 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 837 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 838 | cpu.PC = (cpu.PC + 1) & 0xffff 839 | end 840 | 841 | 842 | return opcodes 843 | -------------------------------------------------------------------------------- /opcodes/ddcb.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- DDCBxx opcodes 3 | -- 4 | 5 | local logger = require "logger" 6 | local common_ops = require "opcodes.common" 7 | 8 | local BIT = common_ops.BIT 9 | local BIT_INDEX = common_ops.BIT_INDEX 10 | local RLC = common_ops.RLC 11 | local RRC = common_ops.RRC 12 | local RL = common_ops.RL 13 | local RR = common_ops.RR 14 | local SLA = common_ops.SLA 15 | local SLL = common_ops.SLL 16 | local SRA = common_ops.SRA 17 | local SRL = common_ops.SRL 18 | 19 | --- 20 | -- Will be bound to the actual functions to be called later in bind_io 21 | -- 22 | local contend_read_no_mreq 23 | local read_mem_byte 24 | local write_mem_byte 25 | 26 | local FLAG_S = 128 27 | local FLAG_Z = 64 28 | local FLAG_B5 = 32 29 | local FLAG_H = 16 30 | local FLAG_B3 = 8 31 | local FLAG_PV = 4 32 | local FLAG_N = 2 33 | local FLAG_C = 1 34 | 35 | local FLAG_N_OFF = 253 36 | local FLAG_PV_OFF = 251 37 | local FLAG_Z_OFF = 191 38 | local FLAG_H_OFF = 239 39 | local FLAG_S_OFF = 127 40 | local FLAG_C_OFF = 254 41 | 42 | 43 | local opcodes = {} 44 | 45 | function opcodes.bind_io (binds) 46 | contend_read_no_mreq = assert(binds.memory.contend_read_no_mreq) 47 | read_mem_byte = assert(binds.memory.read_mem_byte) 48 | write_mem_byte = assert(binds.memory.write_mem_byte) 49 | end 50 | 51 | -- "foo" is used to skip, for instance, RLC IX 52 | -- LD B,RLC (REGISTER+dd) 53 | local instructions = { RLC, RRC, RL, RR, SLA, SRA, SLL, SRL } 54 | local i = 0 55 | for _, instruction in ipairs(instructions) do 56 | local regs = {"B", "C", "D", "E", "H", "L", "foo", "A"} 57 | for _, reg in ipairs(regs) do 58 | opcodes[i] = function (cpu, offset) 59 | local address = cpu.IX + offset 60 | local byte = read_mem_byte(cpu, address) 61 | contend_read_no_mreq(cpu, address, 1) 62 | cpu[reg] = instruction(cpu, byte) 63 | write_mem_byte(cpu, address, cpu[reg]) 64 | end 65 | i = i + 1 66 | end 67 | end 68 | 69 | -- RLC IX 70 | opcodes[0x06] = function (cpu, offset) 71 | local address = cpu.IX + offset 72 | local byte = read_mem_byte(cpu, address) 73 | contend_read_no_mreq(cpu, address, 1) 74 | byte = RLC(cpu, byte) 75 | write_mem_byte(cpu, address, byte) 76 | end 77 | 78 | local base = 0x40 79 | for bit=0, 7 do 80 | for i=0,7 do--for i=0x40, 0x7f, 8 do 81 | opcodes[base + i] = function (cpu, offset) 82 | --logger.debug("BIT 0,IX+nn") 83 | local address = cpu.IX + offset 84 | local byte = read_mem_byte(cpu, address) 85 | contend_read_no_mreq(cpu, address, 1) 86 | BIT_INDEX(cpu, bit, byte, address) 87 | end 88 | end 89 | base = base + 8 90 | end 91 | 92 | -- LD B,RES 0,(IX+dd), etc 93 | local base = 0x80 94 | for b=0, 7 do 95 | local regs = {"B", "C", "D", "E", "H", "L", "foo", "A"} 96 | for i, reg in ipairs(regs) do 97 | local bit = 1 << b -- 2^bit 98 | bit = bit ~ 0xff -- invert 99 | if reg ~= "foo" then 100 | opcodes[base + i - 1] = function (cpu, offset) 101 | local address = cpu.IX + offset 102 | local byte = read_mem_byte(cpu, address) 103 | contend_read_no_mreq(cpu, address, 1) 104 | byte = byte & bit -- turn it off 105 | cpu[reg] = byte 106 | write_mem_byte(cpu, address, byte) 107 | end 108 | else 109 | opcodes[base + i - 1] = function (cpu, offset) 110 | local address = cpu.IX + offset 111 | local byte = read_mem_byte(cpu, address) 112 | contend_read_no_mreq(cpu, address, 1) 113 | byte = byte & bit -- turn it off 114 | write_mem_byte(cpu, address, byte) 115 | end 116 | end 117 | end 118 | base = base + 8 119 | end 120 | 121 | 122 | -- LD B,SET 0,(IX+dd), etc 123 | local base = 0xc0 124 | for b=0, 7 do 125 | local regs = {"B", "C", "D", "E", "H", "L", "foo", "A"} 126 | for i, reg in ipairs(regs) do 127 | local bit = 1 << b -- 2^bit 128 | if reg ~= "foo" then 129 | opcodes[base + i - 1] = function (cpu, offset) 130 | local address = cpu.IX + offset 131 | local byte = read_mem_byte(cpu, address) 132 | contend_read_no_mreq(cpu, address, 1) 133 | byte = byte | bit 134 | cpu[reg] = byte 135 | write_mem_byte(cpu, address, byte) 136 | end 137 | else 138 | opcodes[base + i - 1] = function (cpu, offset) 139 | local address = cpu.IX + offset 140 | local byte = read_mem_byte(cpu, address) 141 | contend_read_no_mreq(cpu, address, 1) 142 | byte = byte | bit 143 | write_mem_byte(cpu, address, byte) 144 | end 145 | end 146 | end 147 | base = base + 8 148 | end 149 | 150 | 151 | 152 | 153 | return opcodes 154 | -------------------------------------------------------------------------------- /opcodes/ed.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- EDxx opcodes 3 | -- 4 | 5 | local logger = require "logger" 6 | local common_ops = require "opcodes.common" 7 | 8 | --- 9 | -- Will be bound to the actual functions to be called later in bind_io 10 | -- 11 | local contend_write_no_mreq 12 | local contend_read_no_mreq 13 | local read_mem_word 14 | local write_mem_word 15 | local write_mem_byte 16 | local read_mem_byte 17 | local write_port 18 | local read_port 19 | 20 | local SUB = common_ops.SUB 21 | 22 | local overflow_add_table = common_ops.tables.overflow_add_table 23 | local overflow_sub_table = common_ops.tables.overflow_sub_table 24 | local halfcarry_add_table = common_ops.tables.halfcarry_add_table 25 | local halfcarry_sub_table = common_ops.tables.halfcarry_sub_table 26 | local sz53p_table = common_ops.tables.sz53p_table 27 | local sz53_table = common_ops.tables.sz53_table 28 | local parity_table = common_ops.tables.parity_table 29 | 30 | 31 | local FLAG_S = 128 32 | local FLAG_Z = 64 33 | local FLAG_B5 = 32 34 | local FLAG_H = 16 35 | local FLAG_B3 = 8 36 | local FLAG_PV = 4 37 | local FLAG_N = 2 38 | local FLAG_C = 1 39 | 40 | local FLAG_N_OFF = 253 41 | local FLAG_PV_OFF = 251 42 | local FLAG_Z_OFF = 191 43 | local FLAG_H_OFF = 239 44 | local FLAG_S_OFF = 127 45 | local FLAG_C_OFF = 254 46 | 47 | 48 | -- increments a 16 bit register 49 | local function increment_16 (high, low) 50 | local temp = ((low | (high << 8)) + 1) & 0xffff 51 | return temp >> 8, temp & 0xff 52 | end 53 | 54 | -- decrements a 16 bit register 55 | local function decrement_16 (high, low) 56 | local temp = ((low | (high << 8)) - 1) & 0xffff 57 | return temp >> 8, temp & 0xff 58 | end 59 | 60 | 61 | 62 | local function SBC_16 (cpu, value) 63 | local HL = cpu.L | cpu.H << 8 64 | local sub16temp = HL - value - (cpu.F & FLAG_C) 65 | local lookup = ( ( HL & 0x8800 ) >> 11 ) | 66 | ( ( value & 0x8800 ) >> 10 ) | 67 | ( ( sub16temp & 0x8800 ) >> 9 ) 68 | cpu.H = (sub16temp >> 8) & 0xff 69 | cpu.L = sub16temp & 0xff 70 | HL = cpu.L | cpu.H << 8 71 | cpu.F = ( (sub16temp & 0x10000 ~= 0) and FLAG_C or 0 ) | 72 | FLAG_N | 73 | overflow_sub_table[lookup >> 4] | 74 | ( cpu.H & ( FLAG_B3 | FLAG_B5 | FLAG_S ) ) | 75 | halfcarry_sub_table[lookup & 0x07] | 76 | ( HL ~= 0 and 0 or FLAG_Z) 77 | end 78 | 79 | local function ADC_16 (cpu, value) 80 | local HL = cpu.L | cpu.H << 8 81 | local add16temp = HL + value + (cpu.F & FLAG_C) 82 | local lookup = ( ( HL & 0x8800 ) >> 11 ) | 83 | ( ( value & 0x8800 ) >> 10 ) | 84 | ( ( add16temp & 0x8800 ) >> 9 ) 85 | cpu.H = (add16temp >> 8) & 0xff 86 | cpu.L = add16temp & 0xff 87 | HL = cpu.L | cpu.H << 8 88 | cpu.F = ( (add16temp & 0x10000 ~= 0) and FLAG_C or 0 ) | 89 | overflow_add_table[lookup >> 4] | 90 | ( cpu.H & ( FLAG_B3 | FLAG_B5 | FLAG_S ) ) | 91 | halfcarry_add_table[lookup & 0x07] | 92 | ( HL ~= 0 and 0 or FLAG_Z) 93 | end 94 | 95 | 96 | local function NEG (cpu) 97 | local byte = cpu.A 98 | cpu.A = 0 99 | SUB(cpu, byte) 100 | end 101 | 102 | 103 | 104 | local opcodes = {} 105 | 106 | function opcodes.bind_io (binds) 107 | contend_read_no_mreq = assert(binds.memory.contend_read_no_mreq) 108 | contend_write_no_mreq = assert(binds.memory.contend_write_no_mreq) 109 | read_mem_byte = assert(binds.memory.read_mem_byte) 110 | read_mem_word = assert(binds.memory.read_mem_word) 111 | write_mem_byte = assert(binds.memory.write_mem_byte) 112 | write_mem_word = assert(binds.memory.write_mem_word) 113 | 114 | write_port = assert(binds.ports.write_port) 115 | read_port = assert(binds.ports.read_port) 116 | end 117 | 118 | 119 | -- 0x40 IN B,(C) 120 | opcodes[0x40] = function (cpu) 121 | --logger.debug("IN B,C") 122 | local BC = cpu.C | cpu.B << 8 123 | cpu.B = assert(read_port(cpu, BC)) 124 | cpu.F = ( cpu.F & FLAG_C) | sz53p_table[cpu.B] 125 | cpu.PC = (cpu.PC + 1) & 0xffff 126 | end 127 | 128 | -- 0x41 OUT (C),B 129 | opcodes[0x41] = function (cpu) 130 | --logger.debug("OUT (C),B") 131 | write_port(cpu, cpu.C | cpu.B << 8, cpu.B) 132 | cpu.PC = (cpu.PC + 1) & 0xffff 133 | end 134 | 135 | -- 0x42 SBC HL,BC 136 | opcodes[0x42] = function (cpu) 137 | --logger.debug("SBC HL,BC") 138 | local IR = cpu.R | cpu.I << 8 139 | for i=1,7 do 140 | contend_read_no_mreq(cpu, IR, 1) 141 | end 142 | SBC_16(cpu, cpu.C | cpu.B << 8) 143 | cpu.PC = (cpu.PC + 1) & 0xffff 144 | end 145 | 146 | -- 0x43 LD (nnnn),BC 147 | opcodes[0x43] = function (cpu) 148 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 149 | --logger.debug("LD ($%04x),BC", address) 150 | write_mem_word(cpu, address, cpu.C | cpu.B << 8) 151 | cpu.PC = (cpu.PC + 3) & 0xffff 152 | end 153 | 154 | -- 0x44 NEG 155 | opcodes[0x44] = function (cpu) 156 | --logger.debug("NEG") 157 | NEG(cpu) 158 | cpu.PC = (cpu.PC + 1) & 0xffff 159 | end 160 | 161 | -- 0x45 RETN 162 | opcodes[0x45] = function (cpu) 163 | --logger.debug("RETN") 164 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 165 | cpu.SP = (cpu.SP + 2) & 0xffff 166 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 167 | end 168 | 169 | opcodes[0x46] = function (cpu) 170 | --logger.debug("IM 0") 171 | cpu.int_mode = 0 172 | cpu.PC = (cpu.PC + 1) & 0xffff 173 | end 174 | 175 | -- 0x47 LD I,A 176 | opcodes[0x47] = function (cpu) 177 | --logger.debug("LD I,A") 178 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1) 179 | cpu.I = cpu.A 180 | cpu.PC = (cpu.PC + 1) & 0xffff 181 | end 182 | 183 | opcodes[0x48] = function (cpu) 184 | --logger.debug("IN C,C") 185 | local BC = cpu.C | cpu.B << 8 186 | cpu.C = assert(read_port(cpu, BC)) 187 | cpu.F = ( cpu.F & FLAG_C) | sz53p_table[cpu.C] 188 | cpu.PC = (cpu.PC + 1) & 0xffff 189 | end 190 | 191 | opcodes[0x49] = function (cpu) 192 | --logger.debug("OUT (C),C") 193 | write_port(cpu, cpu.C | cpu.B << 8, cpu.C) 194 | cpu.PC = (cpu.PC + 1) & 0xffff 195 | end 196 | 197 | opcodes[0x4a] = function (cpu) 198 | --logger.debug("ADC HL,BC") 199 | local IR = cpu.R | cpu.I << 8 200 | for i=1,7 do 201 | contend_read_no_mreq(cpu, IR, 1) 202 | end 203 | ADC_16(cpu, cpu.C | cpu.B << 8) 204 | cpu.PC = (cpu.PC + 1) & 0xffff 205 | end 206 | 207 | -- LD BC,(nnnn) 208 | opcodes[0x4b] = function (cpu) 209 | --logger.debug("LD BC,(nnnn)") 210 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 211 | cpu.C = read_mem_byte(cpu, address) 212 | cpu.B = read_mem_byte(cpu, (address + 1) & 0xffff) 213 | cpu.PC = (cpu.PC + 3) & 0xffff 214 | end 215 | 216 | -- 0x4c NEG 217 | opcodes[0x4c] = function (cpu) 218 | --logger.debug("NEG") 219 | NEG(cpu) 220 | cpu.PC = (cpu.PC + 1) & 0xffff 221 | end 222 | 223 | opcodes[0x4d] = function (cpu) 224 | --logger.debug("RETI") -- igual que retn 225 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 226 | cpu.SP = (cpu.SP + 2) & 0xffff 227 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 228 | end 229 | 230 | -- IM 0 231 | opcodes[0x4e] = function (cpu) 232 | --logger.debug("IM 0") 233 | cpu.int_mode = 0 234 | cpu.PC = (cpu.PC + 1) & 0xffff 235 | end 236 | 237 | opcodes[0x4f] = function (cpu) 238 | --logger.debug("LD R,A") 239 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1) 240 | cpu.R = cpu.A 241 | cpu.PC = (cpu.PC + 1) & 0xffff 242 | end 243 | 244 | opcodes[0x50] = function (cpu) 245 | --logger.debug("IN D,C") 246 | local BC = cpu.C | cpu.B << 8 247 | cpu.D = assert(read_port(cpu, BC)) 248 | cpu.F = (cpu.F & FLAG_C) | sz53p_table[cpu.D] 249 | cpu.PC = (cpu.PC + 1) & 0xffff 250 | end 251 | 252 | opcodes[0x51] = function (cpu) 253 | --logger.debug("OUT (C),D") 254 | write_port(cpu, cpu.C | cpu.B << 8, cpu.D) 255 | cpu.PC = (cpu.PC + 1) & 0xffff 256 | end 257 | 258 | -- SBC HL,DE 259 | opcodes[0x52] = function (cpu) 260 | --logger.debug("SBC HL,DE") 261 | local IR = cpu.R | cpu.I << 8 262 | for i=1,7 do 263 | contend_read_no_mreq(cpu, IR, 1) 264 | end 265 | SBC_16(cpu, cpu.E | cpu.D << 8) 266 | cpu.PC = (cpu.PC + 1) & 0xffff 267 | end 268 | 269 | -- LD (nnnn),DE 270 | opcodes[0x53] = function (cpu) 271 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 272 | --logger.debug("LD ($%04x),DE", address) 273 | write_mem_word(cpu, address, cpu.E | cpu.D << 8) 274 | cpu.PC = (cpu.PC + 3) & 0xffff 275 | end 276 | 277 | -- 0x54 NEG 278 | opcodes[0x54] = function (cpu) 279 | --logger.debug("NEG") 280 | NEG(cpu) 281 | cpu.PC = (cpu.PC + 1) & 0xffff 282 | end 283 | 284 | -- 0x45 RETN 285 | opcodes[0x55] = function (cpu) 286 | --logger.debug("RETN") 287 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 288 | cpu.SP = (cpu.SP + 2) & 0xffff 289 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 290 | end 291 | 292 | -- IM 1 293 | opcodes[0x56] = function (cpu) 294 | --logger.debug("IM 1") 295 | cpu.int_mode = 1 296 | cpu.PC = (cpu.PC + 1) & 0xffff 297 | end 298 | 299 | opcodes[0x57] = function (cpu) 300 | --logger.debug("LD A,I") 301 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1) 302 | cpu.A = cpu.I 303 | cpu.F = ( cpu.F & FLAG_C ) | sz53_table[cpu.A] | ( cpu.iff2 ~= 0 and FLAG_PV or 0 ) 304 | cpu.PC = (cpu.PC + 1) & 0xffff 305 | end 306 | 307 | opcodes[0x58] = function (cpu) 308 | --logger.debug("IN E,C") 309 | local BC = cpu.C | cpu.B << 8 310 | cpu.E = assert(read_port(cpu, BC)) 311 | cpu.F = ( cpu.F & FLAG_C) | sz53p_table[cpu.E] 312 | cpu.PC = (cpu.PC + 1) & 0xffff 313 | end 314 | 315 | opcodes[0x59] = function (cpu) 316 | --logger.debug("OUT (C),E") 317 | write_port(cpu, cpu.C | cpu.B << 8, cpu.E) 318 | cpu.PC = (cpu.PC + 1) & 0xffff 319 | end 320 | 321 | opcodes[0x5a] = function (cpu) 322 | --logger.debug("ADC HL,DE") 323 | local IR = cpu.R | cpu.I << 8 324 | for i=1,7 do 325 | contend_read_no_mreq(cpu, IR, 1) 326 | end 327 | ADC_16(cpu, cpu.E | cpu.D << 8) 328 | cpu.PC = (cpu.PC + 1) & 0xffff 329 | end 330 | 331 | -- LD DE,(nnnn) 332 | opcodes[0x5b] = function (cpu) 333 | --logger.debug("LD DE,(nnnn)") 334 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 335 | cpu.E = read_mem_byte(cpu, address) 336 | cpu.D = read_mem_byte(cpu, (address + 1) & 0xffff) 337 | cpu.PC = (cpu.PC + 3) & 0xffff 338 | end 339 | 340 | -- 0x5c NEG 341 | opcodes[0x5c] = function (cpu) 342 | --logger.debug("NEG") 343 | NEG(cpu) 344 | cpu.PC = (cpu.PC + 1) & 0xffff 345 | end 346 | 347 | -- 0x5d RETN 348 | opcodes[0x5d] = function (cpu) 349 | --logger.debug("RETN") 350 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 351 | cpu.SP = (cpu.SP + 2) & 0xffff 352 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 353 | end 354 | 355 | opcodes[0x5e] = function (cpu) 356 | --logger.debug("IM 2") 357 | cpu.int_mode = 2 358 | cpu.PC = (cpu.PC + 1) & 0xffff 359 | end 360 | 361 | -- LD A,R 362 | opcodes[0x5f] = function (cpu) 363 | --logger.debug("LD A,R") 364 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1) 365 | cpu.A = cpu.R 366 | cpu.F = ( cpu.F & FLAG_C ) | sz53_table[cpu.A] | ( cpu.iff2 ~= 0 and FLAG_PV or 0 ) 367 | cpu.PC = (cpu.PC + 1) & 0xffff 368 | end 369 | 370 | opcodes[0x60] = function (cpu) 371 | --logger.debug("IN D,C") 372 | local BC = cpu.C | cpu.B << 8 373 | cpu.H = assert(read_port(cpu, BC)) 374 | cpu.F = (cpu.F & FLAG_C) | sz53p_table[cpu.H] 375 | cpu.PC = (cpu.PC + 1) & 0xffff 376 | end 377 | 378 | opcodes[0x61] = function (cpu) 379 | --logger.debug("OUT (C),H") 380 | write_port(cpu, cpu.C | cpu.B << 8, cpu.H) 381 | cpu.PC = (cpu.PC + 1) & 0xffff 382 | end 383 | 384 | opcodes[0x62] = function (cpu) 385 | --logger.debug("SBC HL,HL") 386 | local IR = cpu.R | cpu.I << 8 387 | for i=1,7 do 388 | contend_read_no_mreq(cpu, IR, 1) 389 | end 390 | SBC_16(cpu, cpu.L | cpu.H << 8) 391 | cpu.PC = (cpu.PC + 1) & 0xffff 392 | end 393 | 394 | -- LD (nnnn),HL 395 | opcodes[0x63] = function (cpu) 396 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 397 | --logger.debug("LD ($%04x),HL", address) 398 | write_mem_word(cpu, address, cpu.L | cpu.H << 8) 399 | cpu.PC = (cpu.PC + 3) & 0xffff 400 | end 401 | 402 | -- 0x64 NEG 403 | opcodes[0x64] = function (cpu) 404 | --logger.debug("NEG") 405 | NEG(cpu) 406 | cpu.PC = (cpu.PC + 1) & 0xffff 407 | end 408 | 409 | -- 0x65 RETN 410 | opcodes[0x65] = function (cpu) 411 | --logger.debug("RETN") 412 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 413 | cpu.SP = (cpu.SP + 2) & 0xffff 414 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 415 | end 416 | 417 | opcodes[0x66] = function (cpu) 418 | --logger.debug("IM 0") 419 | cpu.int_mode = 0 420 | cpu.PC = (cpu.PC + 1) & 0xffff 421 | end 422 | 423 | opcodes[0x67] = function (cpu) 424 | --logger.debug("RRD") 425 | local HL = cpu.L | cpu.H << 8 426 | local byte = read_mem_byte(cpu, HL) 427 | for i=1,4 do 428 | contend_read_no_mreq(cpu, HL, 1 ) 429 | end 430 | write_mem_byte(cpu, HL, ( ( cpu.A << 4 ) | ( byte >> 4 ) ) & 0xff ) 431 | cpu.A = ( cpu.A & 0xf0 ) | ( byte & 0x0f ) 432 | cpu.F = ( cpu.F & FLAG_C ) | sz53p_table[cpu.A] 433 | cpu.PC = (cpu.PC + 1) & 0xffff 434 | end 435 | 436 | opcodes[0x68] = function (cpu) 437 | --logger.debug("IN D,C") 438 | local BC = cpu.C | cpu.B << 8 439 | cpu.L = assert(read_port(cpu, BC)) 440 | cpu.F = ( cpu.F & FLAG_C) | sz53p_table[cpu.L] 441 | cpu.PC = (cpu.PC + 1) & 0xffff 442 | end 443 | 444 | opcodes[0x69] = function (cpu) 445 | --logger.debug("OUT (C),L") 446 | write_port(cpu, cpu.C | cpu.B << 8, cpu.L) 447 | cpu.PC = (cpu.PC + 1) & 0xffff 448 | end 449 | 450 | opcodes[0x6a] = function (cpu) 451 | --logger.debug("ADC HL,HL") 452 | local IR = cpu.R | cpu.I << 8 453 | for i=1,7 do 454 | contend_read_no_mreq(cpu, IR, 1) 455 | end 456 | ADC_16(cpu, cpu.L | cpu.H << 8) 457 | cpu.PC = (cpu.PC + 1) & 0xffff 458 | end 459 | 460 | opcodes[0x6b] = function (cpu) 461 | --logger.debug("LD HL,(nnnn)") 462 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 463 | cpu.L = read_mem_byte(cpu, address) 464 | cpu.H = read_mem_byte(cpu, (address + 1) & 0xffff) 465 | cpu.PC = (cpu.PC + 3) & 0xffff 466 | end 467 | 468 | -- 0x6c NEG 469 | opcodes[0x6c] = function (cpu) 470 | --logger.debug("NEG") 471 | NEG(cpu) 472 | cpu.PC = (cpu.PC + 1) & 0xffff 473 | end 474 | 475 | -- 0x6d RETN 476 | opcodes[0x6d] = function (cpu) 477 | --logger.debug("RETN") 478 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 479 | cpu.SP = (cpu.SP + 2) & 0xffff 480 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 481 | end 482 | 483 | opcodes[0x6e] = function (cpu) 484 | --logger.debug("IM 0") 485 | cpu.int_mode = 0 486 | cpu.PC = (cpu.PC + 1) & 0xffff 487 | end 488 | 489 | opcodes[0x6f] = function (cpu) 490 | --logger.debug("RLD") 491 | local HL = cpu.L | cpu.H << 8 492 | local byte = read_mem_byte(cpu, HL) 493 | for i=1,4 do 494 | contend_read_no_mreq(cpu, HL, 1 ) 495 | end 496 | write_mem_byte(cpu, HL, ( (byte << 4 ) | ( cpu.A & 0x0f ) ) & 0xff ) 497 | cpu.A = ( cpu.A & 0xf0 ) | ( byte >> 4 ) 498 | cpu.F = ( cpu.F & FLAG_C ) | sz53p_table[cpu.A] 499 | cpu.PC = (cpu.PC + 1) & 0xffff 500 | end 501 | 502 | opcodes[0x70] = function (cpu) 503 | --logger.debug("IN F,C") 504 | local BC = cpu.C | cpu.B << 8 505 | assert(read_port(cpu, BC)) 506 | cpu.F = ( cpu.F & FLAG_C) | sz53p_table[cpu.B] 507 | cpu.PC = (cpu.PC + 1) & 0xffff 508 | end 509 | 510 | opcodes[0x71] = function (cpu) 511 | --logger.debug("OUT C,0") 512 | write_port(cpu, cpu.C | cpu.B << 8, 0) 513 | cpu.PC = (cpu.PC + 1) & 0xffff 514 | end 515 | 516 | opcodes[0x72] = function (cpu) 517 | --logger.debug("SBC HL, SP") 518 | local IR = cpu.R | cpu.I << 8 519 | for i=1,7 do 520 | contend_read_no_mreq(cpu, IR, 1) 521 | end 522 | SBC_16(cpu, cpu.SP) 523 | cpu.PC = (cpu.PC + 1) & 0xffff 524 | end 525 | 526 | -- LD (nnnn),SP 527 | opcodes[0x73] = function (cpu) 528 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 529 | --logger.debug("LD ($%04x),SP", address) 530 | write_mem_word(cpu, address, cpu.SP) 531 | cpu.PC = (cpu.PC + 3) & 0xffff 532 | end 533 | 534 | -- 0x74 NEG 535 | opcodes[0x74] = function (cpu) 536 | --logger.debug("NEG") 537 | NEG(cpu) 538 | cpu.PC = (cpu.PC + 1) & 0xffff 539 | end 540 | 541 | -- 0x75 RETN 542 | opcodes[0x75] = function (cpu) 543 | --logger.debug("RETN") 544 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 545 | cpu.SP = (cpu.SP + 2) & 0xffff 546 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 547 | end 548 | 549 | -- IM 1 550 | opcodes[0x76] = function (cpu) 551 | --logger.debug("IM 1") 552 | cpu.int_mode = 1 553 | cpu.PC = (cpu.PC + 1) & 0xffff 554 | end 555 | 556 | -- IN A,C 557 | opcodes[0x78] = function (cpu) 558 | --logger.debug("IN A,C") 559 | local BC = cpu.C | cpu.B << 8 560 | cpu.A = assert(read_port(cpu, BC)) 561 | cpu.F = ( cpu.F & FLAG_C) | sz53p_table[cpu.A] 562 | cpu.PC = (cpu.PC + 1) & 0xffff 563 | end 564 | 565 | opcodes[0x79] = function (cpu) 566 | --logger.debug("OUT (C),A") 567 | write_port(cpu, cpu.C | cpu.B << 8, cpu.A) 568 | cpu.PC = (cpu.PC + 1) & 0xffff 569 | end 570 | 571 | opcodes[0x7a] = function (cpu) 572 | --logger.debug("ADC HL,SP") 573 | local IR = cpu.R | cpu.I << 8 574 | for i=1,7 do 575 | contend_read_no_mreq(cpu, IR, 1) 576 | end 577 | ADC_16(cpu, cpu.SP) 578 | cpu.PC = (cpu.PC + 1) & 0xffff 579 | end 580 | 581 | opcodes[0x7b] = function (cpu) 582 | --logger.debug("LD SP,(nnnn)") 583 | local address = read_mem_word(cpu, (cpu.PC + 1) & 0xffff) 584 | cpu.SP = read_mem_byte(cpu, address) | read_mem_byte(cpu, (address + 1) & 0xffff) << 8 585 | cpu.PC = (cpu.PC + 3) & 0xffff 586 | end 587 | 588 | -- 0x7c NEG 589 | opcodes[0x7c] = function (cpu) 590 | --logger.debug("NEG") 591 | NEG(cpu) 592 | cpu.PC = (cpu.PC + 1) & 0xffff 593 | end 594 | 595 | -- 0x7d RETN 596 | opcodes[0x7d] = function (cpu) 597 | --logger.debug("RETN") 598 | cpu.PC = read_mem_byte(cpu, cpu.SP) | read_mem_byte(cpu, (cpu.SP + 1) & 0xffff) << 8 599 | cpu.SP = (cpu.SP + 2) & 0xffff 600 | cpu.iff1 = cpu.iff2 -- activa de nuevo las NMI 601 | end 602 | 603 | opcodes[0x7e] = function (cpu) 604 | --logger.debug("IM 2") 605 | cpu.int_mode = 2 606 | cpu.PC = (cpu.PC + 1) & 0xffff 607 | end 608 | 609 | opcodes[0xa0] = function (cpu) 610 | --logger.debug("LDI") 611 | 612 | local byte = read_mem_byte(cpu, cpu.L | cpu.H << 8) 613 | local DE = cpu.E | cpu.D << 8 614 | write_mem_byte(cpu, DE, byte) 615 | contend_write_no_mreq(cpu, DE, 1) 616 | contend_write_no_mreq(cpu, DE, 1) 617 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 618 | local BC = cpu.C | cpu.B << 8 619 | byte = (byte + cpu.A) & 0xff 620 | 621 | cpu.F = ( cpu.F & ( FLAG_C | FLAG_Z | FLAG_S ) ) | ( BC ~= 0 and FLAG_PV or 0 ) | 622 | ( byte & FLAG_B3 ) | ( (byte & 0x02 ~= 0) and FLAG_B5 or 0 ) 623 | 624 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 625 | cpu.D, cpu.E = increment_16(cpu.D, cpu.E) 626 | 627 | cpu.PC = (cpu.PC + 1) & 0xffff 628 | end 629 | 630 | -- CPI 631 | opcodes[0xa1] = function (cpu) 632 | --logger.debug("CPI") 633 | local HL = cpu.L | cpu.H << 8 634 | local value = read_mem_byte(cpu, HL) 635 | local bytetemp = cpu.A - value 636 | local lookup = ( ( cpu.A & 0x08 ) >> 3 ) | 637 | ( ( value & 0x08 ) >> 2 ) | 638 | ( ( bytetemp & 0x08 ) >> 1 ) 639 | for i=1,5 do 640 | contend_read_no_mreq(cpu, HL, 1) 641 | end 642 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 643 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 644 | 645 | local BC = cpu.C | cpu.B << 8 646 | cpu.F = ( cpu.F & FLAG_C ) | 647 | ( BC ~= 0 and ( FLAG_PV | FLAG_N ) or FLAG_N ) | 648 | halfcarry_sub_table[lookup] | 649 | ( bytetemp ~= 0 and 0 or FLAG_Z ) | 650 | ( bytetemp & FLAG_S ) 651 | 652 | if cpu.F & FLAG_H ~= 0 then 653 | bytetemp = (bytetemp - 1) & 0xff 654 | end 655 | cpu.F = cpu.F | 656 | ( bytetemp & FLAG_B3 ) | 657 | ( bytetemp & 0x02 ~= 0 and FLAG_B5 or 0 ) 658 | 659 | cpu.PC = (cpu.PC + 1) & 0xffff 660 | end 661 | 662 | -- INI 663 | opcodes[0xa2] = function (cpu) 664 | --logger.debug("INI") 665 | 666 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 667 | local initemp = read_port(cpu, cpu.C | cpu.B << 8) 668 | write_mem_byte(cpu, cpu.L | cpu.H << 8, initemp) 669 | 670 | cpu.B = (cpu.B - 1) & 0xff 671 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 672 | local initemp2 = (initemp + cpu.C + 1) & 0xff 673 | cpu.F = ( initemp & 0x80 ~= 0 and FLAG_N or 0 ) | 674 | ( initemp2 < initemp and (FLAG_H | FLAG_C) or 0 ) | 675 | ( parity_table[ initemp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 676 | sz53_table[cpu.B] 677 | cpu.PC = (cpu.PC + 1) & 0xffff 678 | end 679 | 680 | -- OUTI 681 | opcodes[0xa3] = function (cpu) 682 | --logger.debug("OUTI") 683 | 684 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 685 | local temp = read_mem_byte(cpu, cpu.L | cpu.H << 8) 686 | cpu.B = (cpu.B - 1) & 0xff 687 | write_port(cpu, cpu.C | cpu.B << 8, temp) 688 | 689 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 690 | local temp2 = (temp + cpu.L) & 0xff 691 | cpu.F = ( temp & 0x80 ~= 0 and FLAG_N or 0 ) | 692 | ( temp2 < temp and (FLAG_H | FLAG_C) or 0 ) | 693 | ( parity_table[ temp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 694 | sz53_table[cpu.B] 695 | cpu.PC = (cpu.PC + 1) & 0xffff 696 | end 697 | 698 | -- LDD 699 | opcodes[0xa8] = function (cpu) 700 | --logger.debug("LDD") 701 | local byte = read_mem_byte(cpu, cpu.L | cpu.H << 8) 702 | local DE = cpu.E | cpu.D << 8 703 | write_mem_byte(cpu, DE, byte) 704 | contend_write_no_mreq(cpu, DE, 1) 705 | contend_write_no_mreq(cpu, DE, 1) 706 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 707 | local BC = cpu.C | cpu.B << 8 708 | byte = (byte + cpu.A) & 0xff 709 | 710 | cpu.F = ( cpu.F & ( FLAG_C | FLAG_Z | FLAG_S ) ) | ( BC ~= 0 and FLAG_PV or 0 ) | 711 | ( byte & FLAG_B3 ) | ( (byte & 0x02 ~= 0) and FLAG_B5 or 0 ) 712 | 713 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 714 | cpu.D, cpu.E = decrement_16(cpu.D, cpu.E) 715 | 716 | cpu.PC = (cpu.PC + 1) & 0xffff 717 | end 718 | 719 | -- CPD 720 | opcodes[0xa9] = function (cpu) 721 | --logger.debug("CPD") 722 | local HL = cpu.L | cpu.H << 8 723 | local value = read_mem_byte(cpu, HL) 724 | local bytetemp = cpu.A - value 725 | local lookup = ( ( cpu.A & 0x08 ) >> 3 ) | 726 | ( ( value & 0x08 ) >> 2 ) | 727 | ( ( bytetemp & 0x08 ) >> 1 ) 728 | for i=1,5 do 729 | contend_read_no_mreq(cpu, HL, 1) 730 | end 731 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 732 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 733 | 734 | local BC = cpu.C | cpu.B << 8 735 | cpu.F = ( cpu.F & FLAG_C ) | 736 | ( BC ~= 0 and ( FLAG_PV | FLAG_N ) or FLAG_N ) | 737 | halfcarry_sub_table[lookup] | 738 | ( bytetemp ~= 0 and 0 or FLAG_Z ) | 739 | ( bytetemp & FLAG_S ) 740 | 741 | if cpu.F & FLAG_H ~= 0 then 742 | bytetemp = (bytetemp - 1) & 0xff 743 | end 744 | cpu.F = cpu.F | 745 | ( bytetemp & FLAG_B3 ) | 746 | ( bytetemp & 0x02 ~= 0 and FLAG_B5 or 0 ) 747 | 748 | cpu.PC = (cpu.PC + 1) & 0xffff 749 | end 750 | 751 | -- IND 752 | opcodes[0xaa] = function (cpu) 753 | --logger.debug("IND") 754 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 755 | local initemp = read_port(cpu, cpu.C | cpu.B << 8) 756 | write_mem_byte(cpu, cpu.L | cpu.H << 8, initemp) 757 | 758 | cpu.B = (cpu.B - 1) & 0xff 759 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 760 | local initemp2 = (initemp + cpu.C - 1) & 0xff 761 | cpu.F = ( initemp & 0x80 ~= 0 and FLAG_N or 0 ) | 762 | ( initemp2 < initemp and (FLAG_H | FLAG_C) or 0 ) | 763 | ( parity_table[ initemp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 764 | sz53_table[cpu.B] 765 | cpu.PC = (cpu.PC + 1) & 0xffff 766 | end 767 | 768 | -- OUTD 769 | opcodes[0xab] = function (cpu) 770 | --logger.debug("OUTD") 771 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 772 | local temp = read_mem_byte(cpu, cpu.L | cpu.H << 8) 773 | cpu.B = (cpu.B - 1) & 0xff 774 | write_port(cpu, cpu.C | cpu.B << 8, temp) 775 | 776 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 777 | local temp2 = (temp + cpu.L) & 0xff 778 | cpu.F = ( temp & 0x80 ~= 0 and FLAG_N or 0 ) | 779 | ( temp2 < temp and (FLAG_H | FLAG_C) or 0 ) | 780 | ( parity_table[ temp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 781 | sz53_table[cpu.B] 782 | cpu.PC = (cpu.PC + 1) & 0xffff 783 | end 784 | 785 | -- LDIR 786 | opcodes[0xb0] = function (cpu) 787 | --logger.debug("LDIR") 788 | local byte = read_mem_byte(cpu, cpu.L | cpu.H << 8) 789 | local DE = cpu.E | cpu.D << 8 790 | write_mem_byte(cpu, DE, byte) 791 | contend_write_no_mreq(cpu, DE, 1) 792 | contend_write_no_mreq(cpu, DE, 1) 793 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 794 | local BC = cpu.C | cpu.B << 8 795 | byte = (byte + cpu.A) & 0xff 796 | 797 | cpu.F = ( cpu.F & ( FLAG_C | FLAG_Z | FLAG_S ) ) | ( BC ~= 0 and FLAG_PV or 0 ) | 798 | ( byte & FLAG_B3 ) | ( (byte & 0x02 ~= 0) and FLAG_B5 or 0 ) 799 | if BC ~= 0 then 800 | for i = 1, 5 do 801 | contend_write_no_mreq(cpu, DE, 1) 802 | end 803 | cpu.PC = (cpu.PC - 2) & 0xffff 804 | end 805 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 806 | cpu.D, cpu.E = increment_16(cpu.D, cpu.E) 807 | 808 | cpu.PC = (cpu.PC + 1) & 0xffff 809 | end 810 | 811 | -- CPIR 812 | opcodes[0xb1] = function (cpu) 813 | --logger.debug("CPIR") 814 | local HL = cpu.L | cpu.H << 8 815 | local value = read_mem_byte(cpu, HL) 816 | local bytetemp = cpu.A - value 817 | local lookup = ( ( cpu.A & 0x08 ) >> 3 ) | 818 | ( ( value & 0x08 ) >> 2 ) | 819 | ( ( bytetemp & 0x08 ) >> 1 ) 820 | for i=1,5 do 821 | contend_read_no_mreq(cpu, HL, 1) 822 | end 823 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 824 | 825 | local BC = cpu.C | cpu.B << 8 826 | cpu.F = ( cpu.F & FLAG_C ) | 827 | ( BC ~= 0 and ( FLAG_PV | FLAG_N ) or FLAG_N ) | 828 | halfcarry_sub_table[lookup] | 829 | ( bytetemp ~= 0 and 0 or FLAG_Z ) | 830 | ( bytetemp & FLAG_S ) 831 | 832 | if cpu.F & FLAG_H ~= 0 then 833 | bytetemp = (bytetemp - 1) & 0xff 834 | end 835 | cpu.F = cpu.F | 836 | ( bytetemp & FLAG_B3 ) | 837 | ( bytetemp & 0x02 ~= 0 and FLAG_B5 or 0 ) 838 | if cpu.F & ( FLAG_PV | FLAG_Z ) == FLAG_PV then 839 | local HL = cpu.L | cpu.H << 8 840 | for i = 1, 5 do 841 | contend_write_no_mreq(cpu, HL, 1) 842 | end 843 | cpu.PC = (cpu.PC - 2) & 0xffff 844 | end 845 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 846 | cpu.PC = (cpu.PC + 1) & 0xffff 847 | end 848 | 849 | -- INIR 850 | opcodes[0xb2] = function (cpu) 851 | --logger.debug("INIR") 852 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 853 | local initemp = read_port(cpu, cpu.C | cpu.B << 8) 854 | write_mem_byte(cpu, cpu.L | cpu.H << 8, initemp) 855 | 856 | cpu.B = (cpu.B - 1) & 0xff 857 | local initemp2 = (initemp + cpu.C + 1) & 0xff 858 | cpu.F = ( initemp & 0x80 ~= 0 and FLAG_N or 0 ) | 859 | ( initemp2 < initemp and (FLAG_H | FLAG_C) or 0 ) | 860 | ( parity_table[ initemp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 861 | sz53_table[cpu.B] 862 | 863 | if cpu.B ~= 0 then 864 | local HL = cpu.L | cpu.H << 8 865 | for i = 1, 5 do 866 | contend_write_no_mreq(cpu, HL, 1) 867 | end 868 | cpu.PC = (cpu.PC - 2) & 0xffff 869 | end 870 | 871 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 872 | cpu.PC = (cpu.PC + 1) & 0xffff 873 | end 874 | 875 | -- OTIR 876 | opcodes[0xb3] = function (cpu) 877 | --logger.debug("OTIR") 878 | 879 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 880 | local temp = read_mem_byte(cpu, cpu.L | cpu.H << 8) 881 | cpu.B = (cpu.B - 1) & 0xff 882 | write_port(cpu, cpu.C | cpu.B << 8, temp) 883 | 884 | cpu.H, cpu.L = increment_16(cpu.H, cpu.L) 885 | local temp2 = (temp + cpu.L) & 0xff 886 | cpu.F = ( temp & 0x80 ~= 0 and FLAG_N or 0 ) | 887 | ( temp2 < temp and (FLAG_H | FLAG_C) or 0 ) | 888 | ( parity_table[ temp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 889 | sz53_table[cpu.B] 890 | 891 | if cpu.B ~= 0 then 892 | local BC = cpu.C | cpu.B << 8 893 | for i = 1, 5 do 894 | contend_write_no_mreq(cpu, BC, 1) 895 | end 896 | cpu.PC = (cpu.PC - 2) & 0xffff 897 | end 898 | cpu.PC = (cpu.PC + 1) & 0xffff 899 | end 900 | 901 | -- LDDR 902 | opcodes[0xb8] = function (cpu) 903 | --logger.debug("LDDR") 904 | local byte = read_mem_byte(cpu, cpu.L | cpu.H << 8) 905 | local DE = cpu.E | cpu.D << 8 906 | write_mem_byte(cpu, DE, byte) 907 | contend_write_no_mreq(cpu, DE, 1) 908 | contend_write_no_mreq(cpu, DE, 1) 909 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 910 | local BC = cpu.C | cpu.B << 8 911 | byte = (byte + cpu.A) & 0xff 912 | 913 | cpu.F = ( cpu.F & ( FLAG_C | FLAG_Z | FLAG_S ) ) | ( BC ~= 0 and FLAG_PV or 0 ) | 914 | ( byte & FLAG_B3 ) | ( (byte & 0x02 ~= 0) and FLAG_B5 or 0 ) 915 | if BC ~= 0 then 916 | for i = 1, 5 do 917 | contend_write_no_mreq(cpu, DE, 1) 918 | end 919 | cpu.PC = (cpu.PC - 2) & 0xffff 920 | end 921 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 922 | cpu.D, cpu.E = decrement_16(cpu.D, cpu.E) 923 | 924 | cpu.PC = (cpu.PC + 1) & 0xffff 925 | end 926 | 927 | -- CPDR 928 | opcodes[0xb9] = function (cpu) 929 | --logger.debug("CPDR") 930 | local HL = cpu.L | cpu.H << 8 931 | local value = read_mem_byte(cpu, HL) 932 | local bytetemp = cpu.A - value 933 | local lookup = ( ( cpu.A & 0x08 ) >> 3 ) | 934 | ( ( value & 0x08 ) >> 2 ) | 935 | ( ( bytetemp & 0x08 ) >> 1 ) 936 | for i=1,5 do 937 | contend_read_no_mreq(cpu, HL, 1) 938 | end 939 | cpu.B, cpu.C = decrement_16(cpu.B, cpu.C) 940 | 941 | local BC = cpu.C | cpu.B << 8 942 | cpu.F = ( cpu.F & FLAG_C ) | 943 | ( BC ~= 0 and ( FLAG_PV | FLAG_N ) or FLAG_N ) | 944 | halfcarry_sub_table[lookup] | 945 | ( bytetemp ~= 0 and 0 or FLAG_Z ) | 946 | ( bytetemp & FLAG_S ) 947 | 948 | if cpu.F & FLAG_H ~= 0 then 949 | bytetemp = (bytetemp - 1) & 0xff 950 | end 951 | cpu.F = cpu.F | 952 | ( bytetemp & FLAG_B3 ) | 953 | ( bytetemp & 0x02 ~= 0 and FLAG_B5 or 0 ) 954 | if cpu.F & ( FLAG_PV | FLAG_Z ) == FLAG_PV then 955 | local HL = cpu.L | cpu.H << 8 956 | for i = 1, 5 do 957 | contend_write_no_mreq(cpu, HL, 1) 958 | end 959 | cpu.PC = (cpu.PC - 2) & 0xffff 960 | end 961 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 962 | cpu.PC = (cpu.PC + 1) & 0xffff 963 | end 964 | 965 | -- INDR 966 | opcodes[0xba] = function (cpu) 967 | --logger.debug("INDR") 968 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 969 | local initemp = read_port(cpu, cpu.C | cpu.B << 8) 970 | write_mem_byte(cpu, cpu.L | cpu.H << 8, initemp) 971 | 972 | cpu.B = (cpu.B - 1) & 0xff 973 | local initemp2 = (initemp + cpu.C + 1) & 0xff 974 | cpu.F = ( initemp & 0x80 ~= 0 and FLAG_N or 0 ) | 975 | ( initemp2 < initemp and (FLAG_H | FLAG_C) or 0 ) | 976 | ( parity_table[ initemp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 977 | sz53_table[cpu.B] 978 | 979 | if cpu.B ~= 0 then 980 | local HL = cpu.L | cpu.H << 8 981 | for i = 1, 5 do 982 | contend_write_no_mreq(cpu, HL, 1) 983 | end 984 | cpu.PC = (cpu.PC - 2) & 0xffff 985 | end 986 | 987 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 988 | cpu.PC = (cpu.PC + 1) & 0xffff 989 | end 990 | 991 | -- OTDR 992 | opcodes[0xbb] = function (cpu) 993 | --logger.debug("OTDR") 994 | contend_read_no_mreq(cpu, cpu.R | cpu.I << 8, 1 ) 995 | local temp = read_mem_byte(cpu, cpu.L | cpu.H << 8) 996 | cpu.B = (cpu.B - 1) & 0xff 997 | write_port(cpu, cpu.C | cpu.B << 8, temp) 998 | 999 | cpu.H, cpu.L = decrement_16(cpu.H, cpu.L) 1000 | local temp2 = (temp + cpu.L) & 0xff 1001 | cpu.F = ( temp & 0x80 ~= 0 and FLAG_N or 0 ) | 1002 | ( temp2 < temp and (FLAG_H | FLAG_C) or 0 ) | 1003 | ( parity_table[ temp2 & 0x07 ~ cpu.B ] ~= 0 and FLAG_PV or 0 ) | 1004 | sz53_table[cpu.B] 1005 | 1006 | if cpu.B ~= 0 then 1007 | local BC = cpu.C | cpu.B << 8 1008 | for i = 1, 5 do 1009 | contend_write_no_mreq(cpu, BC, 1) 1010 | end 1011 | cpu.PC = (cpu.PC - 2) & 0xffff 1012 | end 1013 | cpu.PC = (cpu.PC + 1) & 0xffff 1014 | end 1015 | 1016 | return opcodes 1017 | -------------------------------------------------------------------------------- /opcodes/fd.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- FDxx opcodes 3 | -- 4 | 5 | local logger = require "logger" 6 | local common_ops = require "opcodes.common" 7 | 8 | --- 9 | -- Will be bound to the actual functions to be called later in bind_io 10 | -- 11 | local contend_read_no_mreq 12 | local contend_write_no_mreq 13 | local read_mem_byte 14 | local read_mem_byte_internal 15 | local read_mem_word 16 | local write_mem_byte 17 | local write_mem_word 18 | 19 | local function sign_extend (v) 20 | return v < 128 and v or v - 256 21 | end 22 | 23 | local function high_low (value) 24 | return (value & 0xff00) >> 8, value & 0x00ff 25 | end 26 | 27 | local ADD_16 = common_ops.ADD_16 28 | local ADD_8 = common_ops.ADD_8 29 | local AND = common_ops.AND 30 | local XOR = common_ops.XOR 31 | local OR = common_ops.OR 32 | local CP = common_ops.CP 33 | local SBC = common_ops.SBC 34 | local SUB = common_ops.SUB 35 | local ADC_8 = common_ops.ADC_8 36 | local INC = common_ops.INC 37 | local DEC = common_ops.DEC 38 | 39 | local opcodes_fdcb = require "opcodes.fdcb" 40 | 41 | local FLAG_S = 128 42 | local FLAG_Z = 64 43 | local FLAG_B5 = 32 44 | local FLAG_H = 16 45 | local FLAG_B3 = 8 46 | local FLAG_PV = 4 47 | local FLAG_N = 2 48 | local FLAG_C = 1 49 | 50 | local FLAG_N_OFF = 253 51 | local FLAG_PV_OFF = 251 52 | local FLAG_Z_OFF = 191 53 | local FLAG_H_OFF = 239 54 | local FLAG_S_OFF = 127 55 | local FLAG_C_OFF = 254 56 | 57 | local opcodes = {} 58 | 59 | function opcodes.bind_io (binds) 60 | contend_read_no_mreq = assert(binds.memory.contend_read_no_mreq) 61 | contend_write_no_mreq = assert(binds.memory.contend_write_no_mreq) 62 | read_mem_byte = assert(binds.memory.read_mem_byte) 63 | read_mem_byte_internal = assert(binds.memory.read_mem_byte_internal) 64 | read_mem_word = assert(binds.memory.read_mem_word) 65 | write_mem_byte = assert(binds.memory.write_mem_byte) 66 | write_mem_word = assert(binds.memory.write_mem_word) 67 | 68 | opcodes_fdcb.bind_io(binds) 69 | end 70 | -- TODO ESTO y FCCB.lua se duplican para IX e IY 71 | 72 | -- ADD IY,BC 73 | opcodes[0x09] = function (cpu) 74 | --logger.debug("ADD IY,BC") 75 | cpu.IY = ADD_16(cpu, cpu.IY, cpu.C | cpu.B << 8) 76 | cpu.PC = (cpu.PC + 1) & 0xffff 77 | end 78 | 79 | -- ADD IY,DE 80 | opcodes[0x19] = function (cpu) 81 | --logger.debug("ADD IY,DE") 82 | cpu.IY = ADD_16(cpu, cpu.IY, cpu.E | cpu.D << 8) 83 | cpu.PC = (cpu.PC + 1) & 0xffff 84 | end 85 | 86 | -- LD IY,nnnn 87 | opcodes[0x21] = function (cpu) 88 | local word = read_mem_word(cpu, cpu.PC + 1) 89 | --logger.debug("LD IY,$%04x", word) 90 | cpu.IY = word 91 | cpu.PC = (cpu.PC + 3) & 0xffff 92 | end 93 | 94 | -- LD (nnnn),IY 95 | opcodes[0x22] = function (cpu) 96 | local address = read_mem_word(cpu, cpu.PC + 1) 97 | --logger.debug("LD ($%04x),IY", address) 98 | write_mem_word(cpu, address, cpu.IY) 99 | cpu.PC = (cpu.PC + 3) & 0xffff 100 | end 101 | 102 | -- INC IY 103 | opcodes[0x23] = function (cpu) 104 | --logger.debug("INC IY") 105 | cpu.IY = (cpu.IY + 1) & 0xffff 106 | -- contend with IR register pair 107 | local I_high = cpu.I << 8 108 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 109 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 110 | cpu.PC = (cpu.PC + 1) & 0xffff 111 | end 112 | 113 | -- INC IYh 114 | opcodes[0x24] = function (cpu) 115 | --logger.debug("INC IYh") 116 | -- TODO: faltan los tstates 117 | local IYh, IYl = high_low(cpu.IY) 118 | IYh = INC(cpu, IYh) 119 | cpu.IY = IYl | IYh << 8 120 | cpu.PC = (cpu.PC + 1) & 0xffff 121 | end 122 | 123 | -- DEC 124 | opcodes[0x25] = function (cpu) 125 | --logger.debug("DEC IYh") 126 | local IYh, IYl = high_low(cpu.IY) 127 | IYh = DEC(cpu, IYh) 128 | cpu.IY = IYl | IYh << 8 129 | cpu.PC = (cpu.PC + 1) & 0xffff 130 | end 131 | 132 | -- LD IYh,nn 133 | opcodes[0x26] = function (cpu) 134 | --logger.debug("LD IYh,nn") 135 | local byte = read_mem_byte(cpu, cpu.PC + 1) 136 | cpu.IY = (byte << 8) | (cpu.IY & 0xff) 137 | cpu.PC = (cpu.PC + 2) & 0xffff 138 | end 139 | 140 | -- ADD IY,IY 141 | opcodes[0x29] = function (cpu) 142 | --logger.debug("ADD IY,IY") 143 | cpu.IY = ADD_16(cpu, cpu.IY, cpu.IY) 144 | cpu.PC = (cpu.PC + 1) & 0xffff 145 | end 146 | 147 | -- LD IY,(nnnn) 148 | opcodes[0x2a] = function (cpu) 149 | local address = read_mem_word(cpu, cpu.PC + 1) 150 | --logger.debug("LD IY,($%04x)", address) 151 | cpu.IY = read_mem_word(cpu, address) 152 | cpu.PC = (cpu.PC + 3) & 0xffff 153 | end 154 | 155 | -- DEC IY 156 | opcodes[0x2b] = function (cpu) 157 | --logger.debug("DEC IY") 158 | cpu.IY = (cpu.IY - 1) & 0xffff 159 | -- contend with IR register pair 160 | local I_high = cpu.I << 8 161 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 162 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 163 | cpu.PC = (cpu.PC + 1) & 0xffff 164 | end 165 | 166 | -- INC IYl 167 | opcodes[0x2c] = function (cpu) 168 | --logger.debug("INC IYl") 169 | -- TODO: faltan los tstates 170 | local IYh, IYl = high_low(cpu.IY) 171 | IYl = INC(cpu, IYl) 172 | cpu.IY = IYl | IYh << 8 173 | cpu.PC = (cpu.PC + 1) & 0xffff 174 | end 175 | 176 | -- DEC IYl 177 | opcodes[0x2d] = function (cpu) 178 | --logger.debug("DEC IYl") 179 | local IYh, IYl = high_low(cpu.IY) 180 | IYl = DEC(cpu, IYl) 181 | cpu.IY = IYl | IYh << 8 182 | cpu.PC = (cpu.PC + 1) & 0xffff 183 | end 184 | 185 | -- LD IYl,nn 186 | opcodes[0x2e] = function (cpu) 187 | --logger.debug("LD IYl,nn") 188 | local byte = read_mem_byte(cpu, cpu.PC + 1) 189 | cpu.IY = (cpu.IY & 0xff00) | byte 190 | cpu.PC = (cpu.PC + 2) & 0xffff 191 | end 192 | 193 | -- INC (IY+nn) 194 | opcodes[0x34] = function (cpu) 195 | --logger.debug("INC (IY+nn)") 196 | local offset = sign_extend(read_mem_byte(cpu, cpu.PC + 1)) 197 | for i=1,5 do 198 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 199 | end 200 | local byte = read_mem_byte(cpu, cpu.IY + offset) 201 | contend_read_no_mreq(cpu, cpu.IY + offset, 1) 202 | byte = INC(cpu, byte) 203 | write_mem_byte(cpu, cpu.IY + offset, byte) 204 | 205 | cpu.PC = (cpu.PC + 2) & 0xffff 206 | end 207 | 208 | -- DEC (IY+nn) 209 | opcodes[0x35] = function (cpu) 210 | --logger.debug("DEC (IY+nn)") 211 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 212 | 213 | for i=1,5 do 214 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 215 | end 216 | local byte = read_mem_byte(cpu, cpu.IY + offset) 217 | contend_read_no_mreq(cpu, cpu.IY + offset, 1) 218 | byte = DEC(cpu, byte) 219 | write_mem_byte(cpu, cpu.IY + offset, byte) 220 | 221 | cpu.PC = (cpu.PC + 2) & 0xffff 222 | end 223 | 224 | -- LD (IY+dd),nn 225 | opcodes[0x36] = function (cpu) 226 | --logger.debug("LD (IY+dd),nn") 227 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 228 | local byte = read_mem_byte(cpu, cpu.PC + 2) 229 | contend_read_no_mreq(cpu, cpu.PC + 2, 1) 230 | contend_read_no_mreq(cpu, cpu.PC + 2, 1) 231 | write_mem_byte(cpu, cpu.IY + offset, byte) 232 | cpu.PC = (cpu.PC + 3) & 0xffff 233 | end 234 | 235 | -- ADD IY,SP 236 | opcodes[0x39] = function (cpu) 237 | --logger.debug("ADD IY,SP") 238 | cpu.IY = ADD_16(cpu, cpu.IY, cpu.SP) 239 | cpu.PC = (cpu.PC + 1) & 0xffff 240 | end 241 | 242 | -- LD B,IYh 243 | opcodes[0x44] = function (cpu) 244 | --logger.debug("LD B,IYh") 245 | cpu.B = (cpu.IY & 0xff00) >> 8 246 | cpu.PC = (cpu.PC + 1) & 0xffff 247 | end 248 | 249 | -- LD B,IYl 250 | opcodes[0x45] = function (cpu) 251 | --logger.debug("LD B,IYl") 252 | cpu.B = cpu.IY & 0x00ff 253 | cpu.PC = (cpu.PC + 1) & 0xffff 254 | end 255 | 256 | -- LD B,(IY+nn) 257 | opcodes[0x46] = function (cpu) 258 | --logger.debug("LD B,(IY+nn)") 259 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 260 | for i=1,5 do 261 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 262 | end 263 | cpu.B = read_mem_byte(cpu, cpu.IY + offset) 264 | cpu.PC = (cpu.PC + 2) & 0xffff 265 | end 266 | 267 | -- LD C,IYh 268 | opcodes[0x4c] = function (cpu) 269 | --logger.debug("LD C,IYh") 270 | cpu.C = (cpu.IY & 0xff00) >> 8 271 | cpu.PC = (cpu.PC + 1) & 0xffff 272 | end 273 | 274 | -- LD C,IYl 275 | opcodes[0x4d] = function (cpu) 276 | --logger.debug("LD C,IYl") 277 | cpu.C = cpu.IY & 0x00ff 278 | cpu.PC = (cpu.PC + 1) & 0xffff 279 | end 280 | 281 | -- LD C,(IY+nn) 282 | opcodes[0x4e] = function (cpu) 283 | --logger.debug("LD C,(IY+nn)") 284 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 285 | for i=1,5 do 286 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 287 | end 288 | cpu.C = read_mem_byte(cpu, cpu.IY + offset) 289 | cpu.PC = (cpu.PC + 2) & 0xffff 290 | end 291 | 292 | -- LD D,IYh 293 | opcodes[0x54] = function (cpu) 294 | --logger.debug("LD D,IYh") 295 | cpu.D = (cpu.IY & 0xff00) >> 8 296 | cpu.PC = (cpu.PC + 1) & 0xffff 297 | end 298 | 299 | -- LD D,IYl 300 | opcodes[0x55] = function (cpu) 301 | --logger.debug("LD D,IYl") 302 | cpu.D = cpu.IY & 0x00ff 303 | cpu.PC = (cpu.PC + 1) & 0xffff 304 | end 305 | 306 | -- LD D,(IY+nn) 307 | opcodes[0x56] = function (cpu) 308 | --logger.debug("LD D,(IY+nn)") 309 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 310 | for i=1,5 do 311 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 312 | end 313 | cpu.D = read_mem_byte(cpu, cpu.IY + offset) 314 | cpu.PC = (cpu.PC + 2) & 0xffff 315 | end 316 | 317 | -- LD E,IYh 318 | opcodes[0x5c] = function (cpu) 319 | --logger.debug("LD E,IYh") 320 | cpu.E = (cpu.IY & 0xff00) >> 8 321 | cpu.PC = (cpu.PC + 1) & 0xffff 322 | end 323 | 324 | -- LD E,IYl 325 | opcodes[0x5d] = function (cpu) 326 | --logger.debug("LD E,IYl") 327 | cpu.E = cpu.IY & 0x00ff 328 | cpu.PC = (cpu.PC + 1) & 0xffff 329 | end 330 | 331 | -- LD E,(IY+nn) 332 | opcodes[0x5e] = function (cpu) 333 | --logger.debug("LD E,(IY+nn)") 334 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 335 | for i=1,5 do 336 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 337 | end 338 | cpu.E = read_mem_byte(cpu, cpu.IY + offset) 339 | cpu.PC = (cpu.PC + 2) & 0xffff 340 | end 341 | 342 | -- LD IYh,B 343 | opcodes[0x60] = function (cpu) 344 | --logger.debug("LD IYh,B") 345 | cpu.IY = (cpu.B << 8) | (cpu.IY & 0x00ff) 346 | cpu.PC = (cpu.PC + 1) & 0xffff 347 | end 348 | 349 | -- LD IYh,C 350 | opcodes[0x61] = function (cpu) 351 | --logger.debug("LD IYh,C") 352 | cpu.IY = (cpu.C << 8) | (cpu.IY & 0x00ff) 353 | cpu.PC = (cpu.PC + 1) & 0xffff 354 | end 355 | 356 | -- LD IYh,D 357 | opcodes[0x62] = function (cpu) 358 | --logger.debug("LD IYh,D") 359 | cpu.IY = (cpu.D << 8) | (cpu.IY & 0x00ff) 360 | cpu.PC = (cpu.PC + 1) & 0xffff 361 | end 362 | 363 | -- LD IYh,E 364 | opcodes[0x63] = function (cpu) 365 | --logger.debug("LD IYh,E") 366 | cpu.IY = (cpu.E << 8) | (cpu.IY & 0x00ff) 367 | cpu.PC = (cpu.PC + 1) & 0xffff 368 | end 369 | 370 | -- LD IYh,IYh 371 | opcodes[0x64] = function (cpu) 372 | --logger.debug("LD IYh,IYh") 373 | -- LD IYh,IYh 374 | cpu.PC = (cpu.PC + 1) & 0xffff 375 | end 376 | 377 | -- LD IYh,IYl 378 | opcodes[0x65] = function (cpu) 379 | --logger.debug("LD IYh,IYl") 380 | local IYl = cpu.IY & 0x00ff 381 | cpu.IY = IYl | (IYl << 8) 382 | cpu.PC = (cpu.PC + 1) & 0xffff 383 | end 384 | 385 | -- LD H,(IY+nn) 386 | opcodes[0x66] = function (cpu) 387 | --logger.debug("LD H,(IY+nn)") 388 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 389 | for i=1,5 do 390 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 391 | end 392 | cpu.H = read_mem_byte(cpu, cpu.IY + offset) 393 | cpu.PC = (cpu.PC + 2) & 0xffff 394 | end 395 | 396 | -- LD IYh,A 397 | opcodes[0x67] = function (cpu) 398 | --logger.debug("LD IYh,A") 399 | cpu.IY = (cpu.A << 8) | (cpu.IY & 0x00ff) 400 | cpu.PC = (cpu.PC + 1) & 0xffff 401 | end 402 | 403 | -- LD IYl,B 404 | opcodes[0x68] = function (cpu) 405 | --logger.debug("LD IYl,B") 406 | cpu.IY = (cpu.IY & 0xff00) | cpu.B 407 | cpu.PC = (cpu.PC + 1) & 0xffff 408 | end 409 | 410 | -- LD IYl,C 411 | opcodes[0x69] = function (cpu) 412 | --logger.debug("LD IYl,C") 413 | cpu.IY = (cpu.IY & 0xff00) | cpu.C 414 | cpu.PC = (cpu.PC + 1) & 0xffff 415 | end 416 | 417 | -- LD IYl,D 418 | opcodes[0x6a] = function (cpu) 419 | --logger.debug("LD IYl,D") 420 | cpu.IY = (cpu.IY & 0xff00) | cpu.D 421 | cpu.PC = (cpu.PC + 1) & 0xffff 422 | end 423 | 424 | -- LD IYl,E 425 | opcodes[0x6b] = function (cpu) 426 | --logger.debug("LD IYl,E") 427 | cpu.IY = (cpu.IY & 0xff00) | cpu.E 428 | cpu.PC = (cpu.PC + 1) & 0xffff 429 | end 430 | 431 | -- LD IYl,IYh 432 | opcodes[0x6c] = function (cpu) 433 | --logger.debug("LD IYl,IYh") 434 | local high, low = high_low(cpu.IY) 435 | cpu.IY = high | (high << 8) 436 | cpu.PC = (cpu.PC + 1) & 0xffff 437 | end 438 | 439 | -- LD IYl,IYl 440 | opcodes[0x6d] = function (cpu) 441 | --logger.debug("LD IYl,IYl") 442 | cpu.PC = (cpu.PC + 1) & 0xffff 443 | end 444 | 445 | -- LD L,IY+nn 446 | opcodes[0x6e] = function (cpu) 447 | --logger.debug("LD L,(IY+nn)") 448 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 449 | for i=1,5 do 450 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 451 | end 452 | cpu.L = read_mem_byte(cpu, cpu.IY + offset) 453 | cpu.PC = (cpu.PC + 2) & 0xffff 454 | end 455 | 456 | -- LD IYl,A 457 | opcodes[0x6f] = function (cpu) 458 | --logger.debug("LD IYl,A") 459 | cpu.IY = (cpu.IY & 0xff00) | cpu.A 460 | cpu.PC = (cpu.PC + 1) & 0xffff 461 | end 462 | 463 | -- LD (IY+nn),B 464 | opcodes[0x70] = function (cpu) 465 | --logger.debug("LD (IY+nn),B") 466 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 467 | for i=1,5 do 468 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 469 | end 470 | write_mem_byte(cpu, cpu.IY + offset, cpu.B) 471 | cpu.PC = (cpu.PC + 2) & 0xffff 472 | end 473 | 474 | -- LD (IY+nn),C 475 | opcodes[0x71] = function (cpu) 476 | --logger.debug("LD (IY+nn),C") 477 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 478 | for i=1,5 do 479 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 480 | end 481 | write_mem_byte(cpu, cpu.IY + offset, cpu.C) 482 | cpu.PC = (cpu.PC + 2) & 0xffff 483 | end 484 | 485 | -- LD (IY+nn),D 486 | opcodes[0x72] = function (cpu) 487 | --logger.debug("LD (IY+nn),D") 488 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 489 | for i=1,5 do 490 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 491 | end 492 | write_mem_byte(cpu, cpu.IY + offset, cpu.D) 493 | cpu.PC = (cpu.PC + 2) & 0xffff 494 | end 495 | 496 | -- LD (IY+nn),E 497 | opcodes[0x73] = function (cpu) 498 | --logger.debug("LD (IY+nn),E") 499 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 500 | for i=1,5 do 501 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 502 | end 503 | write_mem_byte(cpu, cpu.IY + offset, cpu.E) 504 | cpu.PC = (cpu.PC + 2) & 0xffff 505 | end 506 | 507 | -- LD (IY+nn),H 508 | opcodes[0x74] = function (cpu) 509 | --logger.debug("LD (IY+nn),H") 510 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 511 | for i=1,5 do 512 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 513 | end 514 | write_mem_byte(cpu, cpu.IY + offset, cpu.H) 515 | cpu.PC = (cpu.PC + 2) & 0xffff 516 | end 517 | 518 | -- LD (IY+nn),L 519 | opcodes[0x75] = function (cpu) 520 | --logger.debug("LD (IY+nn),L") 521 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 522 | for i=1,5 do 523 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 524 | end 525 | write_mem_byte(cpu, cpu.IY + offset, cpu.L) 526 | cpu.PC = (cpu.PC + 2) & 0xffff 527 | end 528 | 529 | -- LD (IY+nn),A 530 | opcodes[0x77] = function (cpu) 531 | --logger.debug("LD (IY+nn),A") 532 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 533 | for i=1,5 do 534 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 535 | end 536 | write_mem_byte(cpu, cpu.IY + offset, cpu.A) 537 | cpu.PC = (cpu.PC + 2) & 0xffff 538 | end 539 | 540 | -- LD A,IYh 541 | opcodes[0x7c] = function (cpu) 542 | --logger.debug("LD A,IYh") 543 | cpu.A = (cpu.IY & 0xff00) >> 8 544 | cpu.PC = (cpu.PC + 1) & 0xffff 545 | end 546 | 547 | -- LD A,IYl 548 | opcodes[0x7d] = function (cpu) 549 | --logger.debug("LD A,IYl") 550 | cpu.A = cpu.IY & 0x00ff 551 | cpu.PC = (cpu.PC + 1) & 0xffff 552 | end 553 | 554 | -- LD A,(IY+nn) 555 | opcodes[0x7e] = function (cpu) 556 | --logger.debug("LD A,(IY+nn)") 557 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 558 | for i=1,5 do 559 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 560 | end 561 | cpu.A = read_mem_byte(cpu, cpu.IY + offset) 562 | cpu.PC = (cpu.PC + 2) & 0xffff 563 | end 564 | 565 | -- ADD A,IYh 566 | opcodes[0x84] = function (cpu) 567 | --logger.debug("ADD A,IYh") 568 | ADD_8(cpu, (cpu.IY & 0xff00) >> 8) 569 | cpu.PC = (cpu.PC + 1) & 0xffff 570 | end 571 | 572 | -- ADD A,IYl 573 | opcodes[0x85] = function (cpu) 574 | --logger.debug("ADD A,IYl") 575 | ADD_8(cpu, cpu.IY & 0x00ff) 576 | cpu.PC = (cpu.PC + 1) & 0xffff 577 | end 578 | 579 | -- ADD A,(IY+nn) 580 | opcodes[0x86] = function (cpu) 581 | --logger.debug("ADD A,(IY+nn)") 582 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 583 | for i=1,5 do 584 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 585 | end 586 | local byte = read_mem_byte(cpu, cpu.IY + offset) 587 | ADD_8(cpu, byte) 588 | cpu.PC = (cpu.PC + 2) & 0xffff 589 | end 590 | 591 | -- ADC A,IYh 592 | opcodes[0x8c] = function (cpu) 593 | --logger.debug("ADC A,IYh") 594 | ADC_8(cpu, (cpu.IY & 0xff00) >> 8) 595 | cpu.PC = (cpu.PC + 1) & 0xffff 596 | end 597 | 598 | -- ADC A,IYl 599 | opcodes[0x8d] = function (cpu) 600 | --logger.debug("ADC A,IYl") 601 | ADC_8(cpu, cpu.IY & 0x00ff) 602 | cpu.PC = (cpu.PC + 1) & 0xffff 603 | end 604 | 605 | -- ADC A,(IY+nn) 606 | opcodes[0x8e] = function (cpu) 607 | --logger.debug("ADC A,(IY+nn)") 608 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 609 | for i=1,5 do 610 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 611 | end 612 | ADC_8(cpu, read_mem_byte(cpu, cpu.IY + offset)) 613 | cpu.PC = (cpu.PC + 2) & 0xffff 614 | end 615 | 616 | -- SUB IYh 617 | opcodes[0x94] = function (cpu) 618 | --logger.debug("SUB IYh") 619 | SUB(cpu, (cpu.IY & 0xff00) >> 8) 620 | cpu.PC = (cpu.PC + 1) & 0xffff 621 | end 622 | 623 | -- SUB IYl 624 | opcodes[0x95] = function (cpu) 625 | --logger.debug("SUB IYl") 626 | SUB(cpu, cpu.IY & 0x00ff) 627 | cpu.PC = (cpu.PC + 1) & 0xffff 628 | end 629 | 630 | -- SUB A,(IY+nn) 631 | opcodes[0x96] = function (cpu) 632 | --logger.debug("SUB A,(IY+nn)") 633 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 634 | for i=1,5 do 635 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 636 | end 637 | SUB(cpu, read_mem_byte(cpu, cpu.IY + offset)) 638 | cpu.PC = (cpu.PC + 2) & 0xffff 639 | end 640 | 641 | -- SBC A,IYh 642 | opcodes[0x9c] = function (cpu) 643 | --logger.debug("SBC A,IYh") 644 | SBC(cpu, (cpu.IY & 0xff00) >> 8) 645 | cpu.PC = (cpu.PC + 1) & 0xffff 646 | end 647 | 648 | -- SBC A,IYl 649 | opcodes[0x9d] = function (cpu) 650 | --logger.debug("SBC A,IYl") 651 | SBC(cpu, cpu.IY & 0x00ff) 652 | cpu.PC = (cpu.PC + 1) & 0xffff 653 | end 654 | 655 | -- SBC A,(IY+nn) 656 | opcodes[0x9e] = function (cpu) 657 | --logger.debug("SBC A,(IY+nn)") 658 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 659 | for i=1,5 do 660 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 661 | end 662 | SBC(cpu, read_mem_byte(cpu, cpu.IY + offset)) 663 | cpu.PC = (cpu.PC + 2) & 0xffff 664 | end 665 | 666 | -- AND IYh 667 | opcodes[0xa4] = function (cpu) 668 | --logger.debug("AND IYh") 669 | AND(cpu, (cpu.IY & 0xff00) >> 8) 670 | cpu.PC = (cpu.PC + 1) & 0xffff 671 | end 672 | 673 | -- AND IYl 674 | opcodes[0xa5] = function (cpu) 675 | --logger.debug("AND IYl") 676 | AND(cpu, cpu.IY & 0x00ff) 677 | cpu.PC = (cpu.PC + 1) & 0xffff 678 | end 679 | 680 | -- AND (IY+nn) 681 | opcodes[0xa6] = function (cpu) 682 | --logger.debug("AND (IY+nn)") 683 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 684 | for i=1,5 do 685 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 686 | end 687 | AND(cpu, read_mem_byte(cpu, cpu.IY + offset)) 688 | cpu.PC = (cpu.PC + 2) & 0xffff 689 | end 690 | 691 | -- XOR IYh 692 | opcodes[0xac] = function (cpu) 693 | --logger.debug("XOR IYh") 694 | XOR(cpu, (cpu.IY & 0xff00) >> 8) 695 | cpu.PC = (cpu.PC + 1) & 0xffff 696 | end 697 | 698 | -- XOR IYl 699 | opcodes[0xad] = function (cpu) 700 | --logger.debug("XOR IYl") 701 | XOR(cpu, cpu.IY & 0x00ff) 702 | cpu.PC = (cpu.PC + 1) & 0xffff 703 | end 704 | 705 | -- XOR (IY+nn) 706 | opcodes[0xae] = function (cpu) 707 | --logger.debug("XOR (IY+nn)") 708 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 709 | for i=1,5 do 710 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 711 | end 712 | XOR(cpu, read_mem_byte(cpu, cpu.IY + offset)) 713 | cpu.PC = (cpu.PC + 2) & 0xffff 714 | end 715 | 716 | -- OR IYh 717 | opcodes[0xb4] = function (cpu) 718 | --logger.debug("OR IYh") 719 | OR(cpu, (cpu.IY & 0xff00) >> 8) 720 | cpu.PC = (cpu.PC + 1) & 0xffff 721 | end 722 | 723 | -- OR IYl 724 | opcodes[0xb5] = function (cpu) 725 | --logger.debug("OR IYl") 726 | OR(cpu, cpu.IY & 0x00ff) 727 | cpu.PC = (cpu.PC + 1) & 0xffff 728 | end 729 | 730 | -- OR (IY+nn) 731 | opcodes[0xb6] = function (cpu) 732 | --logger.debug("OR (IY+nn)") 733 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 734 | for i=1,5 do 735 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 736 | end 737 | OR(cpu, read_mem_byte(cpu, cpu.IY + offset)) 738 | cpu.PC = (cpu.PC + 2) & 0xffff 739 | end 740 | 741 | -- CP IYh 742 | opcodes[0xbc] = function (cpu) 743 | --logger.debug("CP IYh") 744 | CP(cpu, (cpu.IY & 0xff00) >> 8) 745 | cpu.PC = (cpu.PC + 1) & 0xffff 746 | end 747 | 748 | -- CP IYl 749 | opcodes[0xbd] = function (cpu) 750 | --logger.debug("CP IYl") 751 | CP(cpu, cpu.IY & 0x00ff) 752 | cpu.PC = (cpu.PC + 1) & 0xffff 753 | end 754 | 755 | -- CP (IY+nn) 756 | opcodes[0xbe] = function (cpu) 757 | --logger.debug("CP (IY+nn)") 758 | local offset = sign_extend( read_mem_byte(cpu, cpu.PC + 1) ) 759 | for i=1,5 do 760 | contend_read_no_mreq(cpu, cpu.PC + 1, 1) 761 | end 762 | CP(cpu, read_mem_byte(cpu, cpu.IY + offset)) 763 | cpu.PC = (cpu.PC + 2) & 0xffff 764 | end 765 | 766 | -- 0xCB FDCB opcodes 767 | opcodes[0xcb] = function (cpu) 768 | --logger.warning("shifting FDCB") 769 | contend_read_no_mreq(cpu, cpu.PC + 1, 3) 770 | local offset = sign_extend( read_mem_byte_internal(cpu, cpu.PC + 1) ) 771 | contend_read_no_mreq(cpu, cpu.PC + 2, 3) 772 | local opcode = read_mem_byte_internal(cpu, cpu.PC + 2) 773 | contend_read_no_mreq(cpu, cpu.PC + 2, 1) 774 | contend_read_no_mreq(cpu, cpu.PC + 2, 1) 775 | local f = opcodes_fdcb[opcode] 776 | if not f then 777 | --logger.fatal("Opcode FDCB 0x%0x (%d) not found", opcode, opcode) 778 | error("") 779 | return 780 | end 781 | f(cpu, offset) 782 | cpu.PC = (cpu.PC + 3) & 0xffff 783 | end 784 | 785 | -- POP IY 786 | opcodes[0xe1] = function (cpu) 787 | --logger.debug("POP IY") 788 | local low = read_mem_byte(cpu, cpu.SP) 789 | local high = read_mem_byte(cpu, cpu.SP + 1) 790 | cpu.IY = low | (high << 8) 791 | cpu.SP = (cpu.SP + 2) & 0xffff 792 | cpu.PC = (cpu.PC + 1) & 0xffff 793 | end 794 | 795 | -- EX (SP),IY 796 | opcodes[0xe3] = function (cpu) 797 | --logger.debug("EX (SP),IY") 798 | local temp = cpu.IY 799 | cpu.IY = read_mem_word(cpu, cpu.SP) 800 | contend_read_no_mreq(cpu, cpu.SP + 1, 1) 801 | write_mem_byte(cpu, cpu.SP + 1, (temp & 0xff00) >> 8) 802 | write_mem_byte(cpu, cpu.SP, temp & 0xff) 803 | contend_write_no_mreq(cpu, cpu.SP, 1) 804 | contend_write_no_mreq(cpu, cpu.SP, 1) 805 | cpu.PC = (cpu.PC + 1) & 0xffff 806 | end 807 | 808 | -- PUSH IY 809 | opcodes[0xe5] = function (cpu) 810 | --logger.debug("PUSH IY") 811 | -- contend with IR register pair 812 | local I_high = cpu.I << 8 813 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 814 | 815 | cpu.SP = (cpu.SP - 2) & 0xffff 816 | write_mem_byte(cpu, cpu.SP + 1, (cpu.IY & 0xff00) >> 8) 817 | write_mem_byte(cpu, cpu.SP, cpu.IY & 0xff) 818 | cpu.PC = (cpu.PC + 1) & 0xffff 819 | end 820 | 821 | -- JP IY 822 | opcodes[0xe9] = function (cpu) 823 | --logger.debug("JP IY") 824 | cpu.PC = cpu.IY 825 | end 826 | 827 | -- LD SP,IY 828 | opcodes[0xf9] = function (cpu) 829 | --logger.debug("LD SP,IY") 830 | cpu.SP = cpu.IY 831 | -- contend with IR register pair 832 | local I_high = cpu.I << 8 833 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 834 | contend_read_no_mreq(cpu, I_high | cpu.R, 1) 835 | cpu.PC = (cpu.PC + 1) & 0xffff 836 | end 837 | 838 | 839 | return opcodes 840 | -------------------------------------------------------------------------------- /opcodes/fdcb.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- DDCBxx opcodes 3 | -- 4 | 5 | local logger = require "logger" 6 | local common_ops = require "opcodes.common" 7 | 8 | local BIT_INDEX = common_ops.BIT_INDEX 9 | local RLC = common_ops.RLC 10 | local RRC = common_ops.RRC 11 | local RL = common_ops.RL 12 | local RR = common_ops.RR 13 | local SLA = common_ops.SLA 14 | local SLL = common_ops.SLL 15 | local SRA = common_ops.SRA 16 | local SRL = common_ops.SRL 17 | 18 | --- 19 | -- Will be bound to the actual functions to be called later in bind_io 20 | -- 21 | local contend_read_no_mreq 22 | local read_mem_byte 23 | local write_mem_byte 24 | 25 | local FLAG_S = 128 26 | local FLAG_Z = 64 27 | local FLAG_B5 = 32 28 | local FLAG_H = 16 29 | local FLAG_B3 = 8 30 | local FLAG_PV = 4 31 | local FLAG_N = 2 32 | local FLAG_C = 1 33 | 34 | local FLAG_N_OFF = 253 35 | local FLAG_PV_OFF = 251 36 | local FLAG_Z_OFF = 191 37 | local FLAG_H_OFF = 239 38 | local FLAG_S_OFF = 127 39 | local FLAG_C_OFF = 254 40 | 41 | 42 | local opcodes = {} 43 | 44 | function opcodes.bind_io (binds) 45 | contend_read_no_mreq = assert(binds.memory.contend_read_no_mreq) 46 | read_mem_byte = assert(binds.memory.read_mem_byte) 47 | write_mem_byte = assert(binds.memory.write_mem_byte) 48 | end 49 | 50 | -- "foo" is used to skip, for instance, RLC IY 51 | -- LD B,RLC (REGISTER+dd) 52 | local instructions = { RLC, RRC, RL, RR, SLA, SRA, SLL, SRL } 53 | local i = 0 54 | for _, instruction in ipairs(instructions) do 55 | local regs = {"B", "C", "D", "E", "H", "L", "foo", "A"} 56 | for _, reg in ipairs(regs) do 57 | opcodes[i] = function (cpu, offset) 58 | local address = cpu.IY + offset 59 | local byte = read_mem_byte(cpu, address) 60 | contend_read_no_mreq(cpu, address, 1) 61 | cpu[reg] = instruction(cpu, byte) 62 | write_mem_byte(cpu, address, cpu[reg]) 63 | end 64 | i = i + 1 65 | end 66 | end 67 | 68 | -- RLC IY 69 | opcodes[0x06] = function (cpu, offset) 70 | local address = cpu.IY + offset 71 | local byte = read_mem_byte(cpu, address) 72 | contend_read_no_mreq(cpu, address, 1) 73 | byte = RLC(cpu, byte) 74 | write_mem_byte(cpu, address, byte) 75 | end 76 | 77 | local base = 0x40 78 | for bit=0, 7 do 79 | for i=0,7 do--for i=0x40, 0x7f, 8 do 80 | opcodes[base + i] = function (cpu, offset) 81 | --logger.debug("BIT 0,IY+nn") 82 | local address = cpu.IY + offset 83 | local byte = read_mem_byte(cpu, address) 84 | contend_read_no_mreq(cpu, address, 1) 85 | BIT_INDEX(cpu, bit, byte, address) 86 | end 87 | end 88 | base = base + 8 89 | end 90 | 91 | 92 | -- LD B,RES 0,(IY+dd), etc 93 | local base = 0x80 94 | for b=0, 7 do 95 | local regs = {"B", "C", "D", "E", "H", "L", "foo", "A"} 96 | for i, reg in ipairs(regs) do 97 | local bit = 1 << b -- 2^bit 98 | bit = bit ~ 0xff -- invert 99 | if reg ~= "foo" then 100 | opcodes[base + i - 1] = function (cpu, offset) 101 | local address = cpu.IY + offset 102 | local byte = read_mem_byte(cpu, address) 103 | contend_read_no_mreq(cpu, address, 1) 104 | byte = byte & bit -- turn it off 105 | cpu[reg] = byte 106 | write_mem_byte(cpu, address, byte) 107 | end 108 | else 109 | opcodes[base + i - 1] = function (cpu, offset) 110 | local address = cpu.IY + offset 111 | local byte = read_mem_byte(cpu, address) 112 | contend_read_no_mreq(cpu, address, 1) 113 | byte = byte & bit -- turn it off 114 | write_mem_byte(cpu, address, byte) 115 | end 116 | end 117 | end 118 | base = base + 8 119 | end 120 | 121 | 122 | -- LD B,SET 0,(IY+dd), etc 123 | local base = 0xc0 124 | for b=0, 7 do 125 | local regs = {"B", "C", "D", "E", "H", "L", "foo", "A"} 126 | for i, reg in ipairs(regs) do 127 | local bit = 1 << b -- 2^bit 128 | if reg ~= "foo" then 129 | opcodes[base + i - 1] = function (cpu, offset) 130 | local address = cpu.IY + offset 131 | local byte = read_mem_byte(cpu, address) 132 | contend_read_no_mreq(cpu, address, 1) 133 | byte = byte | bit 134 | cpu[reg] = byte 135 | write_mem_byte(cpu, address, byte) 136 | end 137 | else 138 | opcodes[base + i - 1] = function (cpu, offset) 139 | local address = cpu.IY + offset 140 | local byte = read_mem_byte(cpu, address) 141 | contend_read_no_mreq(cpu, address, 1) 142 | byte = byte | bit 143 | write_mem_byte(cpu, address, byte) 144 | end 145 | end 146 | end 147 | base = base + 8 148 | end 149 | 150 | 151 | return opcodes 152 | -------------------------------------------------------------------------------- /port.lua: -------------------------------------------------------------------------------- 1 | local logger = require "logger" 2 | 3 | local SDL = require "SDL" 4 | 5 | local read_port_handler = {} 6 | 7 | local FLAG_S = 128 8 | local FLAG_Z = 64 9 | local FLAG_B5 = 32 10 | local FLAG_H = 16 11 | local FLAG_B3 = 8 12 | local FLAG_PV = 4 13 | local FLAG_N = 2 14 | local FLAG_C = 1 15 | 16 | 17 | local issue = 0xff 18 | 19 | -- port is a 16 bit value 20 | local function default_port_handler (cpu, port) 21 | --if(g_iNoLinea < 64 || g_iNoLinea > 64 + 192) {// || /*scanline < 24 ||*/ scanline > 128) 22 | -- return 0xff; 23 | --} 24 | --else { 25 | -- return g_memoria[g_iPaginaPantalla][(g_iScanline / 4 + D_AttribArray[g_iNoLinea - 64]) - 0x4000]; 26 | --end 27 | --return 0xff 28 | -- TODO; Have access to the current scanline 29 | logger.info("default_port_handler: %s", cpu.tstates) 30 | return 0 31 | end 32 | 33 | --- 34 | -- Helper function to read a mid-row of the keyboard. 35 | -- A "mid row" is, for instance, asdfg or qwert 36 | local function read_key_row (keys, k1, k2, k3, k4, k5) 37 | return (keys[k1] and 0xfe or 0xff) 38 | & (keys[k2] and 0xfd or 0xff) 39 | & (keys[k3] and 0xfb or 0xff) 40 | & (keys[k4] and 0xf7 or 0xff) 41 | & (keys[k5] and 0xef or 0xff) 42 | 43 | end 44 | 45 | local function count_bits (value) 46 | -- count how many bits on 47 | local counter = 0 48 | for i = 0, 7 do 49 | if value & 0x01 ~= 0 then counter = counter + 1 end 50 | value = value >> 1 51 | end 52 | return counter 53 | end 54 | 55 | 56 | local function read_keyboard (cpu, port_high) 57 | -- get the currently pressed keys 58 | SDL.pumpEvents() 59 | local keys = SDL.getKeyboardState() 60 | 61 | local pressed_keys = issue -- depends on the keyboard issue (issue 2 or issue 3) 62 | 63 | local scancode = SDL.scancode 64 | 65 | --logger.info("read_keyboard: port: %02x %s", port_high, cpu.tstates) 66 | 67 | -- Map cetain key combinations to ease the usage 68 | -- If Backspace is pressed -> LeftShift + 0 are simulated 69 | -- If Capslock is pressed -> LeftShift + 2 are simulated 70 | -- If cursor Up is pressed -> LeftShift + 7 are simulated 71 | -- If cursor Down is pressed -> LeftShift + 6 are simulated 72 | -- If cursor Left is pressed -> LeftShift + 5 are simulated 73 | -- If cursor Right is pressed -> LeftShift + 8 are simulated 74 | 75 | if port_high & 0x01 == 0 then 76 | --logger.info("read_keyboard: row symbol_shift z x c v") 77 | -- scan the row symbol_shift z x c v 78 | pressed_keys = pressed_keys & read_key_row(keys, scancode.LeftShift, scancode.Z, scancode.X, scancode.C, scancode.V) 79 | -- Map Backspace, CapsLock and cursors to emulated keyboard. This combinations all fakes a LeftShift press 80 | if keys[scancode.Backspace] or keys[scancode.CapsLock] or keys[scancode.Up] or keys[scancode.Down] or 81 | keys[scancode.Left] or keys[scancode.Right] 82 | then 83 | pressed_keys = pressed_keys & 0xfe 84 | end 85 | end 86 | if port_high & 0x02 == 0 then 87 | --logger.info("read_keyboard: row a s d f g") 88 | -- scan the row a s d f g 89 | pressed_keys = pressed_keys & read_key_row(keys, scancode.A, scancode.S, scancode.D, scancode.F, scancode.G) 90 | end 91 | if port_high & 0x04 == 0 then 92 | --logger.info("read_keyboard: row q w e r t") 93 | -- scan the row q w e r t 94 | pressed_keys = pressed_keys & read_key_row(keys, scancode.Q, scancode.W, scancode.E, scancode.R, scancode.T) 95 | end 96 | if port_high & 0x08 == 0 then 97 | --logger.info("read_keyboard: row 1 2 3 4 5") 98 | -- scan the row 1 2 3 4 5 99 | pressed_keys = pressed_keys & read_key_row(keys, scancode["1"], scancode["2"], scancode["3"], scancode["4"], scancode["5"]) 100 | -- Map CapsLock and Cursors 101 | if keys[scancode.CapsLock] then pressed_keys = pressed_keys & 0xfd end -- 2 102 | if keys[scancode.Left] then pressed_keys = pressed_keys & 0xef end -- 5 103 | end 104 | if port_high & 0x10 == 0 then 105 | --logger.info("read_keyboard: row 6 7 8 9 0") 106 | -- scan the row 6 7 8 9 0 (backwards) 107 | pressed_keys = pressed_keys & read_key_row(keys, scancode["0"], scancode["9"], scancode["8"], scancode["7"], scancode["6"]) 108 | -- Map Backspace and Cursors 109 | if keys[scancode.Backspace] then pressed_keys = pressed_keys & 0xfe end -- 0 110 | if keys[scancode.Right] then pressed_keys = pressed_keys & 0xfb end -- 8 111 | if keys[scancode.Up] then pressed_keys = pressed_keys & 0xf7 end -- 7 112 | if keys[scancode.Down] then pressed_keys = pressed_keys & 0xef end -- 6 113 | end 114 | if port_high & 0x20 == 0 then 115 | --logger.info("read_keyboard: row y u i o p") 116 | -- scan the row y u i o p (backwards) 117 | pressed_keys = pressed_keys & read_key_row(keys, scancode.P, scancode.O, scancode.I, scancode.U, scancode.Y) 118 | end 119 | if port_high & 0x40 == 0 then 120 | --logger.info("read_keyboard: row h j k l ") 121 | -- scan the row h j k l (backwards) 122 | pressed_keys = pressed_keys & read_key_row(keys, scancode.Return, scancode.L, scancode.K, scancode.J, scancode.H) 123 | end 124 | if port_high & 0x80 == 0 then 125 | --logger.info("read_keyboard: row b n m symbol_shift space") 126 | -- scan the row b n m symbol_shift space 127 | pressed_keys = pressed_keys & read_key_row(keys, scancode.Space, scancode.RightShift, scancode.M, scancode.N, scancode.B) 128 | end 129 | 130 | --logger.info("read_keyboard: port: %02x %s pressed_keys %s", port_high, cpu.tstates, pressed_keys) 131 | 132 | -- mask carry flag so we don't touch it 133 | cpu.F = cpu.F & FLAG_C 134 | if pressed_keys == 0 then 135 | cpu.F = cpu.F | FLAG_Z 136 | elseif pressed_keys & 0x80 ~= 0 then 137 | cpu.F = cpu.F | FLAG_S 138 | end 139 | 140 | -- count how many bits on 141 | local count = count_bits(pressed_keys) 142 | if count & 0x01 == 0 then 143 | cpu.F = cpu.F | FLAG_PV 144 | end 145 | 146 | cpu.F = cpu.F | (pressed_keys & (FLAG_B5 | FLAG_B3)) 147 | 148 | --return 0xbf 149 | return pressed_keys 150 | end 151 | 152 | 153 | --- 154 | -- Reads the kempston joystick (allows us to use the cursor keys of the keyboard in place of a joystick) 155 | local function read_kempston (cpu, port_high) 156 | 157 | local keys = SDL.getKeyboardState() 158 | local scancode = SDL.scancode 159 | 160 | local value = (keys[scancode.LeftControl] or keys[scancode.RightControl]) and 16 or 0 161 | | (keys[scancode.Up] and 8 or 0) 162 | | (keys[scancode.Down] and 4 or 0) 163 | | (keys[scancode.Left] and 2 or 0) 164 | | (keys[scancode.Right] and 1 or 0) 165 | 166 | -- mask carry flag so we don't touch it 167 | cpu.F = cpu.F & FLAG_C 168 | if value == 0 then 169 | cpu.F = cpu.F | FLAG_Z 170 | elseif value & 0x80 ~= 0 then 171 | cpu.F = cpu.F | FLAG_S 172 | end 173 | 174 | -- count how many bits on 175 | local count = count_bits(value) 176 | if count & 0x01 == 0 then 177 | cpu.F = cpu.F | FLAG_PV 178 | end 179 | 180 | cpu.F = cpu.F | (value & (FLAG_B5 | FLAG_B3)) 181 | 182 | return value 183 | end 184 | 185 | 186 | local public = {} 187 | 188 | function public.initialize_ports () 189 | read_port_handler[0xfe] = read_keyboard 190 | --//ReadPortHandler[0xfe] = ReadPlaybackStream; 191 | read_port_handler[0x31] = read_kempston 192 | read_port_handler[0x7f] = read_fuller 193 | read_port_handler[0xfb] = read_alphacom_printer 194 | read_port_handler[0xbf] = read_light_gun 195 | 196 | --//archivoOut = fopen("c:\\tecOut.out", "wb+"); 197 | --//archivoOut = fopen("c:\\tecOut.out", "rb"); 198 | return true 199 | end 200 | 201 | 202 | --- 203 | -- Decodes and read a port 204 | -- 205 | function public.decode_port (cpu, port_high, port_low) 206 | -- Kempston? 207 | -- bit 7,6,5 are low? 208 | if (port_low & 0xe0 == 0) 209 | or port_low == 0xdf -- some games rely on this 210 | then 211 | return read_kempston(cpu, port_high) 212 | end 213 | 214 | local handler = read_port_handler[port_low] or default_port_handler 215 | return handler(cpu, port_high) 216 | end 217 | 218 | 219 | return public 220 | --------------------------------------------------------------------------------