From 3f52d2d3295bec02125df04daa7bab960b44f747 Mon Sep 17 00:00:00 2001 From: g012 Date: Sat, 23 Sep 2017 23:42:32 +0200 Subject: [PATCH] Added dead stripping. --- 6502.lua | 124 +++++++++++++++++++++++++++++++++++++++++++--------- l65.lua | 131 ++++++++++++++++++++++++++++++++++++++++--------------- vcs.lua | 22 +++++++--- 3 files changed, 216 insertions(+), 61 deletions(-) diff --git a/6502.lua b/6502.lua index 4b3d218..05d387c 100644 --- a/6502.lua +++ b/6502.lua @@ -4,13 +4,43 @@ local symbols={} M.symbols=symbols local locations={} M.locations=locations local stats={} M.stats=stats setmetatable(stats, stats) +M.strip = true -- set to false to disable dead stripping of relocatable sections +M.pcall = pcall -- set to empty function returning false to disable eval during compute_size() +-- set to pcall directly if you want to keep ldazab/x/y eval during compute_size() even if +-- disabled for other parts (required to distinguish automatically between zp/abs addressing) +M.pcall_za = function(...) return M.pcall(...) end + M.__index = M +M.__newindex = function(t,k,v) + local kk = k + if type(k) == 'string' and k:sub(1,1) == '_' and M.label_current then + kk = M.label_current .. k + end + if symbols[kk] then error("attempt to modify symbol " .. k) end + rawset(t,k,v) +end symbols.__index = symbols setmetatable(M, symbols) M.link = function() if stats.unused then return end + if M.strip then + symbols.__index = function(tab,key) + local val = rawget(symbols, key) + if type(val) == 'table' and val.type == 'section' then + val.refcount = (val.refcount or 0) + 1 + end + return val + end + end + for _,location in ipairs(locations) do + for _,section in ipairs(location.sections) do + section:compute_size() + end + end + symbols.__index = symbols + stats.used = 0 stats.unused = 0 stats.cycles = 0 @@ -37,13 +67,19 @@ M.link = function() local section_count = #sections location.cycles=0 location.used=0 for ix,section in ipairs(sections) do - section:compute_size() location.cycles = location.cycles + section.cycles location.used = location.used + section.size if section.size == 0 then sections[ix]=nil if not section.org then table.insert(symbols_to_remove, section.label) end - elseif not section.org then table.insert(position_independent_sections, section) end + elseif not section.org then + if M.strip and not section.refcount then + sections[ix]=nil + table.insert(symbols_to_remove, section.label) + else + table.insert(position_independent_sections, section) + end + end end do local j=0 for i=1,section_count do if sections[i] ~= nil then j=j+1 sections[j],sections[i] = sections[i],sections[j] end @@ -173,7 +209,7 @@ M.resolve = function() -- set local label references resolver local llresolver = { __index = function(tab,key) - if type(key) ~= 'string' or key:sub(1,1) ~= '_' then return nil end + if type(key) ~= 'string' or key:sub(1,1) ~= '_' or not M.label_current then return nil end return symbols[M.label_current .. key] end } setmetatable(symbols, llresolver) @@ -372,6 +408,29 @@ M.endpage = function() constraint.to = #section.instructions end +local size_ref = function(v) + if type(v) == 'string' then v=symbols[v] end + if type(v) == 'table' and v.type == 'section' then v.refcount = 1 + (v.refcount or 0) end +end +local size_dc = function(v) + if type(v) == 'function' then + local r,x = M.pcall(v) + if not r then return v end + v = x + end + size_ref(v) + return v +end +local size_op = function(late, early) + if type(late) == 'function' then + local r,x = M.pcall(late, early or 0) + if not r then return late,early end + late=x early=nil + end + size_ref(late) size_ref(early) + return late,early +end + local byte_normalize = function(v) if v < -0x80 or v > 0xFF then error("value out of byte range: " .. v) end if v < 0 then v = v + 0x100 end @@ -430,6 +489,10 @@ M.byte_impl = function(args, nrm) else error("unsupported type for byte() argument: " .. t .. ", value: " .. v) end end + local size = function() + for i,v in ipairs(data) do data[i] = size_dc(v) end + return #data + end local asbin = function(b) for _,v in ipairs(data) do if type(v) == 'function' then v = v() end @@ -439,7 +502,7 @@ M.byte_impl = function(args, nrm) b[#b+1] = nrm(v) end end - table.insert(M.section_current.instructions, { data=data, size=#data, asbin=asbin }) + table.insert(M.section_current.instructions, { data=data, size=size, asbin=asbin }) end -- byte(...) -- Declare bytes to go into the binary stream. @@ -489,6 +552,10 @@ M.word = function(...) else error("unsupported type for word() argument: " .. t .. ", value: " .. v) end end + local size = function() + for i,v in ipairs(data) do data[i] = size_dc(v) end + return #data*2 + end local asbin = function(b) for _,v in ipairs(data) do if type(v) == 'function' then v = v() end @@ -500,7 +567,7 @@ M.word = function(...) b[#b+1] = v>>8 end end - table.insert(M.section_current.instructions, { data=data, size=#data*2, asbin=asbin }) + table.insert(M.section_current.instructions, { data=data, size=size, asbin=asbin }) end M.long = function(...) @@ -515,6 +582,10 @@ M.long = function(...) else error("unsupported type for long() argument: " .. t .. ", value: " .. v) end end + local size = function() + for i,v in ipairs(data) do data[i] = size_dc(v) end + return #data*4 + end local asbin = function(b) for _,v in ipairs(data) do if type(v) == 'function' then v = v() end @@ -528,7 +599,7 @@ M.long = function(...) b[#b+1] = v>>24 end end - table.insert(M.section_current.instructions, { data=data, size=#data*4, asbin=asbin }) + table.insert(M.section_current.instructions, { data=data, size=size, asbin=asbin }) end local op,cycles_def,xcross_def @@ -561,8 +632,9 @@ cycles_def=2 xcross_def=0 local opimm={ } M.opimm = opimm for k,v in pairs(opimm) do M[k .. 'imm'] = function(late, early) + local size = function() late,early = size_op(late,early) return 2 end local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end - table.insert(M.section_current.instructions, { size=2, cycles=2, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=2, asbin=asbin }) end end cycles_def=3 xcross_def=0 local opzpg={ @@ -574,8 +646,9 @@ cycles_def=3 xcross_def=0 local opzpg={ } M.opzpg = opzpg for k,v in pairs(opzpg) do M[k .. 'zpg'] = function(late, early) + local size = function() late,early = size_op(late,early) return 2 end local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end - table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end cycles_def=4 xcross_def=0 local opabs={ @@ -587,11 +660,12 @@ cycles_def=4 xcross_def=0 local opabs={ } M.opabs = opabs for k,v in pairs(opabs) do M[k .. 'abs'] = function(late, early) + local size = function() late,early = size_op(late,early) return 3 end local asbin = function(b) local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end - table.insert(M.section_current.instructions, { size=3, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end local opzab={} M.opabs = opabs @@ -607,8 +681,9 @@ for k,_ in pairs(opzab) do local abs = opabs[k] local ins = { cycles=abs.cycles } ins.size = function() - local r,x = pcall(late, early or 0) + local r,x = M.pcall_za(late, early or 0) if not r then return 3 end + size_ref(x) x = word_normalize(x) local zpg = opzpg[k] if x <= 0xff and zpg then @@ -637,8 +712,9 @@ cycles_def=4 xcross_def=0 local opzpx={ } M.opzpx = opzpx for k,v in pairs(opzpx) do M[k .. 'zpx'] = function(late, early) + local size = function() late,early = size_op(late,early) return 2 end local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end - table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end cycles_def=4 xcross_def=1 local opabx={ @@ -649,11 +725,12 @@ cycles_def=4 xcross_def=1 local opabx={ } M.opabx = opabx for k,v in pairs(opabx) do M[k .. 'abx'] = function(late, early) + local size = function() late,early = size_op(late,early) return 3 end local asbin = function(b) local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end - table.insert(M.section_current.instructions, { size=3, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end local opzax={} M.opabx = opabx @@ -669,8 +746,9 @@ for k,_ in pairs(opzax) do local abx = opabx[k] local ins = { cycles=abx.cycles } ins.size = function() - local r,x = pcall(late, early or 0) + local r,x = M.pcall_za(late, early or 0) if not r then return 3 end + size_ref(x) x = word_normalize(x) local zpx = opzpx[k] if x <= 0xff and zpx then @@ -698,8 +776,9 @@ cycles_def=4 xcross_def=0 local opzpy={ } M.opzpy = opzpy for k,v in pairs(opzpy) do M[k .. 'zpy'] = function(late, early) + local size = function() late,early = size_op(late,early) return 2 end local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end - table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end cycles_def=4 xcross_def=1 local opaby={ @@ -710,11 +789,12 @@ cycles_def=4 xcross_def=1 local opaby={ } M.opaby = opaby for k,v in pairs(opaby) do M[k .. 'aby'] = function(late, early) + local size = function() late,early = size_op(late,early) return 3 end local asbin = function(b) local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end - table.insert(M.section_current.instructions, { size=3, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end local opzay={} M.opaby = opaby @@ -730,8 +810,9 @@ for k,_ in pairs(opzay) do local aby = opaby[k] local ins = { cycles=aby.cycles } ins.size = function() - local r,x = pcall(late, early or 0) + local r,x = M.pcall_za(late, early or 0) if not r then return 3 end + size_ref(x) x = word_normalize(x) local zpy = opzpy[k] if x <= 0xff and zpy then @@ -763,7 +844,7 @@ for k,v in pairs(oprel) do local op = { cycles=2 } op.size = function() offset = section.size - op.size=2 + label = size_dc(label) return 2 end op.asbin = function(b) @@ -787,11 +868,12 @@ cycles_def=5 xcross_def=0 local opind={ } M.opind = opind for k,v in pairs(opind) do M[k .. 'ind'] = function(late, early) + local size = function() late,early = size_op(late,early) return 3 end local asbin = function(b) local x = op_eval_word(late,early) b[#b+1]=v.opc b[#b+1]=x&0xff b[#b+1]=x>>8 end - table.insert(M.section_current.instructions, { size=3, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end cycles_def=6 xcross_def=0 local opinx={ @@ -801,8 +883,9 @@ cycles_def=6 xcross_def=0 local opinx={ } M.opinx = opinx for k,v in pairs(opinx) do M[k .. 'inx'] = function(late, early) + local size = function() late,early = size_op(late,early) return 2 end local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end - table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end cycles_def=5 xcross_def=1 local opiny={ @@ -812,8 +895,9 @@ cycles_def=5 xcross_def=1 local opiny={ } for k,v in pairs(opiny) do M[k .. 'iny'] = function(late, early) + local size = function() late,early = size_op(late,early) return 2 end local asbin = function(b) b[#b+1]=v.opc b[#b+1]=op_eval_byte(late,early) end - table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, asbin=asbin }) + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, asbin=asbin }) end end diff --git a/l65.lua b/l65.lua index 1e1c676..a668ac0 100644 --- a/l65.lua +++ b/l65.lua @@ -54,7 +54,7 @@ local Keywords_6502 = { 'lax', 'rla', 'rra', 'sax', 'sbx', 'sha', 'shs', 'shx', 'shy', 'slo', 'sre', } -local Registers_6502 = { a=8, x=8, y=8 } +local Registers_6502 = { a=8, x=8, y=8, s=8 } local syntax6502_on local function syntax6502(on) @@ -470,8 +470,8 @@ local function LexLua(src) onoff(syntax6502) toEmit = {Type = 'Symbol', Data = ';'} elseif dat == 'syntax6502k' then - onoff(syntax6502k) - toEmit = {Type = 'Symbol', Data = ';'} + onoff(function() end) + toEmit = {Type = 'Keyword', Data = 'syntax6502k_' .. opt} elseif dat == 'encapsulate' then onoff(function() end) toEmit = {Type = 'Keyword', Data = 'encapsulate_' .. opt} @@ -494,35 +494,7 @@ local function LexLua(src) if Keywords[dat] then toEmit = {Type = 'Keyword', Data = dat} else - if syntax6502k_on then - local i=0 - while true do c=peek(i) if not Spaces[c] then break end i=i+1 end - if c == '=' then - local idents,ident = {dat} - repeat - i = i+1 - ident,i,c = peek_ident(i) - if not ident then break end - table.insert(idents, ident) - until c ~= '=' - local reg = idents[#idents] - if Registers_6502[reg] then - -- list of assignements ends with =a, =x, or =y - get_n(i) - -- TODO find a=expr, emit lda expr - local st = 'st'..reg - idents[#idents] = nil - toEmit = {} - for k,v in ipairs(idents) do - table.insert(toEmit, { Type='Keyword', Data=st }) - table.insert(toEmit, { Type='Ident', Data=v }) - end - end - end - end - if not toEmit then - toEmit = {Type = 'Ident', Data = dat} - end + toEmit = {Type = 'Ident', Data = dat} end elseif Digits[c] or (peek() == '.' and Digits[peek(1)]) then @@ -1254,6 +1226,12 @@ local function ParseLua(src) end + local pragma_map = { + encapsulate_on = function() opcode_arg_encapsulate(true) end, + encapsulate_off = function() opcode_arg_encapsulate(false) end, + syntax6502k_on = function() syntax6502k(true) end, + syntax6502k_off = function() syntax6502k(false) end, + } local function ParseStatement(scope) local stat = nil local tokenList = {} @@ -1262,6 +1240,7 @@ local function ParseLua(src) local p = function(t,n) return function() return '<' .. t .. string.rep(' ', 7-#t) .. ' ' .. n .. ' >' end end local t = function(t,s,w) return { Type=t, Data=s, Print=p(t,s), Char=c(), Line=l(), LeadingWhite=w or {} } end local no_encapsulation = { Function=true, NumberExpr=true, StringExpr=true } + local reg = function(e) local t=e.Tokens[1] if t then return Registers_6502[t.Data] end end local function emit_call(params) local name,args,inverse_encapsulate = params.name, params.args or {}, params.inverse_encapsulate @@ -1339,8 +1318,11 @@ local function ParseLua(src) end -- parser pragmas - if tok:ConsumeKeyword('encapsulate_on') then opcode_arg_encapsulate(true) - elseif tok:ConsumeKeyword('encapsulate_off') then opcode_arg_encapsulate(false) + do + ::search_pragma:: + for k,v in pairs(pragma_map) do + if tok:ConsumeKeyword(k) then v() goto search_pragma end + end end -- label declarations @@ -1387,10 +1369,10 @@ local function ParseLua(src) -- declare data if not stat then if tok:ConsumeKeyword('dc', tokenList) then - if not tok:ConsumeSymbol('.', tokenList) then GenerateError("'.' expected") end + if not tok:ConsumeSymbol('.', tokenList) then return false, GenerateError("'.' expected") end local suffix_list = { b='byte', w='word', l='long' } local func = suffix_list[tok:Get(tokenList).Data] - if not func then GenerateError("'b', 'w' or 'l' expected") end + if not func then return false, GenerateError("'b', 'w' or 'l' expected") end local inverse_encapsulate={} inverse_encapsulate[1] = tok:ConsumeSymbol('!', tokenList) local st, expr = ParseExpr(scope) @@ -1414,6 +1396,83 @@ local function ParseLua(src) stat = emit_call{name=func, args=exprs, inverse_encapsulate=inverse_encapsulate} end end + -- k65 style syntax + if not stat and syntax6502k_on then + -- *=[a,x,y,s]=? + do + tok:Save() + local exprs = {} + while true do + local st, expr = ParseExpr(scope) + if not st then break end + table.insert(exprs, expr) + if not tok:ConsumeSymbol('=', tokenList) then break end + end + if #exprs < 2 then + tok:Restore() + else + local hasreg + for e in exprs do hasreg=reg(e) if hasreg then break end end + if not hasreg then + tok:Restore() + else + tok:Commit() + local skip + for i=#exprs-1,1,-1 do + if skip then + skip = false + else + local src,dst = exprs[i+1],exprs[i] + local src_reg,dst_reg = reg(src),reg(dst) + local op,arg + if src_reg=='s' then + if dst_reg=='x' then + op = 'tsximp' + end + elseif dst_reg=='s' then + if src_reg=='x' then + op = 'txsimp' + end + elseif src_reg and not dst_reg then + arg = i + op = 'st'..src_reg + elseif dst_reg and not src_reg then + arg = i+1 + if dst_reg=='x' and i > 1 and reg(exprs[i-1])=='a' then + op='lax' skip=true + else + op = 'ld'..src_reg + end + end + if not op then + return false, GenerateError("no opcode for assignment") + end + if arg then + arg = exprs[arg] + end + end + end + end + + local t,r,rexpr,rexpr_ix + rexpr_ix=#exprs rexpr=exprs[rexprs_ix] t=#rexpr.Tokens[1] if t then r=Registers_6502[t.Data] end + if not r then rexpr_ix=#exprs-1 rexpr=exprs[rexprs_ix] t=#rexpr.Tokens[1] if t then r=Registers_6502[t.Data] end end + if r then + end + end + end + + if tok:Is('Ident') and tok:Peek(1).Data == '=' then + local reg = tok:Peek(2).Data + if Registers_6502[reg] then + local st, arg = ParseExpr(scope) + tok:Get(tokenList) tok:Get(tokenList) + arg.Tokens[1].LeadingWhite,tokenList[1].LeadingWhite = tokenList[1].LeadingWhite,arg.Tokens[1].LeadingWhite + stat = emit_call{name = 'st'..reg..'zab', args = {arg}} + end + end + end + -- 6502 opcodes if not stat then local mod_st, mod_expr, inverse_encapsulate diff --git a/vcs.lua b/vcs.lua index 3d7389d..7022d22 100644 --- a/vcs.lua +++ b/vcs.lua @@ -50,7 +50,7 @@ vcs = { HMCLR = 0x2b, -- clear horizontal motion registers CXCLR = 0x2c, -- clear collision latches= 0x20 - -- TIA read on,ly + -- TIA read only CXM0P = 0x30, -- 11...... read collision M0-P1, M0-P0 (Bit 7 --6) CXM1P = 0x31, -- 11...... read collision M1-P0, M1-P1 CXP0FB = 0x32, -- 11...... read collision P0-PF, P0-BL @@ -83,8 +83,20 @@ do local symbols = cpu.symbols for k,v in pairs(vcs) do symbols[k] = v end end --- forbid globals of same key as system address constants -cpu.__newindex = function(t,k,v) - if vcs[k] then error("attempt to modify read only symbol " .. k) end - rawset(t,k,v) + +--[[ TODO enable this when lua load() is changed +function bank_stubs(count, hotspot) + function switchbank(i) bit 0x1000+hotspot+i end + local base = 0x10000 - (count << 12) + for bi=0,count-1 do + local o = base+(bi<<12) + _ENV['bank' .. bi] = location{o, o+0xfff, rorg=0xf000} + local start=section{"entry"..bi, org=o+hotspot-6} switchbank(0) if bi==0 then jmp main end + section{"switchtab"..bi, org=o+hotspot} for i=1,count do byte(0) end + section{"vectors"..bi, org=o+0xffc} word(start,start) + end end +function f8() bank_stubs(2, 0xff8) end +function f6() bank_stubs(4, 0xff6) end +function f4() bank_stubs(8, 0xff4) end +]]