From 608f0b5583d3c284468c284b53d620342cb062dd Mon Sep 17 00:00:00 2001 From: g012 Date: Fri, 8 Sep 2017 13:25:15 +0200 Subject: [PATCH] Finished untested link function. --- 6502.lua | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 124 insertions(+), 11 deletions(-) diff --git a/6502.lua b/6502.lua index 730509a..e12e50e 100644 --- a/6502.lua +++ b/6502.lua @@ -1,5 +1,9 @@ local M = {} +local symbols = {} +local sections = {} +local locations = {} + local byte_normalize = function(v) if v < -128 or v > 255 then error("value out of byte range: " .. v) end if v < 0 then v = v + 0x100 end @@ -21,6 +25,126 @@ local word_emit = function(v, bin) bin[#bin+1] = 0xff & (v // 0x100) end +local link = function() + for _,location in ipairs(locations) do + + local chunk_reserve = function(chunk_ix, chunk, start, size) + if start == chunk.start then + if size == chunk.size then location.chunks[chunk_ix] = nil + else chunk.start=start+size chunk.size=chunk.size-size end + else + if chunk.size - (start - chunk.start) == size then chunk.size = chunk.size - size + else + chunk.size = start - chunk.start + table.insert(location.chunks, chunk_ix+1, { start=start+size, size=chunk.start+chunk.size-(start+size) }) + end + end + end + + -- filter sections list + local position_independent_sections = {} + local symbols_to_remove = {} + for ix,section in ipairs(sections) do + if symbols[section.label] then error("duplicate symbol: " .. section.label) end + symbols[section.label] = section + section:compute_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 + end + for _,v in ipairs(symbols_to_remove) do symbols[v] = nil end + + -- fixed position sections + for section_ix,section in ipairs(sections) do if section.org then + if section.org < location.start or section.org > location.finish then + error("ORG section " .. section.label .. " starts outside container location") + end + for chunk_ix,chunk in ipairs(location.chunks) do + if chunk.start <= section.org and chunk.size - (section.org - chunk.start) >= section.size then + chunk_reserve(chunk_ix, chunk, section.org, section.size) + goto chunk_located + end + end + error("ORG section " .. section.label .. " overflows its location") + ::chunk_located:: + end end + + -- position independent sections + table.sort(position_independent_sections, function(a,b) return a.size < b.size end) + while #position_independent_sections > 0 do + local section = position_independent_sections[1] + local chunks = {} + for _,chunk in ipairs(location.chunks) do + if chunk.size >= section.size then chunks[#chunks+1] = chunk end + end + table.sort(chunks, function(a,b) return a.size < b.size end) + for chunk_ix,chunk in ipairs(chunks) do + local waste,position = math.maxinteger + local usage_lowest = function(start, finish) + local inc=1 + if section.align then + start = (start + section.align - 1) // section.align * section.align + if section.offset then start = start + section.offset end + inc = section.align + end + for address=start,finish,inc do + for _,constraint in ipairs(section.constraints) do + local start, finish = address+contraint.start, address+constraint.finish + if start // 0x100 == finish // 0x100 then + if constraint.type == 'crosspage' then goto constraints_not_met end + else + if constraint.type == 'samepage' then goto constraints_not_met end + end + end + local w = math.min(address - chunk.start, chunk.size - (address - chunk.start)) + if w < waste then waste=w position=address end + ::constraints_not_met:: + end + end + local finish = math.min(chunk.start + 0xff, chunk.start + chunk.size - section.size) + usage_lowest(chunk.start, finish) + if chunk.size ~= math.huge then + local start = math.max(chunk.start + chunk.size - section.size - 0xff, chunk.start) + usage_lowest(start, chunk.start + chunk.size - section.size) + end + if position then + chunk_reserve(chunk_ix, chunk, position, section.size) + section.org = position + goto chunk_located + end + end + error("unable to find space for section " .. section.label) + ::chunk_located:: + end + + end +end + +M.location = function(start, finish) + local size = (finish or math.huge) - start + locations[#locations+1] = { start=start, finish=finish, chunks={ { start=start, size=size } } } +end + +M.section = function(t) + local section = {} + if (type(t) == 'string') then section.label = t + else + assert(type(t) == 'table') + assert(type(t[1]) == 'string' and string.len(t[1]) > 0) + section=t section.label=t[1] section[1]=nil + if section.offset and not section.align then error("section " .. section.label .. " has offset, but no align") end + end + section.constraints = {} + section.instructions = {} + function section:compute_size() + self.size = 0 + for _,instruction in ipairs(self.instructions) do + -- TODO + end + end +end + M.byte = function(...) local data = {...} for _,v in ipairs(data) do byte_emit(byte_normalize(v)) end @@ -30,17 +154,6 @@ M.word = function(...) for _,v in ipairs(data) do word_emit(word_normalize(v)) end end -M.section = function(t) - local s = {} - if (type(t) == 'string') then s.name = t - else - assert(type(t) == 'table') - assert(type(t.name) == 'string' and string.len(t.name) > 0) - s = t - end - s.instructions = {} -end - return M --[===[