From 4d6749f1a3ebaa35a7f2885251885b7663dc6789 Mon Sep 17 00:00:00 2001 From: g012 Date: Mon, 2 Oct 2017 00:40:38 +0200 Subject: [PATCH] Added related sections constraint. --- .travis.yml | 31 ++++++--- 6502.lua | 167 ++++++++++++++++++++++++++++++++--------------- samples/vcs1.l65 | 11 +++- 3 files changed, 145 insertions(+), 64 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8deb0ac..7ed60b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,21 @@ -language: c -os: - - linux - - osx -compiler: - - clang - - gcc -script: - - cmake . -DCMAKE_BUILD_TYPE=Release - - make +language: c +os: + - linux + - osx +compiler: + - clang + - gcc +script: + - cmake . -DCMAKE_BUILD_TYPE=Release + - make + - ./l65 samples/vcs0.l65 + - ./l65 samples/vcs1.l65 +deploy: + provider: releases + api_key: + secure: MhH11SvqA5SCbxBbIPpT4lupbkZitK+4N5nKj0HZMBejVnY78bpePJ20pdIDGZQ+bUkZP8NEfLxrIsIheRuvS7nFOXehqAFmZhC3qA7LNrgColC2jISLrzipuG9fS1M8cYdGk11imYEZIx1RrpLAdGrMSR1dx+c44Fwzs271r2t2gchgcFlUvJiAUl9Fy5bEsX95jCJF4N8ozss3oBs7coFfuGBeC9AcFahekDsRrJh8oUA1VmP+pHukgronhDz9gqVAKNSrIR7/gZjOLVXU9e/rdmFUbO6WeYBlgDF85Jqzw0KI+O9pORfcRcxb+tXqLcECQJX0s4fyS/AdObr5lMov6NCT1Z6krkxrlko6ahHc5ZgZIkEcC9RNnmGfj+1ZPspCphiQfgUd7Z4KDLK6bqIGBFQlfPQHtz8BDW8tLTxLC3heSMzu5FI8i9lBxQKQa6+mifE1kmmj2v60TndocJ4YWb3diSBYWrQYFCI1pwcE5JerffP4mF9OL42oXsQbi9dqtnc3aqEPR5C4BUSoQtzknrm4UFjPCl8dPX2mpkXaRemcpn3Xi/ANx5VOdy5EfIQ10jkg/TkdRHr+YqrfW4fHEn5lKhhNrf1l2jDg30BPJ/3D7lW5wOuaHezDUzVUdXPVO0cxj2ap6nj88WHx66+ySAPZK0/wF2XVnTkEHM0= + file: l65 + skip_cleanup: true + on: + repo: g012/l65 + tags: true diff --git a/6502.lua b/6502.lua index 85600aa..b416b16 100644 --- a/6502.lua +++ b/6502.lua @@ -3,6 +3,7 @@ local M = {} local symbols={} M.symbols=symbols local locations={} M.locations=locations local sections={} M.sections=sections +local relations={} M.relations=relations local stats={} M.stats=stats setmetatable(stats, stats) M.strip = true -- set to false to disable dead stripping of relocatable sections @@ -75,12 +76,53 @@ M.link = function() for i=chunk_ix,chunk_ix+#new_chunks-1 do ins(chunks, i, new_chunks[i-chunk_ix+1]) end end + local chunk_from_address = function(section, address) + local chunks,rorg = section.location.chunks,section.location.rorg + for i,chunk in ipairs(chunks) do + if address >= chunk.start and address+section.size <= chunk.start+chunk.size then + return chunk,i + end + end + end + + local check_section_position = function(section, address, chunk) + local chunk = chunk_from_address(section, address) + if not chunk then return end + local rorg = section.location.rorg + if section.align then + local raddress = rorg(address) + if section.offset then raddress = raddress - section.offset end + if raddress % section.align ~= 0 then return end + end + for _,constraint in ipairs(section.constraints) do + local cstart, cfinish = address+constraint.start, address+constraint.finish + if rorg(cstart) // 0x100 == rorg(cfinish) // 0x100 then + if constraint.type == 'crosspage' then return end + else + if constraint.type == 'samepage' then return end + end + end + local address_end = address+section.size + local waste = math.min(address - chunk.start, chunk.size - (address_end - chunk.start)) + local raddress,raddress_end = rorg(address),rorg(address_end) + local align,cross=0x100,0 + repeat + local cross_count = (raddress_end+align-1)//align - (raddress+align-1)//align + if raddress&(align-1) == 0 then cross_count=cross_count+1 end + cross = cross + align * align * cross_count + align = align>>1 + until align==1 + local lsb=0 + for i=0,15 do if raddress&(1<= section.size then - local waste,position,position_end = math.maxinteger + local waste,cross,lsb,position = math.maxinteger,math.maxinteger,math.maxinteger local usage_lowest = function(start, finish) local inc=1 if section.align then @@ -91,40 +133,24 @@ M.link = function() inc = section.align end for address=start,finish,inc do - for _,constraint in ipairs(section.constraints) do - local cstart, cfinish = address+constraint.start, address+constraint.finish - if rorg(cstart) // 0x100 == rorg(cfinish) // 0x100 then - if constraint.type == 'crosspage' then goto constraints_not_met end - else - if constraint.type == 'samepage' then goto constraints_not_met end + local nwaste, ncross, nlsb = check_section_position(section, address, chunk) + if nwaste then + if constrain then + nwaste, ncross, nlsb = constrain(address, nwaste, ncross, nlsb) + if not nwaste then goto skip end end + if nwaste > waste then goto skip end + if nwaste == waste then + -- if waste is the same, keep the one that uses the least amount of aligned addresses + if ncross > cross then goto skip end + if ncross == cross then + -- if cross count is same, take the one with the most set LSB count (eg. select 11 over 10) + if nlsb > lsb then goto skip end + end + end + position,waste,cross,lsb = address,nwaste,ncross,nlsb + ::skip:: end - local address_end = address+section.size - local w = math.min(address - chunk.start, chunk.size - (address_end - chunk.start)) - if w > waste then goto constraints_not_met end - if w==waste then - local rposition,rposition_end = rorg(position),rorg(position_end) - local raddress,raddress_end = rorg(address),rorg(address_end) - -- if waste is the same, keep the one that uses the least amount of aligned addresses - local align=0x100 - repeat - local cross_count_cur = (rposition_end+align-1)//align - (rposition+align-1)//align - if rposition&(align-1) == 0 then cross_count_cur=cross_count_cur+1 end - local cross_count_new = (raddress_end+align-1)//align - (raddress+align-1)//align - if raddress&(align-1) == 0 then cross_count_new=cross_count_new+1 end - if cross_count_new < cross_count_cur then goto select_pos end - align = align>>1 - until align==1 - -- if cross count is same, take the one with the most set LSB count (eg. select 11 over 10) - local lsb_cur,lsb_new=0,0 - for i=0,15 do if rposition&(1<b.size end) - end - table.sort(sibling_sections, function(a,b) return a[1].size==b[1].size and a[1].idb[1].size end) - for _,section in ipairs(sibling_sections) do - local siblings = section.siblings - local relate = section.relate or function(sibling, siblings) + + 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 + local related,ins = {},table.insert + local function collect(section, offset) + local relatives = relations[section] + if relatives then + for relative,relative_offset in pairs(relatives) do + if not related[relative] then + relative_offset = relative_offset + offset + related[relative] = relative_offset + collect(relative, relative_offset) + end + end + end end - for _,sibling in siblings do - if not relate(sibling, siblings) then goto not_suitable end + collect(section, 0) + 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) + if not nwaste then return end + waste, cross, lsb = waste+nwaste, cross+ncross, lsb+nlsb + end + return waste, cross, lsb + end) + if not position then + error("unable to find space for section " .. section.label) + end + for section,offset in pairs(related) do + section.org = position + 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 - ::not_suitable:: end -]] + for _,location in ipairs(locations) do local position_independent_sections = location.position_independent_sections table.sort(position_independent_sections, function(a,b) return a.size==b.size and a.label>b.label or a.size>b.size end) @@ -373,7 +418,7 @@ M.location = function(start, finish) location.rorg = function(x) return x+offset end end end - location.sections = {} -- TODO remove + 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 location.chunks={ { id=id(), start=location.start, size=size } } @@ -398,7 +443,7 @@ M.section = function(t) section=t name=t[1] or 'S'..id() section[1]=nil if section.offset and not section.align then error("section " .. name .. " has offset, but no align") end end - table.insert(M.location_current.sections, section) -- TODO remove + table.insert(M.location_current.sections, section) table.insert(M.sections, section) section.location = M.location_current M.section_current = section @@ -434,6 +479,22 @@ M.section = function(t) return section end +-- relate(section1, section2 [, [offset1,] offset2]) +-- Add a position relationship between 'section1' and 'section2', with 'offset1' +-- bytes from selected position for 'section2', and 'offset2' bytes from selec- +-- -ted positon for 'section1'. +-- If offset1 is omitted, -offset2 is used. +M.relate = function(section1, section2, offset, offset2) + local rel1 = relations[section1] or {} + rel1[section2] = offset2 or offset + relations[section1] = rel1 + local rel2 = relations[section2] or {} + rel2[section1] = offset2 and offset + relations[section2] = rel2 + section1.related = true + section2.related = true +end + M.label = function(name) local label,offset local section,rorg = M.section_current,M.location_current.rorg diff --git a/samples/vcs1.l65 b/samples/vcs1.l65 index 5d5a0f8..177de42 100644 --- a/samples/vcs1.l65 +++ b/samples/vcs1.l65 @@ -9,7 +9,16 @@ location(0xf000, 0xffff) section{'vectors', org=0xfffc} dc.w start,start local kernel = function() - ldx#0xd0 @_loop sta WSYNC stx COLUBK dex bne _loop + -- add a dummy instruction to collect cycle count and binary size + local kernel_cycles,kernel_size + table.insert(section_current.instructions, { bin=function() kernel_cycles=cycles kernel_size=size end }) + + samepage + ldx#0xd0 @_loop sta WSYNC stx COLUBK dex bne _loop + end + + -- and get the delta (cycles are counted without taking any branch) + table.insert(section_current.instructions, { bin=function() print('kernel cycles: ', cycles-kernel_cycles, 'kernel size: ', size-kernel_size) end }) end local wait = function() local l=label() lda INTIM bne l end