Added dead stripping.

This commit is contained in:
g012 2017-09-23 23:42:32 +02:00
parent 7eabbe80a6
commit 3f52d2d329
3 changed files with 216 additions and 61 deletions

124
6502.lua
View File

@ -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

131
l65.lua
View File

@ -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

22
vcs.lua
View File

@ -50,7 +50,7 @@ vcs = {
HMCLR = 0x2b, -- <strobe> clear horizontal motion registers
CXCLR = 0x2c, -- <strobe> 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
]]