diff --git a/6502.lua b/6502.lua index b416b16..cbc8574 100644 --- a/6502.lua +++ b/6502.lua @@ -224,14 +224,14 @@ M.link = function() end end end - table.sort(related_sections, function(a,b) return a[1].size==b[1].size and a[1].idb[1].size end) - for _,section in ipairs(related_sections) do + table.sort(related_sections, function(a,b) return a.size==b.size and a.idb.size end) + for _,section in ipairs(related_sections) do if not section.org then local related,ins = {},table.insert - local function collect(section, offset) - local relatives = relations[section] + local function collect(section_parent, offset) + local relatives = relations[section_parent] if relatives then for relative,relative_offset in pairs(relatives) do - if not related[relative] then + if not related[relative] and relative ~= section then relative_offset = relative_offset + offset related[relative] = relative_offset collect(relative, relative_offset) @@ -240,10 +240,12 @@ M.link = function() end end collect(section, 0) + local location_start = section.location.start local position = position_section(section, function(address, waste, cross, lsb) local waste, cross, lsb = 0, 0, 0 for section,offset in pairs(related) do - local nwaste, ncross, nlsb = check_section_position(section, address+offset) + local section_address = address + (section.location.start - location_start) + offset + local nwaste, ncross, nlsb = check_section_position(section, section_address) if not nwaste then return end waste, cross, lsb = waste+nwaste, cross+ncross, lsb+nlsb end @@ -253,12 +255,12 @@ M.link = function() error("unable to find space for section " .. section.label) end for section,offset in pairs(related) do - section.org = position + offset + section.org = position + (section.location.start - location_start) + offset local chunk,chunk_ix = chunk_from_address(section, section.org) chunk_reserve(section, chunk_ix) symbols[section.label] = section.location.rorg(section.org) end - end + end end for _,location in ipairs(locations) do local position_independent_sections = location.position_independent_sections @@ -401,7 +403,7 @@ end M.location = function(start, finish) local location if type(start) ~= 'table' then - location = { type='location', start=start, finish=finish } + location = { start=start, finish=finish } else if start.type == 'location' then for _,v in ipairs(locations) do if v == start then @@ -418,6 +420,7 @@ M.location = function(start, finish) location.rorg = function(x) return x+offset end end end + location.type = 'location' location.sections = {} if not location.rorg then location.rorg = function(x) return x end end local size = (location.finish or math.huge) - location.start + 1 @@ -486,10 +489,10 @@ end -- If offset1 is omitted, -offset2 is used. M.relate = function(section1, section2, offset, offset2) local rel1 = relations[section1] or {} - rel1[section2] = offset2 or offset + rel1[section2] = (offset2 or offset) or 0 relations[section1] = rel1 local rel2 = relations[section2] or {} - rel2[section1] = offset2 and offset + rel2[section1] = (offset2 and offset) or -rel1[section2] relations[section2] = rel2 section1.related = true section2.related = true @@ -508,6 +511,7 @@ M.label = function(name) end if symbols[name] then error("duplicate symbol: " .. name) end symbols[name] = label + label.label = name label.size = function() offset = section.size label.size = 0 @@ -558,6 +562,14 @@ M.sleep = function(cycles, noillegal) for i=1,cycles/2 do nopimp() end end +local op_resolve = function(v) + if type(v) == 'function' then v=v() end + if type(v) == 'table' and v.label then v = symbols[v.label] end + if type(v) == 'string' then v = symbols[v] end + if type(v) ~= 'number' then error("unresolved symbol: " .. tostring(v)) end + return v +end + local size_ref = function(v) if type(v) == 'string' then v=symbols[v] end if type(v) == 'table' and v.type == 'label' then v.section.refcount = 1 + (v.section.refcount or 0) end @@ -572,7 +584,7 @@ local size_dc = function(v) end local size_op = function(late, early) if type(late) == 'function' then - local r,x = M.pcall(late, early or 0) + local r,x = M.pcall(late, early or 0, op_resolve) if not r or not x then return late,early end late=x early=nil end @@ -769,7 +781,7 @@ op = function(code, cycles, extra_on_crosspage) end local op_eval = function(late, early) local x = early or 0 - return type(late) == 'function' and late(x) or x+late + 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_word = function(late, early) return word_normalize(op_eval(late, early)) end @@ -845,7 +857,7 @@ for k,_ in pairs(opzab) do local abs = opabs[k] local ins = { cycles=abs.cycles } ins.size = function() local l65dbg=l65dbg - local r,x = M.pcall_za(late, early or 0) + local r,x = M.pcall_za(op_eval, late, early) if not r then return 3 end size_ref(x) x = word_normalize(x) @@ -861,9 +873,9 @@ for k,_ in pairs(opzab) do return 3 end ins.bin = function() local l65dbg=l65dbg - local x = word_normalize(late(early or 0)) + 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) end + if x <= 0xff 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) @@ -913,7 +925,7 @@ for k,_ in pairs(opzax) do local abx = opabx[k] local ins = { cycles=abx.cycles } ins.size = function() local l65dbg=l65dbg - local r,x = M.pcall_za(late, early or 0) + local r,x = M.pcall_za(op_eval, late, early) if not r then return 3 end size_ref(x) x = word_normalize(x) @@ -929,9 +941,9 @@ for k,_ in pairs(opzax) do return 3 end ins.bin = function() local l65dbg=l65dbg - local x = word_normalize(late(early or 0)) + 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) end + if x <= 0xff 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) @@ -980,7 +992,7 @@ for k,_ in pairs(opzay) do local aby = opaby[k] local ins = { cycles=aby.cycles } ins.size = function() local l65dbg=l65dbg - local r,x = M.pcall_za(late, early or 0) + local r,x = M.pcall_za(op_eval, late, early) if not r then return 3 end size_ref(x) x = word_normalize(x) @@ -996,9 +1008,9 @@ for k,_ in pairs(opzay) do return 3 end ins.bin = function() local l65dbg=l65dbg - local x = word_normalize(late(early or 0)) + 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) end + if x <= 0xff 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/l65.lua b/l65.lua index 4709218..10f3d0b 100644 --- a/l65.lua +++ b/l65.lua @@ -1270,15 +1270,18 @@ local function ParseLua(src, src_name) end end elseif #args > 0 and ( (encapsulate and not inverse_encapsulate) or (not encapsulate and inverse_encapsulate) ) and not no_encapsulation[args[1].AstType] then - -- opcode arguments of type (late, early), where only late is to be encapsulated with a _o parameter to be set to early and added to late + -- opcode arguments of type (late, early), where only late is to be encapsulated with _o parameter to be set to early and added to _f(late) local inner_call_scope = CreateScope(op_var.Variable.Scope) + local fvarexpr = { + AstType='VarExpr', Name='_f', Variable={ Name='_f', Scope=CreateScope(inner_call_scope) }, Tokens = { t('Ident', '_f') } + } local inner_add = { AstType='BinopExpr', Op='+', OperatorPrecedence=10, Tokens={ t('Symbol', '+') }, Lhs = { AstType='VarExpr', Name='_o', Variable={ IsGlobal=false, Name='_o', Scope=inner_call_scope }, Tokens={ t('Ident', '_o', {space}) } }, Rhs = { - AstType='Parentheses', Inner=args[1], Tokens={ t('Symbol', '('), t('Symbol', ')') } + AstType = 'CallExpr', Base = fvarexpr, Arguments = {args[1]}, Tokens = { t('Symbol', '('), t('Symbol', ')') } } } local inner_call_body = { @@ -1288,8 +1291,11 @@ local function ParseLua(src, src_name) } local inner_call = { AstType='Function', VarArg=false, IsLocal=true, Scope=inner_call_scope, Body=inner_call_body, - Arguments={ { IsGlobal=false, Name='_o', Scope=inner_call_scope } }, - Tokens={ t('Keyword', 'function'), t('Symbol', '('), t('Ident', '_o'), t('Symbol', ')'), t('Keyword', 'end', {space}) } + Arguments={ + { IsGlobal=false, Name='_o', Scope=inner_call_scope }, + { IsGlobal=false, Name='_f', Scope=inner_call_scope }, + }, + Tokens={ t('Keyword', 'function'), t('Symbol', '('), t('Ident', '_o'), t('Symbol', ','), t('Ident', '_f'), t('Symbol', ')'), t('Keyword', 'end', {space}) } } args[1] = inner_call end @@ -2505,12 +2511,15 @@ l65.msghandler = function(msg) if line:find("in local 'late'") then break end table.insert(lines, line) end - print(table.concat(lines,'\n')) + lines = table.concat(lines,'\n') + lines = lines:gsub("^%s*\r?\n$", '') + io.stderr:write(lines .. '\n') end local trace = v.trace:match(".-\n(.*)\n.-'xpcall'") trace = trace:gsub('%[string "(.-%.l65)"%]', '%1') trace = trace:gsub('stack traceback:', '') - print(trace) + trace = trace:gsub("^%s*\r?\n$", '') + io.stderr:write(trace .. '\n') os.exit(-2) end j = j + 1 diff --git a/samples/vcs0.l65 b/samples/vcs0.l65 index 9d0867d..3986e88 100644 --- a/samples/vcs0.l65 +++ b/samples/vcs0.l65 @@ -9,7 +9,8 @@ end init() @_frame overscan() vblank() screen(kernel) jmp _frame -; + +; -- needed if last instruction is implied writebin(filename..'.bin') writesym(filename..'.sym') print(stats) diff --git a/samples/vcs2.l65 b/samples/vcs2.l65 new file mode 100644 index 0000000..91aa6fb --- /dev/null +++ b/samples/vcs2.l65 @@ -0,0 +1,19 @@ +require'vcs' + +mappers.F4() +local bank_core,bank_fx = rom0,rom1 + +location(bank_fx) +@@kernel + ldx#0xd0 @_loop sta WSYNC stx COLUBK dex bne _loop rts + +location(bank_core) +@@main + init() +@_frame + overscan() vblank() screen_begin() far(kernel) screen_end() jmp _frame + +; +writebin(filename..'.bin') +writesym(filename..'.sym') +print(stats) diff --git a/vcs.l65 b/vcs.l65 index 10df10b..2eee5cb 100644 --- a/vcs.l65 +++ b/vcs.l65 @@ -186,16 +186,19 @@ screen = function(f) screen_begin() if f then f() end screen_end() end -- call an asm function into another bank and generate the stubs if needed local far_stubs = {} far_stubs=far_stubs local far = function(dst) + dst.section.refcount = dst.section.refcount + 1 local stub,loc_src,loc_dst = far_stubs[dst],location_current,dst.section.location - if not (stub and stub.stub_caller.location==loc_src and stub.stub_callee.location==loc_dst) then + if not (stub and stub[loc_src]) then local seccur = section_current local stub_caller = section() switchrom(loc_dst.rom) skip(6) rts location(loc_dst) local stub_callee = section() jsr dst switchrom(loc_src.rom) section(seccur) - far_stubs[dst] = relate(stub_caller, stub_callee, 3) + relate(stub_caller, stub_callee, 3) + if not stub then far_stubs[dst] = {} end + far_stubs[dst][loc_src] = stub_caller end - jsr stub_caller + jsr far_stubs[dst][loc_src] end mappers = {} @@ -213,7 +216,7 @@ end local bank_stubs = function(irq, count, hotspot, entry) function switchrom(i) assert(i>=0 and i=0 and i=0 and i<16) bit 0x80b+(i<<4) end - far = far + _ENV.far = far -- map TIA also to 0x40-0x7F: use VSYNC for bank 14, and VSYNC2 for bank 15 vcs.VSYNC2=0x40 cpu.symbols.VSYNC2=0x40 for bi=0,count-1 do