diff --git a/6502.lua b/6502.lua index 8c51a46..b0ed5ef 100644 --- a/6502.lua +++ b/6502.lua @@ -808,6 +808,9 @@ M.long = function(...) table.insert(M.section_current.instructions, { data=data, size=size, bin=bin }) end +-- Return a value in rage [0x00, 0xff] if x is to use zeropage addressing mode. Defaults to range [0x0000-0x00ff]. +M.zeropage = function(x) if x >= -128 and x <= 0xff then return byte_normalize(x) end end + local op,cycles_def,xcross_def op = function(code, cycles, extra_on_crosspage) return { opc=code, cycles=cycles or cycles_def, xcross=extra_on_crosspage or xcross_def } @@ -816,7 +819,12 @@ local op_eval = function(late, early) local x = early or 0 return type(late) == 'function' and late(x,op_resolve) or x+op_resolve(late) end -local op_eval_byte = function(late, early) return byte_normalize(op_eval(late, early)) end +local op_eval_byte = function(late, early, nozp) + local v = op_eval(late, early) + local zpv = zeropage(v) + if not nozp and zpv then return zpv end + return byte_normalize(v) +end local op_eval_word = function(late, early) return word_normalize(op_eval(late, early)) end cycles_def=2 xcross_def=0 local opimp={ asl=op(0x0a), brk=op(0x00,7), clc=op(0x18), cld=op(0xd8), cli=op(0x58), clv=op(0xb8), dex=op(0xca), dey=op(0x88), @@ -839,7 +847,7 @@ for k,v in pairs(opimm) do M[k .. 'imm'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early) } end + local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early,true) } end table.insert(M.section_current.instructions, { size=size, cycles=2, bin=bin }) end end @@ -882,7 +890,7 @@ for k,_ in pairs(opzab) do M[k .. 'zab'] = function(late, early) if type(late) ~= 'function' then local x = (early or 0) + late - if x >= -128 and x <= 0xff then return M[k .. 'zpg'](late, early) end + if zeropage(x) then return M[k .. 'zpg'](late, early) end if x >= -32768 and x <= 0xffff then return M[k .. 'abs'](late, early) end error("value out of word range: " .. x) end @@ -894,11 +902,11 @@ for k,_ in pairs(opzab) do if not r then return 3 end size_ref(x) x = word_normalize(x) - local zpg = opzpg[k] - if x <= 0xff and zpg then + local zpg,zpv = opzpg[k], zeropage(x) + if zpv and zpg then ins.size = 2 ins.cycles = zpg.cycles - ins.bin = function() return { zpg.opc, x } end + ins.bin = function() return { zpg.opc, zpv } end return 2 end ins.size = 3 @@ -908,7 +916,7 @@ for k,_ in pairs(opzab) do ins.bin = function() local l65dbg=l65dbg local x = word_normalize(op_eval(late, early)) -- since we assumed absolute on link phase, we must generate absolute in binary - if x <= 0xff and opzpg[k] then io.stderr:write("warning: forcing abs on zpg operand for opcode " .. k .. "\n") end + if zeropage(x) and opzpg[k] then io.stderr:write("warning: forcing abs on zpg operand for opcode " .. k .. "\n") end return { abs.opc, x&0xff, x>>8 } end table.insert(M.section_current.instructions, ins) @@ -950,7 +958,7 @@ for k,_ in pairs(opzax) do M[k .. 'zax'] = function(late, early) if type(late) ~= 'function' then local x = (early or 0) + late - if x >= -128 and x <= 0xff then return M[k .. 'zpx'](late, early) end + if zeropage(x) then return M[k .. 'zpx'](late, early) end if x >= -32768 and x <= 0xffff then return M[k .. 'abx'](late, early) end error("value out of word range: " .. x) end @@ -962,11 +970,11 @@ for k,_ in pairs(opzax) do if not r then return 3 end size_ref(x) x = word_normalize(x) - local zpx = opzpx[k] - if x <= 0xff and zpx then + local zpx,zpv = opzpx[k], zeropage(x) + if zpv and zpx then ins.size = 2 ins.cycles = zpx.cycles - ins.bin = function() return { zpx.opc, x } end + ins.bin = function() return { zpx.opc, zpv } end return 2 end ins.size = 3 @@ -976,7 +984,7 @@ for k,_ in pairs(opzax) do ins.bin = function() local l65dbg=l65dbg local x = word_normalize(op_eval(late, early)) -- since we assumed absolute on link phase, we must generate absolute in binary - if x <= 0xff and opzpx[k] then io.stderr:write("warning: forcing abx on zpx operand for opcode " .. k .. "\n") end + if zeropage(x) and opzpx[k] then io.stderr:write("warning: forcing abx on zpx operand for opcode " .. k .. "\n") end return { abx.opc, x&0xff, x>>8 } end table.insert(M.section_current.instructions, ins) @@ -1017,7 +1025,7 @@ for k,_ in pairs(opzay) do M[k .. 'zay'] = function(late, early) if type(late) ~= 'function' then local x = (early or 0) + late - if x >= -128 and x <= 0xff then return M[k .. 'zpy'](late, early) end + if zeropage(x) then return M[k .. 'zpy'](late, early) end if x >= -32768 and x <= 0xffff then return M[k .. 'aby'](late, early) end error("value out of word range: " .. x) end @@ -1029,11 +1037,11 @@ for k,_ in pairs(opzay) do if not r then return 3 end size_ref(x) x = word_normalize(x) - local zpy = opzpy[k] - if x <= 0xff and zpy then + local zpy,zpv = opzpy[k], zeropage(x) + if zpv and zpy then ins.size = 2 ins.cycles = zpy.cycles - ins.bin = function() return { zpy.opc, x } end + ins.bin = function() return { zpy.opc, zpv } end return 2 end ins.size = 3 @@ -1043,7 +1051,7 @@ for k,_ in pairs(opzay) do ins.bin = function() local l65dbg=l65dbg local x = word_normalize(op_eval(late, early)) -- since we assumed absolute on link phase, we must generate absolute in binary - if x <= 0xff and opzpy[k] then io.stderr:write("warning: forcing aby on zpy operand for opcode " .. k .. "\n") end + if zeropage(x) and opzpy[k] then io.stderr:write("warning: forcing aby on zpy operand for opcode " .. k .. "\n") end return { aby.opc, x&0xff, x>>8 } end table.insert(M.section_current.instructions, ins) diff --git a/README.md b/README.md index 33e7787..7913995 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,8 @@ Check if `v` is within long range, call `error` if it is not, or convert negativ `pcall_za`: ...unless this field is set to system's `pcall`. Defaults to module's `pcall`. This field is used only by the `za*` (`zab`, `zax`, `zay`) virtual addressing modes, to discriminate between zeropage and absolute addressing. +`zeropage`: a function with one number parameter, returning its zeropage byte value if it is within zero/direct page addressing range, nothing otherwise. Set by default to page [0x0000, 0x00ff]. + `symbols`: list of symbols, resolved or not. Values can be anything before the resolve phase, but must be numbers after (except for the metatable fields). Set as the metatable of the 6502 module, which itself should be set as the metatable of the current `_ENV` environment. `locations`: list of all the registered locations. @@ -336,7 +338,7 @@ Check if `v` is within long range, call `error` if it is not, or convert negativ `id()`: return a new unique numeric identifier. `stats`: a table of statistics regarding the build: - * `cycles`: the total 6502 cycle count of the program, considering no branch is taken and no page is crossed. + * `cycles`: the total 6502 cycle count of the program, assuming no branch is taken and no page is crossed. * `used`: the total ROM bytes actually used by the program. * `unused`: total empty ROM space. * `resolved_count`: number of symbols resolved during resolve phase. diff --git a/pce.l65 b/pce.l65 new file mode 100644 index 0000000..ec716cf --- /dev/null +++ b/pce.l65 @@ -0,0 +1,5 @@ +-- set cpu to HuC6280 +cpu = require "6502" +setmetatable(_ENV, cpu) +cpu.zeropage = function(x) if x >= 0x2000 and x <= 0x20ff then return x&0xff end end +