mirror of
https://github.com/g012/l65.git
synced 2025-01-03 03:32:53 +00:00
Added optional far keyword with encapsulation for far calls of not yet declared labels.
This commit is contained in:
parent
27887f42c6
commit
462c4a3b8d
4
6502.lua
4
6502.lua
@ -6,6 +6,8 @@ local sections={} M.sections=sections
|
||||
local relations={} M.relations=relations
|
||||
local stats={} M.stats=stats setmetatable(stats, stats)
|
||||
|
||||
local before_link={} M.before_link=before_link
|
||||
|
||||
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
|
||||
@ -30,6 +32,8 @@ local id = function() id_=id_+1 return id_ end M.id=id
|
||||
M.link = function()
|
||||
if stats.unused then return end
|
||||
|
||||
for _,v in ipairs(before_link) do v() end
|
||||
|
||||
if M.strip then
|
||||
symbols.__index = function(tab,key)
|
||||
local val = rawget(symbols, key)
|
||||
|
121
l65.lua
121
l65.lua
@ -76,6 +76,7 @@ local function opcode_arg_encapsulate(on)
|
||||
end
|
||||
opcode_arg_encapsulate(true)
|
||||
|
||||
local opcode_encapsulate = {} -- additionnal opcode, to have basic encapsulation (function(a) return a end)
|
||||
local opcode_implied = lookupify{
|
||||
'asl', 'brk', 'clc', 'cld', 'cli', 'clv', 'dex', 'dey',
|
||||
'inx', 'iny', 'lsr', 'nop', 'pha', 'php', 'pla', 'plp',
|
||||
@ -152,6 +153,21 @@ local opcode_relative = lookupify{
|
||||
'bcc', 'bcs', 'beq', 'bmi', 'bne', 'bpl', 'bvc', 'bvs',
|
||||
}
|
||||
|
||||
local addressing_map = {
|
||||
imp = opcode_implied,
|
||||
imm = opcode_immediate,
|
||||
zpg = opcode_zeropage,
|
||||
zpx = opcode_zeropage_x,
|
||||
zpy = opcode_zeropage_y,
|
||||
abs = opcode_absolute,
|
||||
abx = opcode_absolute_x,
|
||||
aby = opcode_absolute_y,
|
||||
ind = opcode_indirect,
|
||||
inx = opcode_indirect_x,
|
||||
iny = opcode_indirect_y,
|
||||
rel = opcode_relative,
|
||||
}
|
||||
|
||||
local Scope = {
|
||||
new = function(self, parent)
|
||||
local s = {
|
||||
@ -459,12 +475,13 @@ local function LexLua(src)
|
||||
if char == 1 and peek_n(7) == '#pragma' then
|
||||
get_n(7)
|
||||
local dat,opt = get_word()
|
||||
local onoff = function(f)
|
||||
local onoff = function(f, noerr)
|
||||
opt = get_word()
|
||||
if opt == 'on' then f(true)
|
||||
elseif opt == 'off' then f(false)
|
||||
else generateError("invalid option for pragma " .. dat .. ", expected: [on,off]")
|
||||
elseif not noerr then generateError("invalid option for pragma " .. dat .. ", expected: [on,off]")
|
||||
end
|
||||
return opt
|
||||
end
|
||||
if dat == 'syntax6502' then
|
||||
onoff(syntax6502)
|
||||
@ -473,8 +490,23 @@ local function LexLua(src)
|
||||
onoff(function() end)
|
||||
toEmit = {Type = 'Keyword', Data = 'syntax6502k_' .. opt}
|
||||
elseif dat == 'encapsulate' then
|
||||
onoff(function() end)
|
||||
toEmit = {Type = 'Keyword', Data = 'encapsulate_' .. opt}
|
||||
local opcode = onoff(function() end, true)
|
||||
if opcode then
|
||||
opcode_encapsulate[opcode] = get_word()
|
||||
table.insert(Keywords_6502, opcode)
|
||||
Keywords[opcode] = syntax6502_on
|
||||
toEmit = {Type = 'Symbol', Data = ';'}
|
||||
else
|
||||
toEmit = {Type = 'Keyword', Data = 'encapsulate_' .. opt}
|
||||
end
|
||||
elseif dat == 'add_opcode' then
|
||||
local opcode,addressing = get_word(),get_word()
|
||||
local map = addressing_map[addressing]
|
||||
if not map then generateError("invalid addressing for pragma add_opcode: " .. addressing .. " (opcode: " .. opcode .. ")") end
|
||||
map[opcode] = true
|
||||
table.insert(Keywords_6502, opcode)
|
||||
Keywords[opcode] = syntax6502_on
|
||||
toEmit = {Type = 'Symbol', Data = ';'}
|
||||
else generateError("unknown pragma: " .. dat)
|
||||
end
|
||||
|
||||
@ -1271,32 +1303,44 @@ local function ParseLua(src, src_name)
|
||||
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 _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 = 'CallExpr', Base = fvarexpr, Arguments = {args[1]}, Tokens = { t('Symbol', '('), t('Symbol', ')') }
|
||||
local inner_call_scope,inner_call = CreateScope(op_var.Variable.Scope)
|
||||
if params.basic then
|
||||
local inner_call_body = {
|
||||
AstType='StatList', Scope=CreateScope(inner_call_scope), Tokens={}, Body={
|
||||
{ AstType='ReturnStatement', Arguments={args[1]}, Tokens={ t('Keyword', 'return', {space}) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
local inner_call_body = {
|
||||
AstType='StatList', Scope=CreateScope(inner_call_scope), Tokens={}, Body={
|
||||
{ AstType='ReturnStatement', Arguments={inner_add}, Tokens={ t('Keyword', 'return', {space}) } }
|
||||
inner_call = {
|
||||
AstType='Function', VarArg=false, IsLocal=true, Scope=inner_call_scope, Body=inner_call_body, Arguments={},
|
||||
Tokens={ t('Keyword', 'function'), t('Symbol', '('), t('Symbol', ')'), t('Keyword', 'end', {space}) }
|
||||
}
|
||||
}
|
||||
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 },
|
||||
{ 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}) }
|
||||
}
|
||||
else
|
||||
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 = 'CallExpr', Base = fvarexpr, Arguments = {args[1]}, Tokens = { t('Symbol', '('), t('Symbol', ')') }
|
||||
}
|
||||
}
|
||||
local inner_call_body = {
|
||||
AstType='StatList', Scope=CreateScope(inner_call_scope), Tokens={}, Body={
|
||||
{ AstType='ReturnStatement', Arguments={inner_add}, Tokens={ t('Keyword', 'return', {space}) } }
|
||||
}
|
||||
}
|
||||
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 },
|
||||
{ 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}) }
|
||||
}
|
||||
end
|
||||
args[1] = inner_call
|
||||
end
|
||||
local exp_call = {
|
||||
@ -1484,7 +1528,14 @@ local function ParseLua(src, src_name)
|
||||
local mod_st, mod_expr, inverse_encapsulate
|
||||
for _,op in pairs(Keywords_6502) do
|
||||
if tok:ConsumeKeyword(op, tokenList) then
|
||||
if opcode_relative[op] then
|
||||
if opcode_encapsulate[op] then
|
||||
inverse_encapsulate = tok:ConsumeSymbol('!', tokenList)
|
||||
local st, expr = ParseExpr(scope) if not st then return false, expr end
|
||||
local paren_open_whites = {}
|
||||
if inverse_encapsulate then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_open_whites, v) end end
|
||||
for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end
|
||||
stat = emit_call{name=opcode_encapsulate[op], args={expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites, basic=true} break
|
||||
elseif opcode_relative[op] then
|
||||
local st, expr = ParseExpr(scope) if not st then return false, expr end
|
||||
if expr.AstType == 'VarExpr' and expr.Variable.IsGlobal then
|
||||
expr = as_string_expr(expr, expr.Name)
|
||||
@ -2490,6 +2541,8 @@ l65.report = function(success, ...)
|
||||
os.exit(-1)
|
||||
end
|
||||
l65.msghandler = function(msg)
|
||||
local o = function(s) io.stderr:write(s) end
|
||||
|
||||
msg = tostring(msg)
|
||||
msg = msg:gsub('%[string "(.-%.l65)"%]', '%1') -- [string "xxx.l65"] -> xxx.l65
|
||||
local trace_cur = debug.traceback(nil, 2)
|
||||
@ -2503,7 +2556,6 @@ l65.msghandler = function(msg)
|
||||
local n,v = debug.getlocal(i, j)
|
||||
if not n then break end
|
||||
if n == 'l65dbg' then
|
||||
local o = function(s) io.stderr:write(s) end
|
||||
o(string.format("%s\n", msg))
|
||||
if trace_cur:find("in local 'late'") then
|
||||
local lines = {}
|
||||
@ -2511,15 +2563,12 @@ l65.msghandler = function(msg)
|
||||
if line:find("in local 'late'") then break end
|
||||
table.insert(lines, line)
|
||||
end
|
||||
lines = table.concat(lines,'\n')
|
||||
lines = lines:gsub("^%s*\r?\n$", '')
|
||||
io.stderr:write(lines .. '\n')
|
||||
o(table.concat(lines,'\n'))
|
||||
end
|
||||
local trace = v.trace:match(".-\n(.*)\n.-'xpcall'")
|
||||
trace = trace:gsub('%[string "(.-%.l65)"%]', '%1')
|
||||
trace = trace:gsub('stack traceback:', '')
|
||||
trace = trace:gsub("^%s*\r?\n$", '')
|
||||
io.stderr:write(trace .. '\n')
|
||||
o(trace .. '\n')
|
||||
os.exit(-2)
|
||||
end
|
||||
j = j + 1
|
||||
@ -2528,7 +2577,7 @@ l65.msghandler = function(msg)
|
||||
end
|
||||
|
||||
trace_cur = trace_cur:match(".-\n(.*)\n.-'xpcall'")
|
||||
io.stderr:write(string.format("%s\n%s\n", msg, trace_cur))
|
||||
o(string.format("%s\n%s\n", msg, trace_cur))
|
||||
os.exit(-3)
|
||||
end
|
||||
do
|
||||
|
@ -1,17 +1,18 @@
|
||||
require'vcs'
|
||||
#pragma encapsulate far farcall
|
||||
|
||||
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
|
||||
overscan() vblank() screen_begin() far kernel screen_end() jmp _frame
|
||||
|
||||
location(bank_fx)
|
||||
@@kernel
|
||||
ldx#0xd0 @_loop sta WSYNC stx COLUBK dex bne _loop rts
|
||||
|
||||
;
|
||||
writebin(filename..'.bin')
|
||||
|
34
vcs.l65
34
vcs.l65
@ -184,20 +184,24 @@ screen = function(f) screen_begin() if f then f() end screen_end() end
|
||||
|
||||
-- for mappers that swap banks in place
|
||||
-- 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[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)
|
||||
relate(stub_caller, stub_callee, 3)
|
||||
if not stub then far_stubs[dst] = {} end
|
||||
far_stubs[dst][loc_src] = stub_caller
|
||||
local far_stubs = {} _ENV.far_stubs=far_stubs
|
||||
farcall = function(dst)
|
||||
local loc_src = location_current
|
||||
local create_stubs = function()
|
||||
if type(dst) == 'function' then dst = dst() end
|
||||
local stub,loc_dst = far_stubs[dst],dst.section.location
|
||||
if not (stub and stub[loc_src]) then
|
||||
location(loc_src)
|
||||
local stub_caller = section() switchrom(loc_dst.rom) skip(6) rts
|
||||
location(loc_dst)
|
||||
local stub_callee = section() jsr dst switchrom(loc_src.rom)
|
||||
relate(stub_caller, stub_callee, 3)
|
||||
if not stub then far_stubs[dst] = {} end
|
||||
far_stubs[dst][loc_src] = stub_caller
|
||||
end
|
||||
end
|
||||
-- create stubs at the end to get to the referenced labels
|
||||
table.insert(before_link, create_stubs)
|
||||
jsr far_stubs[dst][loc_src]
|
||||
end
|
||||
|
||||
@ -216,7 +220,6 @@ end
|
||||
|
||||
local bank_stubs = function(irq, count, hotspot, entry)
|
||||
function switchrom(i) assert(i>=0 and i<count) bit 0x1000+hotspot+i end
|
||||
_ENV.far = far
|
||||
local base = 0x10000 - (count << 12)
|
||||
for bi=0,count-1 do
|
||||
local o = base+(bi<<12)
|
||||
@ -301,7 +304,6 @@ local bank_stubs2 = function(irq, hotspot0, hotspot1)
|
||||
elseif i==1 then bit hotspot1
|
||||
else error("invalid rom index: " .. i) end
|
||||
end
|
||||
_ENV.far = far
|
||||
local base = 0xe000
|
||||
for bi=0,1 do
|
||||
local o = base+(bi<<12)
|
||||
@ -314,7 +316,6 @@ mappers.UA = function(irq) bank_stubs2(irq, 0x220, 0x240) end
|
||||
mappers['0840'] = function(irq) bank_stubs2(irq, 0x800, 0x840) end
|
||||
mappers.SB = function(count, irq)
|
||||
function switchrom(i) assert(i>=0 and i<count) bit 0x800+i end
|
||||
_ENV.far = far
|
||||
for bi=0,count-1 do
|
||||
local o = bi*0x1000 + 0x1000
|
||||
_ENV['rom' .. bi] = location{o, o+0xfff, rorg=0xf000}
|
||||
@ -345,7 +346,6 @@ end
|
||||
|
||||
mappers.X07 = function(irq)
|
||||
function switchrom(i) assert(i>=0 and i<16) bit 0x80b+(i<<4) end
|
||||
_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
|
||||
|
@ -572,6 +572,8 @@ syn match l65Opcode /\<shy\>/
|
||||
syn match l65Opcode /\<slo\%(.[bw]\)\=\>/
|
||||
syn match l65Opcode /\<sre\%(.[bw]\)\=\>/
|
||||
|
||||
syn match l65Opcode /\<far\>/
|
||||
|
||||
" Define the default highlighting.
|
||||
" For version 5.7 and earlier: only when not done already
|
||||
" For version 5.8 and later: only when an item doesn't have highlighting yet
|
||||
|
Loading…
Reference in New Issue
Block a user