From 662ef74b53c508446635a2dea80b1963c063f89c Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 3 Nov 2018 17:16:17 +0100 Subject: [PATCH 01/41] Moved architecture independent code to asm.lua --- 6502.lua | 984 +++++-------------------------------------------- CMakeLists.txt | 1 + asm.lua | 837 +++++++++++++++++++++++++++++++++++++++++ main.c | 4 +- 4 files changed, 928 insertions(+), 898 deletions(-) create mode 100644 asm.lua diff --git a/6502.lua b/6502.lua index d7d4548..8c9a8c1 100644 --- a/6502.lua +++ b/6502.lua @@ -1,883 +1,65 @@ -local M = {} - -local symbols,symbolsorg={},{} M.symbols,M.symbolsorg=symbols,symbolsorg -local locations={} M.locations=locations -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.strip_empty = false -- set to true to strip empty sections: their label will then not resolve -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) - -local id_ = 0 -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) - if type(val) == 'table' and val.type == 'label' then - val.section.refcount = val.section.refcount + 1 - end - return val - end - end - for _,section in ipairs(sections) do - section:compute_size() - end - symbols.__index = symbols - - local chunk_reserve = function(section, chunk_ix) - local chunks = section.location.chunks - local chunk = chunks[chunk_ix] - local holes = section.holes - local new_chunks,ins = {},table.insert - - local chunk1 = { id=id(), start=chunk.start, size=section.org-chunk.start } - local hole_ix = 1 - local hole1 = holes[1] - if hole1 and hole1.start==0 then - chunk1.size = chunk1.size + hole1.size - hole_ix = 2 - end - if chunk1.size > 0 then ins(new_chunks, chunk1) end - while hole_ix <= #holes do - local hole = holes[hole_ix] - local chunki = { id=id(), start=section.org+hole.start, size=hole.size } - ins(new_chunks, chunki) - hole_ix = hole_ix + 1 - end - local chunkl = { id=id(), start=section.org+section.size, size=chunk.start+chunk.size-(section.org+section.size) } - local chunkn = new_chunks[#new_chunks] - if chunkn and chunkn.start+chunkn.size==chunkl.start then - chunkn.size = chunkn.size + chunkl.size - elseif chunkl.size > 0 then - ins(new_chunks, chunkl) - end - - table.remove(chunks, chunk_ix) - 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,cross,lsb,position = math.maxinteger,math.maxinteger,math.maxinteger - local usage_lowest = function(start, finish) - local inc=1 - if section.align then - local rstart = rorg(start) - local arstart = (rstart + section.align - 1) // section.align * section.align - if section.offset then arstart = arstart + section.offset end - start = start + arstart-rstart - inc = section.align - end - for address=start,finish,inc do - 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 - 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 - section.org = position - chunk_reserve(section, chunk_ix) - --print(section.label, string.format("%04X\t%d", position, section.size)) - --for k,v in ipairs(location.chunks) do print(string.format(" %04X %04X %d", v.start, v.size+v.start-1, v.size)) end - return position - end - end end - end - - stats.used = 0 - stats.unused = 0 - stats.cycles = 0 - local related_sections = {} - for _,location in ipairs(locations) do - local sections,rorg = location.sections,location.rorg - - -- filter sections list - local position_independent_sections = {} - local symbols_to_remove = {} - local section_count = #sections - location.cycles=0 location.used=0 - for ix,section in ipairs(sections) do - location.cycles = location.cycles + section.cycles - location.used = location.used + section.size - if section.size == 0 then - if M.strip_empty or section.weak then - sections[ix]=nil - if not section.org then table.insert(symbols_to_remove, section.label) end - else - section.org = location.start - end - elseif not section.org then - if M.strip and not section.refcount and not section.strong then - sections[ix]=nil - table.insert(symbols_to_remove, section.label) - elseif section.related then - table.insert(related_sections, section) - 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 - end end - for _,v in ipairs(symbols_to_remove) do symbols[v] = nil end - location.position_independent_sections = position_independent_sections - stats.cycles = stats.cycles + location.cycles - stats.used = stats.used + location.used - - -- 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 or math.huge) 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(section, chunk_ix) - goto chunk_located - end - end - error("ORG section " .. section.label .. " overflows its location") - ::chunk_located:: - end end - end - - table.sort(related_sections, function(a,b) if a.size==b.size then return a.idb.size end) - for _,section in ipairs(related_sections) do if not section.org then - local related,ins = {},table.insert - local function collect(section_parent, offset) - local relatives = relations[section_parent] - if relatives then - for relative,relative_offset in pairs(relatives) do - if not related[relative] and relative ~= section then - relative_offset = relative_offset + offset - related[relative] = relative_offset - collect(relative, relative_offset) - end - end - end - end - collect(section, 0) - local location_start = section.location.start - 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 section_address = address + (section.location.start - location_start) + offset - local nwaste, ncross, nlsb = check_section_position(section, section_address) - 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 + (section.location.start - location_start) + offset - local chunk,chunk_ix = chunk_from_address(section, section.org) - chunk_reserve(section, chunk_ix) - end - end end - - for _,location in ipairs(locations) do - local position_independent_sections = location.position_independent_sections - table.sort(position_independent_sections, function(a,b) if a.size==b.size then return a.label>b.label end return a.size>b.size end) - for _,section in ipairs(position_independent_sections) do - if not position_section(section) then - error("unable to find space for section " .. section.label) - end - end - - -- unused space stats - local unused = 0 - for _,chunk in ipairs(location.chunks) do - if chunk.size ~= math.huge then - unused = unused + chunk.size - else - location.stops_at = chunk.start-1 - end - end - location.unused = unused - stats.unused = stats.unused + unused - - end -end - -M.resolve = function() - if stats.resolved_count then return end - M.link() - - stats.resolved_count = 0 - repeat local count = 0 - for k,v in pairs(symbols) do if k ~= '__index' then - local t = type(v) - if t == 'function' then v=v() t=type(v) symbols[k]=v count=count+1 end - if t == 'table' and type(v.resolve) == 'function' then symbols[k],symbolsorg[k]=v.resolve() count=count+1 end - if t == 'string' and symbols[v] then symbols[k]=symbols[v] count=count+1 end - stats.resolved_count = stats.resolved_count + count - end end until count == 0 - - -- set local label references resolver - local llresolver = { __index = function(tab,key) - 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) -end - -M.genbin = function(filler) - if #locations == 0 then return end - if not filler then filler = 0 end -- brk opcode - M.resolve() - local bin = {} - local ins,mov = table.insert,table.move - table.sort(locations, function(a,b) return a.start < b.start end) - local of0 = locations[1].start - local fill - for _,location in ipairs(locations) do - if location.start < #bin then - error(string.format("location [%04x,%04x] overlaps another", location.start, location.finish or location.stops_at)) - end - if fill then for i=#bin+of0,location.start-1 do ins(bin, filler) end end - M.size=0 M.cycles=0 - local sections = location.sections - table.sort(sections, function(a,b) return a.org < b.org end) - for _,section in ipairs(sections) do - for i=#bin+of0,section.org-1 do ins(bin, filler) end - local bin_offset = math.min(#bin, section.org-of0)+1 - for _,instruction in ipairs(section.instructions) do - local b,o = instruction.bin - if type(b) == 'function' then b,o = b(filler) end - if type(b) == 'table' then mov(b,1,#b,bin_offset,bin) bin_offset=bin_offset+#b - elseif b then bin[bin_offset]=b bin_offset=bin_offset+1 end - if o then - bin_offset=bin_offset+o - for i=#bin,bin_offset-1 do ins(bin, filler) end - end - M.size=#bin M.cycles=M.cycles+(instruction.cycles or 0) - end - end - fill = not location.nofill - if location.finish and fill then - for i=#bin+of0,location.finish do ins(bin, filler) end - end - end - stats.bin_size = #bin - return bin -end - -M.writebin = function(filename, bin) - if not filename then filename = 'main.bin' end - if not bin then bin = M.genbin() end - local f = assert(io.open(filename, "wb"), "failed to open " .. filename .. " for writing") - f:write(string.char(table.unpack(bin))) - f:close() -end - --- return a table of entry(address, label) -M.getsym = function(entry) - local ins = table.insert - local s,sym_rev = {},{} - for k,v in pairs(symbols) do if type(v) == 'number' then ins(sym_rev,k) end end - table.sort(sym_rev, function(a,b) local x,y=symbols[a],symbols[b] if x==y then return a 1 then - ins(s, string.format(" --- Total --- %5d %5d %5d", stats.unused, stats.used, stats.bin_size)) - end - return table.concat(s, '\n') -end - -M.location = function(start, finish) - local location - if type(start) ~= 'table' then - location = { start=start, finish=finish } - else - if start.type == 'location' then - for _,v in ipairs(locations) do if v == start then - M.location_current = start - return start - end end - error("unable to find reference to location [" .. (start.start or '?') .. ", " .. (start.finish or '?') .. "]") - end - location = start - location.start = start[1] - location.finish = start[2] - if type(location.rorg) == 'number' then - local offset = location.rorg - location.start - location.rorg = function(x) return x+offset end - end - end - location.type = 'location' - 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 } } - locations[#locations+1] = location - M.location_current = location - return location -end - -M.section = function(t) - local section = {} - local name = t or 'S'..id() - if type(name) ~= 'string' then - assert(type(t) == 'table', "invalid arguments for section") - if t.type == 'section' then - for _,v in ipairs(sections) do if v == t then - M.location_current = t.location - M.section_current = t - return t - end end - error("unable to find reference to section " .. (t.label or '?')) - end - 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) - table.insert(M.sections, section) - section.location = M.location_current - M.section_current = section - section.type = 'section' - section.id = id() - section.constraints = {} - section.instructions = {} - assert(name:sub(1,1) ~= '_', "sections can't be named with a local label") - section.label = M.label(name) - section.holes = {} - section.refcount = 0 - function section:compute_size() - local instructions = self.instructions - self.size=0 self.cycles=0 - for _,instruction in ipairs(instructions) do - instruction.offset = self.size - local ins_sz = instruction.size or 0 - if type(ins_sz) == 'function' then - -- evaluation is needed to get the size (distinguish zpg/abs) - -- labels and sections are not resolved at this point, so - -- evaluation will fail if the size is not explicitly stated (.b/.w); - -- in that case, assume max size - ins_sz = ins_sz() - end - self.size = self.size + ins_sz - self.cycles = self.cycles + (instruction.cycles or 0) - end - for _,constraint in ipairs(self.constraints) do - constraint.start = instructions[constraint.from].offset - constraint.finish = constraint.to==#instructions and self.size or instructions[constraint.to+1].offset - end - end - 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) - assert(section1.type == 'section', "section1 is not a section") - assert(section2.type == 'section', "section2 is not a section") - local rel1 = relations[section1] or {} - rel1[section2] = (offset2 or offset) or 0 - relations[section1] = rel1 - local rel2 = relations[section2] or {} - rel2[section1] = (offset2 and offset) or -rel1[section2] - 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 - label = { type='label', section=section } - if not name then name='_L'..id() end - if name:sub(1,1) == '_' then -- local label - name = M.label_current .. name - else - M.label_current = name - label.bin = function() M.label_current = name end - end - if symbols[name] then error("duplicate symbol: " .. name) end - symbols[name] = label - label.label = name - label.size = function() - offset = section.size - label.size = 0 - return 0 - end - label.resolve = function() - local o = section.org + offset - return rorg(o),o - end - table.insert(section.instructions, label) - return name,label -end - -M.samepage = function() - local section = M.section_current - table.insert(section.constraints, { type='samepage', from=#section.instructions+1 }) -end -M.crosspage = function() - local section = M.section_current - table.insert(section.constraints, { type='crosspage', from=#section.instructions+1 }) -end -M.endpage = function() - local section = M.section_current - local constraint = section.constraints[#section.constraints] - assert(constraint and not constraint.to, "closing constraint, but no constraint is open") - constraint.to = #section.instructions -end - --- skip(bytes) --- Insert a hole in the section of 'bytes' bytes, which can be used by other --- relocatable sections. -M.skip = function(bytes) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local ins,section = {},M.section_current - ins.size = function() - table.insert(section.holes, { start=ins.offset, size=bytes }) - return bytes - end - ins.bin = function(filler) return nil,bytes end - table.insert(section.instructions, ins) -end - --- sleep(cycles [, noillegal]) --- Waste 'cycles' cycles. If 'noillegal' is true, trashes NZ flags. -M.sleep = function(cycles, noillegal) - assert(cycles > 1, "can't sleep for less than 2 cycles") - if cycles & 1 ~= 0 then - if noillegal then bitzpg(0) else nopzpg(0) end - cycles = cycles - 3 - end - for i=1,cycles/2 do nopimp() end -end - -local op_resolve = function(v) - if type(v) == 'function' then v=v() end - if type(v) == 'table' and v.label then v = symbols[v.label] end - if type(v) == 'string' then v = symbols[v] end - if type(v) ~= 'number' then error("unresolved symbol: " .. tostring(v)) end - return v -end M.op_resolve = op_resolve - -local size_ref = function(v) - if type(v) == 'string' then v=symbols[v] end - if type(v) == 'table' and v.type == 'label' then v.section.refcount = 1 + (v.section.refcount or 0) end -end -local size_dc = function(v) - if type(v) == 'function' then - local r,x = M.pcall(v) - if not r or not x then return v end - 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, op_resolve) - if not r or not x 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 - return v & 0xff -end -M.byte_normalize = byte_normalize - -local word_normalize = function(v) - if v < -0x8000 or v > 0xFFFF then error("value out of word range: " .. v) end - if v < 0 then v = v + 0x10000 end - return v & 0xffff -end -M.word_normalize = word_normalize - -local long_normalize = function(v) - if v < -0x80000000 or v > 0xFFFFFFFF then error("value out of word range: " .. v) end - if v < 0 then v = v + 0x100000000 end - return v & 0xffffffff -end -M.long_normalize = long_normalize - --- charset([s] [, f]) --- Set a new charset to be used for next string data in byte(). --- Without argument, revert to Lua charset. --- s: string of all letters of charset --- f: letter index offset or function to transform the letter index -M.charset = function(s, f) - local st = type(s) - if st == 'nil' then M.cs = nil return s end - if st == 'table' then M.cs = s return s end - if not f then f = function(v) return v end - elseif type(f) == 'number' then f = function(v) return v + f end end - local t,i={},0 - for c in s:gmatch'.' do local v=i t[c]=function() return f(v) end i=i+1 end - M.cs=t - return t -end - -M.byte_impl = function(args, nrm) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local data,cs = {},M.cs - for k,v in ipairs(args) do - local t = type(v) - if t == 'number' or t == 'function' then data[#data+1] = v - elseif t == 'table' then table.move(v,1,#v,#data+1,data) - elseif t == 'string' then - if cs then - for c in v:gmatch'.' do - local i=cs[c] - if not i then error("character " .. c .. " is not part of current charset") end - data[#data+1]=i - end - else - local s = {v:byte(1,#v)} - table.move(s, 1, #s, #data+1, data) - end - 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 bin = function() local l65dbg=l65dbg - local b={} - for k,v in ipairs(data) do - if type(v) == 'function' then v = v() end - local vt = type(v) - if vt == 'table' and v.label then v = symbols[v.label] - elseif vt == 'string' then v = symbols[v] end - if type(v) ~= 'number' then error("unresolved symbol for dc.b, index " .. k) end - b[#b+1] = nrm(v) - end - return b - end - table.insert(M.section_current.instructions, { data=data, size=size, bin=bin }) -end --- byte(...) --- Declare bytes to go into the binary stream. --- Each argument can be either: --- * a number resolving to a valid range byte --- * a string, converted to bytes using the charset previously defined, --- or Lua's charset if none was defined --- * a table, with each entry resolving to a valid range byte --- * a function, resolving to exactly one valid range byte, evaluated --- after symbols have been resolved -M.byte = function(...) - return M.byte_impl({...}, byte_normalize) -end -local byte_encapsulate = function(args) - for k,v in ipairs(args) do - local vt = type(v) - if vt == 'string' or vt == 'table' and (v.type == 'section' or v.type == 'label') then - args[k] = function() return v end - end - end - return args -end -M.byte_hi = function(...) - return M.byte_impl(byte_encapsulate{...}, function(v) return (v>>8)&0xff end) -end -M.byte_lo = function(...) - return M.byte_impl(byte_encapsulate{...}, function(v) return v&0xff end) -end - --- word(...) --- Declare words to go into the binary stream. --- Each argument can be either: --- * a section or a label --- * a number resolving to a valid range word --- * a table, with each entry resolving to a valid range word --- * a function, resolving to exactly one valid range word, evaluated --- after symbols have been resolved -M.word = function(...) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local args = {...} - local data = {} - for k,v in ipairs(args) do - local t = type(v) - if t == 'number' or t == 'function' or t == 'string' then data[#data+1] = v - elseif t == 'table' then - if v.type == 'section' or v.type == 'label' then data[#data+1] = function() return v end - else table.move(v,1,#v,#data+1,data) end - 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 bin = function() local l65dbg=l65dbg - local b={} - for k,v in ipairs(data) do - if type(v) == 'function' then v = v() end - local vt = type(v) - if vt == 'table' and v.label then v = symbols[v.label] - elseif vt == 'string' then v = symbols[v] end - if type(v) ~= 'number' then error("unresolved symbol for dc.w, index " .. k) end - v = word_normalize(v) - b[#b+1] = v&0xff - b[#b+1] = v>>8 - end - return b - end - table.insert(M.section_current.instructions, { data=data, size=size, bin=bin }) -end - -M.long = function(...) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local args = {...} - local data = {} - for k,v in ipairs(args) do - local t = type(v) - if t == 'number' or t == 'function' or t == 'string' then data[#data+1] = v - elseif t == 'table' then - if v.type == 'section' or v.type == 'label' then data[#data+1] = function() return v end - else table.move(v,1,#v,#data+1,data) end - 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 bin = function() local l65dbg=l65dbg - local b={} - for k,v in ipairs(data) do - if type(v) == 'function' then v = v() end - local vt = type(v) - if vt == 'table' and v.label then v = symbols[v.label] - elseif vt == 'string' then v = symbols[v] end - if type(v) ~= 'number' then error("unresolved symbol for dc.l, index " .. k) end - v = long_normalize(v) - b[#b+1] = v&0xff - b[#b+1] = (v>>8)&0xff - b[#b+1] = (v>>16)&0xff - b[#b+1] = v>>24 - end - return b - end - table.insert(M.section_current.instructions, { data=data, size=size, bin=bin }) -end +M = require "asm" -- Return a value in rage [0x00, 0xff] if x is to use zeropage addressing mode. Defaults to range [0x0000-0x00ff]. -M.zeropage = function(x) if x >= -128 and x <= 0xff then return byte_normalize(x) end end +M.zeropage = function(x) if x >= -128 and x <= 0xff then return M.byte_normalize(x) end end + +local cycles_def,xcross_def -local op,cycles_def,xcross_def -op = function(code, cycles, extra_on_crosspage) - return { opc=code, cycles=cycles or cycles_def, xcross=extra_on_crosspage or xcross_def } -end -local op_eval = function(late, early) - local x = early or 0 - return type(late) == 'function' and late(x,op_resolve) or x+op_resolve(late) -end -local op_eval_byte = function(late, early, nozp) - local v = op_eval(late, early) - local zpv = zeropage(v) - if not nozp and zpv then return zpv end - return byte_normalize(v) -end -local op_eval_word = function(late, early) return word_normalize(op_eval(late, early)) end cycles_def=2 xcross_def=0 local opimp={ - asl=op(0x0a), brk=op(0x00,7), clc=op(0x18), cld=op(0xd8), cli=op(0x58), clv=op(0xb8), dex=op(0xca), dey=op(0x88), - inx=op(0xe8), iny=op(0xc8), lsr=op(0x4a), nop=op(0xea), pha=op(0x48,3), php=op(0x08,3), pla=op(0x68,4), plp=op(0x28,4), - rol=op(0x2a), ror=op(0x6a), rti=op(0x40,6), rts=op(0x60,6), sec=op(0x38), sei=op(0x78), tax=op(0xaa), tay=op(0xa8), - tsx=op(0xba), txa=op(0x8a), txs=op(0x9a), tya=op(0x98), - jam=op(0x02,0), + asl=M.op(0x0a), brk=M.op(0x00,7), clc=M.op(0x18), cld=M.op(0xd8), cli=M.op(0x58), clv=M.op(0xb8), dex=M.op(0xca), dey=M.op(0x88), + inx=M.op(0xe8), iny=M.op(0xc8), lsr=M.op(0x4a), nop=M.op(0xea), pha=M.op(0x48,3), php=M.op(0x08,3), pla=M.op(0x68,4), plp=M.op(0x28,4), + rol=M.op(0x2a), ror=M.op(0x6a), rti=M.op(0x40,6), rts=M.op(0x60,6), sec=M.op(0x38), sei=M.op(0x78), tax=M.op(0xaa), tay=M.op(0xa8), + tsx=M.op(0xba), txa=M.op(0x8a), txs=M.op(0x9a), tya=M.op(0x98), + jam=M.op(0x02,0), } M.opimp = opimp for k,v in pairs(opimp) do M[k .. 'imp'] = function() table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) end end + cycles_def=2 xcross_def=0 local opimm={ - adc=op(0x69), ['and']=op(0x29), cmp=op(0xc9), cpx=op(0xe0), cpy=op(0xc0), eor=op(0x49), lda=op(0xa9), ldx=op(0xa2), - ldy=op(0xa0), ora=op(0x09), sbc=op(0xe9), - anc=op(0x0b), ane=op(0x8b), arr=op(0x6b), asr=op(0x4b), jam=op(0x12,0), lax=op(0xab), nop=op(0x80), sbx=op(0xcb), + adc=M.op(0x69), ['and']=M.op(0x29), cmp=M.op(0xc9), cpx=M.op(0xe0), cpy=M.op(0xc0), eor=M.op(0x49), lda=M.op(0xa9), ldx=M.op(0xa2), + ldy=M.op(0xa0), ora=M.op(0x09), sbc=M.op(0xe9), + anc=M.op(0x0b), ane=M.op(0x8b), arr=M.op(0x6b), asr=M.op(0x4b), jam=M.op(0x12,0), lax=M.op(0xab), nop=M.op(0x80), sbx=M.op(0xcb), } M.opimm = opimm for k,v in pairs(opimm) do M[k .. 'imm'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early,true) } end + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early,true) } end table.insert(M.section_current.instructions, { size=size, cycles=2, bin=bin }) end end cycles_def=3 xcross_def=0 local opzpg={ - adc=op(0x65), ['and']=op(0x25), asl=op(0x06,5), bit=op(0x24), cmp=op(0xc5), cpx=op(0xe4), cpy=op(0xc4), dec=op(0xc6,5), - eor=op(0x45), inc=op(0xe6,5), lda=op(0xa5), ldx=op(0xa6), ldy=op(0xa4), lsr=op(0x46,5), ora=op(0x05), rol=op(0x26,5), - ror=op(0x66,5), sbc=op(0xe5), sta=op(0x85), stx=op(0x86), sty=op(0x84), - dcp=op(0xc7,5), isb=op(0xe7,5), jam=op(0x22,0), lax=op(0xa7), nop=op(0x04), rla=op(0x27,5), rra=op(0x67,5), sax=op(0x87), - slo=op(0x07,5), sre=op(0x47,5), + adc=M.op(0x65), ['and']=M.op(0x25), asl=M.op(0x06,5), bit=M.op(0x24), cmp=M.op(0xc5), cpx=M.op(0xe4), cpy=M.op(0xc4), dec=M.op(0xc6,5), + eor=M.op(0x45), inc=M.op(0xe6,5), lda=M.op(0xa5), ldx=M.op(0xa6), ldy=M.op(0xa4), lsr=M.op(0x46,5), ora=M.op(0x05), rol=M.op(0x26,5), + ror=M.op(0x66,5), sbc=M.op(0xe5), sta=M.op(0x85), stx=M.op(0x86), sty=M.op(0x84), + dcp=M.op(0xc7,5), isb=M.op(0xe7,5), jam=M.op(0x22,0), lax=M.op(0xa7), nop=M.op(0x04), rla=M.op(0x27,5), rra=M.op(0x67,5), sax=M.op(0x87), + slo=M.op(0x07,5), sre=M.op(0x47,5), } M.opzpg = opzpg for k,v in pairs(opzpg) do M[k .. 'zpg'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early) } end + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end + cycles_def=4 xcross_def=0 local opabs={ - adc=op(0x6d), ['and']=op(0x2d), asl=op(0x0e,6), bit=op(0x2c), cmp=op(0xcd), cpx=op(0xec), cpy=op(0xcc), dec=op(0xce,6), - eor=op(0x4d), inc=op(0xee,6), jmp=op(0x4c,3), jsr=op(0x20,6), lda=op(0xad), ldx=op(0xae), ldy=op(0xac), lsr=op(0x4e,6), - ora=op(0x0d), rol=op(0x2e,6), ror=op(0x6e,6), sbc=op(0xed), sta=op(0x8d), stx=op(0x8e), sty=op(0x8c), - dcp=op(0xcf,6), isb=op(0xef,6), jam=op(0x72,0), lax=op(0xaf), nop=op(0x0c), rla=op(0x2f,6), rra=op(0x6f,6), sax=op(0x8f), - slo=op(0x0f,6), sre=op(0x4f,6), + adc=M.op(0x6d), ['and']=M.op(0x2d), asl=M.op(0x0e,6), bit=M.op(0x2c), cmp=M.op(0xcd), cpx=M.op(0xec), cpy=M.op(0xcc), dec=M.op(0xce,6), + eor=M.op(0x4d), inc=M.op(0xee,6), jmp=M.op(0x4c,3), jsr=M.op(0x20,6), lda=M.op(0xad), ldx=M.op(0xae), ldy=M.op(0xac), lsr=M.op(0x4e,6), + ora=M.op(0x0d), rol=M.op(0x2e,6), ror=M.op(0x6e,6), sbc=M.op(0xed), sta=M.op(0x8d), stx=M.op(0x8e), sty=M.op(0x8c), + dcp=M.op(0xcf,6), isb=M.op(0xef,6), jam=M.op(0x72,0), lax=M.op(0xaf), nop=M.op(0x0c), rla=M.op(0x2f,6), rra=M.op(0x6f,6), sax=M.op(0x8f), + slo=M.op(0x0f,6), sre=M.op(0x4f,6), } M.opabs = opabs for k,v in pairs(opabs) do M[k .. 'abs'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 3 end + local size = function() late,early = M.size_op(late,early) return 3 end local bin = function() local l65dbg=l65dbg - local x = op_eval_word(late,early) + local x = M.op_eval_word(late,early) return { v.opc, x&0xff, x>>8 } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) @@ -897,10 +79,10 @@ for k,_ in pairs(opzab) do local abs = opabs[k] local ins = { cycles=abs.cycles } ins.size = function() local l65dbg=l65dbg - local r,x = M.pcall_za(op_eval, late, early) + local r,x = M.pcall_za(M.op_eval, late, early) if not r then return 3 end - size_ref(x) - x = word_normalize(x) + M.size_ref(x) + x = M.word_normalize(x) local zpg,zpv = opzpg[k], zeropage(x) if zpv and zpg then ins.size = 2 @@ -913,7 +95,7 @@ for k,_ in pairs(opzab) do return 3 end ins.bin = function() local l65dbg=l65dbg - local x = word_normalize(op_eval(late, early)) + local x = M.word_normalize(M.op_eval(late, early)) -- since we assumed absolute on link phase, we must generate absolute in binary if zeropage(x) and opzpg[k] then io.stderr:write("warning: forcing abs on zpg operand for opcode " .. k .. "\n") end return { abs.opc, x&0xff, x>>8 } @@ -921,31 +103,33 @@ for k,_ in pairs(opzab) do table.insert(M.section_current.instructions, ins) end end + cycles_def=4 xcross_def=0 local opzpx={ - adc=op(0x75), ['and']=op(0x35), asl=op(0x16,6), cmp=op(0xd5), dec=op(0xd6,6), eor=op(0x55), inc=op(0xf6,6), lda=op(0xb5), - ldy=op(0xb4), lsr=op(0x56,6), ora=op(0x15), rol=op(0x36,6), ror=op(0x76,6), sbc=op(0xf5), sta=op(0x95), sty=op(0x94), - dcp=op(0xd7,6), isb=op(0xf7,6), jam=op(0x32,0), nop=op(0x14), rla=op(0x37,6), rra=op(0x77,6), slo=op(0x17,6), sre=op(0x57,6), + adc=M.op(0x75), ['and']=M.op(0x35), asl=M.op(0x16,6), cmp=M.op(0xd5), dec=M.op(0xd6,6), eor=M.op(0x55), inc=M.op(0xf6,6), lda=M.op(0xb5), + ldy=M.op(0xb4), lsr=M.op(0x56,6), ora=M.op(0x15), rol=M.op(0x36,6), ror=M.op(0x76,6), sbc=M.op(0xf5), sta=M.op(0x95), sty=M.op(0x94), + dcp=M.op(0xd7,6), isb=M.op(0xf7,6), jam=M.op(0x32,0), nop=M.op(0x14), rla=M.op(0x37,6), rra=M.op(0x77,6), slo=M.op(0x17,6), sre=M.op(0x57,6), } M.opzpx = opzpx for k,v in pairs(opzpx) do M[k .. 'zpx'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early) } end + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end + cycles_def=4 xcross_def=1 local opabx={ - adc=op(0x7d), ['and']=op(0x3d), asl=op(0x1e,7,0), cmp=op(0xdd), dec=op(0xde,7,0), eor=op(0x5d), inc=op(0xfe,7,0), lda=op(0xbd), - ldy=op(0xbc), lsr=op(0x5e,7,0), ora=op(0x1d), rol=op(0x3e,7,0), ror=op(0x7e,7,0), sbc=op(0xfd), sta=op(0x9d,5,0), - dcp=op(0xdf,7,0), isb=op(0xff,7,0), jam=op(0x92,0,0), nop=op(0x1c), rla=op(0x3f,7,0), rra=op(0x7f,7,0), shy=op(0x9c,5,0), slo=op(0x1f,7,0), - sre=op(0x5f,7,0), + adc=M.op(0x7d), ['and']=M.op(0x3d), asl=M.op(0x1e,7,0), cmp=M.op(0xdd), dec=M.op(0xde,7,0), eor=M.op(0x5d), inc=M.op(0xfe,7,0), lda=M.op(0xbd), + ldy=M.op(0xbc), lsr=M.op(0x5e,7,0), ora=M.op(0x1d), rol=M.op(0x3e,7,0), ror=M.op(0x7e,7,0), sbc=M.op(0xfd), sta=M.op(0x9d,5,0), + dcp=M.op(0xdf,7,0), isb=M.op(0xff,7,0), jam=M.op(0x92,0,0), nop=M.op(0x1c), rla=M.op(0x3f,7,0), rra=M.op(0x7f,7,0), shy=M.op(0x9c,5,0), slo=M.op(0x1f,7,0), + sre=M.op(0x5f,7,0), } M.opabx = opabx for k,v in pairs(opabx) do M[k .. 'abx'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 3 end + local size = function() late,early = M.size_op(late,early) return 3 end local bin = function() local l65dbg=l65dbg - local x = op_eval_word(late,early) + local x = M.op_eval_word(late,early) return { v.opc, x&0xff, x>>8 } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) @@ -965,10 +149,10 @@ for k,_ in pairs(opzax) do local abx = opabx[k] local ins = { cycles=abx.cycles } ins.size = function() local l65dbg=l65dbg - local r,x = M.pcall_za(op_eval, late, early) + local r,x = M.pcall_za(M.op_eval, late, early) if not r then return 3 end - size_ref(x) - x = word_normalize(x) + M.size_ref(x) + x = M.word_normalize(x) local zpx,zpv = opzpx[k], zeropage(x) if zpv and zpx then ins.size = 2 @@ -981,7 +165,7 @@ for k,_ in pairs(opzax) do return 3 end ins.bin = function() local l65dbg=l65dbg - local x = word_normalize(op_eval(late, early)) + local x = M.word_normalize(M.op_eval(late, early)) -- since we assumed absolute on link phase, we must generate absolute in binary if zeropage(x) and opzpx[k] then io.stderr:write("warning: forcing abx on zpx operand for opcode " .. k .. "\n") end return { abx.opc, x&0xff, x>>8 } @@ -989,30 +173,32 @@ for k,_ in pairs(opzax) do table.insert(M.section_current.instructions, ins) end end + cycles_def=4 xcross_def=0 local opzpy={ - ldx=op(0xb6), stx=op(0x96), - jam=op(0x42,0), lax=op(0xb7), sax=op(0x97), + ldx=M.op(0xb6), stx=M.op(0x96), + jam=M.op(0x42,0), lax=M.op(0xb7), sax=M.op(0x97), } M.opzpy = opzpy for k,v in pairs(opzpy) do M[k .. 'zpy'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early) } end + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end + cycles_def=4 xcross_def=1 local opaby={ - adc=op(0x79), ['and']=op(0x39), cmp=op(0xd9), eor=op(0x59), lda=op(0xb9), ldx=op(0xbe), ora=op(0x19), sbc=op(0xf9), - sta=op(0x99,5,0), - dcp=op(0xdb,7,0), isb=op(0xfb,7,0), jam=op(0xb2,0,0), las=op(0xbb), lax=op(0xbf), rla=op(0x3b,7,0), rra=op(0x7b,7,0), sha=op(0x9f,5,0), - shs=op(0x9b,5,0), shx=op(0x9e,5,0), slo=op(0x1b,7,0), sre=op(0x5b,7,0), + adc=M.op(0x79), ['and']=M.op(0x39), cmp=M.op(0xd9), eor=M.op(0x59), lda=M.op(0xb9), ldx=M.op(0xbe), ora=M.op(0x19), sbc=M.op(0xf9), + sta=M.op(0x99,5,0), + dcp=M.op(0xdb,7,0), isb=M.op(0xfb,7,0), jam=M.op(0xb2,0,0), las=M.op(0xbb), lax=M.op(0xbf), rla=M.op(0x3b,7,0), rra=M.op(0x7b,7,0), sha=M.op(0x9f,5,0), + shs=M.op(0x9b,5,0), shx=M.op(0x9e,5,0), slo=M.op(0x1b,7,0), sre=M.op(0x5b,7,0), } M.opaby = opaby for k,v in pairs(opaby) do M[k .. 'aby'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 3 end + local size = function() late,early = M.size_op(late,early) return 3 end local bin = function() local l65dbg=l65dbg - local x = op_eval_word(late,early) + local x = M.op_eval_word(late,early) return { v.opc, x&0xff, x>>8 } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) @@ -1032,10 +218,10 @@ for k,_ in pairs(opzay) do local aby = opaby[k] local ins = { cycles=aby.cycles } ins.size = function() local l65dbg=l65dbg - local r,x = M.pcall_za(op_eval, late, early) + local r,x = M.pcall_za(M.op_eval, late, early) if not r then return 3 end - size_ref(x) - x = word_normalize(x) + M.size_ref(x) + x = M.word_normalize(x) local zpy,zpv = opzpy[k], zeropage(x) if zpv and zpy then ins.size = 2 @@ -1048,7 +234,7 @@ for k,_ in pairs(opzay) do return 3 end ins.bin = function() local l65dbg=l65dbg - local x = word_normalize(op_eval(late, early)) + local x = M.word_normalize(M.op_eval(late, early)) -- since we assumed absolute on link phase, we must generate absolute in binary if zeropage(x) and opzpy[k] then io.stderr:write("warning: forcing aby on zpy operand for opcode " .. k .. "\n") end return { aby.opc, x&0xff, x>>8 } @@ -1056,8 +242,9 @@ for k,_ in pairs(opzay) do table.insert(M.section_current.instructions, ins) end end + cycles_def=2 xcross_def=0 local oprel={ - bcc=op(0x90), bcs=op(0xb0), beq=op(0xf0), bmi=op(0x30), bne=op(0xd0), bpl=op(0x10), bvc=op(0x50), bvs=op(0x70), + bcc=M.op(0x90), bcs=M.op(0xb0), beq=M.op(0xf0), bmi=M.op(0x30), bne=M.op(0xd0), bpl=M.op(0x10), bvc=M.op(0x50), bvs=M.op(0x70), } M.oprel = oprel for k,v in pairs(oprel) do M[k .. 'rel'] = function(label) @@ -1067,7 +254,7 @@ for k,v in pairs(oprel) do local op = { cycles=2 } op.size = function() offset = section.size - label = size_dc(label) + label = M.size_dc(label) return 2 end op.bin = function() local l65dbg=l65dbg @@ -1085,44 +272,47 @@ for k,v in pairs(oprel) do table.insert(M.section_current.instructions, op) end end + cycles_def=5 xcross_def=0 local opind={ - jmp=op(0x6c), - jam=op(0xd2,0), + jmp=M.op(0x6c), + jam=M.op(0xd2,0), } M.opind = opind for k,v in pairs(opind) do M[k .. 'ind'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 3 end + local size = function() late,early = M.size_op(late,early) return 3 end local bin = function() local l65dbg=l65dbg - local x = op_eval_word(late,early) + local x = M.op_eval_word(late,early) return { v.opc, x&0xff, x>>8 } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end + cycles_def=6 xcross_def=0 local opinx={ - adc=op(0x61), ['and']=op(0x21), cmp=op(0xc1), eor=op(0x41), lda=op(0xa1), ora=op(0x01), sbc=op(0xe1), sta=op(0x81), - dcp=op(0xc3,8), isb=op(0xe3,8), jam=op(0x52,0), lax=op(0xa3), rla=op(0x23,8), rra=op(0x63,8), sax=op(0x83), slo=op(0x03,8), - sre=op(0x43,8), + adc=M.op(0x61), ['and']=M.op(0x21), cmp=M.op(0xc1), eor=M.op(0x41), lda=M.op(0xa1), ora=M.op(0x01), sbc=M.op(0xe1), sta=M.op(0x81), + dcp=M.op(0xc3,8), isb=M.op(0xe3,8), jam=M.op(0x52,0), lax=M.op(0xa3), rla=M.op(0x23,8), rra=M.op(0x63,8), sax=M.op(0x83), slo=M.op(0x03,8), + sre=M.op(0x43,8), } M.opinx = opinx for k,v in pairs(opinx) do M[k .. 'inx'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early) } end + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end + cycles_def=5 xcross_def=1 local opiny={ - adc=op(0x71), ['and']=op(0x31), cmp=op(0xd1), eor=op(0x51), lda=op(0xb1), ora=op(0x11), sbc=op(0xf1), sta=op(0x91,6), - dcp=op(0xd3,8), isb=op(0xf3,8), jam=op(0x62,0,0), lax=op(0xb3), rla=op(0x33,8), rra=op(0x73,8), sha=op(0x93,6), slo=op(0x13,8), - sre=op(0x53,8), + adc=M.op(0x71), ['and']=M.op(0x31), cmp=M.op(0xd1), eor=M.op(0x51), lda=M.op(0xb1), ora=M.op(0x11), sbc=M.op(0xf1), sta=M.op(0x91,6), + dcp=M.op(0xd3,8), isb=M.op(0xf3,8), jam=M.op(0x62,0,0), lax=M.op(0xb3), rla=M.op(0x33,8), rra=M.op(0x73,8), sha=M.op(0x93,6), slo=M.op(0x13,8), + sre=M.op(0x53,8), } for k,v in pairs(opiny) do M[k .. 'iny'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, op_eval_byte(late,early) } end + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end diff --git a/CMakeLists.txt b/CMakeLists.txt index b16cbac..1c9469f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ set(L65_HEADERS file(GLOB L65_FILES ${L65_SOURCE_DIR}/*.l65) set(L65_SCRIPTS + ${L65_SOURCE_DIR}/asm.lua ${L65_SOURCE_DIR}/6502.lua ${L65_SOURCE_DIR}/dkjson.lua ${L65_SOURCE_DIR}/l65.lua diff --git a/asm.lua b/asm.lua new file mode 100644 index 0000000..a8bf5a1 --- /dev/null +++ b/asm.lua @@ -0,0 +1,837 @@ +local M = {} + +local symbols,symbolsorg={},{} M.symbols,M.symbolsorg=symbols,symbolsorg +local locations={} M.locations=locations +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.strip_empty = false -- set to true to strip empty sections: their label will then not resolve +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) + +local id_ = 0 +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) + if type(val) == 'table' and val.type == 'label' then + val.section.refcount = val.section.refcount + 1 + end + return val + end + end + for _,section in ipairs(sections) do + section:compute_size() + end + symbols.__index = symbols + + local chunk_reserve = function(section, chunk_ix) + local chunks = section.location.chunks + local chunk = chunks[chunk_ix] + local holes = section.holes + local new_chunks,ins = {},table.insert + + local chunk1 = { id=id(), start=chunk.start, size=section.org-chunk.start } + local hole_ix = 1 + local hole1 = holes[1] + if hole1 and hole1.start==0 then + chunk1.size = chunk1.size + hole1.size + hole_ix = 2 + end + if chunk1.size > 0 then ins(new_chunks, chunk1) end + while hole_ix <= #holes do + local hole = holes[hole_ix] + local chunki = { id=id(), start=section.org+hole.start, size=hole.size } + ins(new_chunks, chunki) + hole_ix = hole_ix + 1 + end + local chunkl = { id=id(), start=section.org+section.size, size=chunk.start+chunk.size-(section.org+section.size) } + local chunkn = new_chunks[#new_chunks] + if chunkn and chunkn.start+chunkn.size==chunkl.start then + chunkn.size = chunkn.size + chunkl.size + elseif chunkl.size > 0 then + ins(new_chunks, chunkl) + end + + table.remove(chunks, chunk_ix) + 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,cross,lsb,position = math.maxinteger,math.maxinteger,math.maxinteger + local usage_lowest = function(start, finish) + local inc=1 + if section.align then + local rstart = rorg(start) + local arstart = (rstart + section.align - 1) // section.align * section.align + if section.offset then arstart = arstart + section.offset end + start = start + arstart-rstart + inc = section.align + end + for address=start,finish,inc do + 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 + 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 + section.org = position + chunk_reserve(section, chunk_ix) + --print(section.label, string.format("%04X\t%d", position, section.size)) + --for k,v in ipairs(location.chunks) do print(string.format(" %04X %04X %d", v.start, v.size+v.start-1, v.size)) end + return position + end + end end + end + + stats.used = 0 + stats.unused = 0 + stats.cycles = 0 + local related_sections = {} + for _,location in ipairs(locations) do + local sections,rorg = location.sections,location.rorg + + -- filter sections list + local position_independent_sections = {} + local symbols_to_remove = {} + local section_count = #sections + location.cycles=0 location.used=0 + for ix,section in ipairs(sections) do + location.cycles = location.cycles + section.cycles + location.used = location.used + section.size + if section.size == 0 then + if M.strip_empty or section.weak then + sections[ix]=nil + if not section.org then table.insert(symbols_to_remove, section.label) end + else + section.org = location.start + end + elseif not section.org then + if M.strip and not section.refcount and not section.strong then + sections[ix]=nil + table.insert(symbols_to_remove, section.label) + elseif section.related then + table.insert(related_sections, section) + 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 + end end + for _,v in ipairs(symbols_to_remove) do symbols[v] = nil end + location.position_independent_sections = position_independent_sections + stats.cycles = stats.cycles + location.cycles + stats.used = stats.used + location.used + + -- 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 or math.huge) 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(section, chunk_ix) + goto chunk_located + end + end + error("ORG section " .. section.label .. " overflows its location") + ::chunk_located:: + end end + end + + table.sort(related_sections, function(a,b) if a.size==b.size then return a.idb.size end) + for _,section in ipairs(related_sections) do if not section.org then + local related,ins = {},table.insert + local function collect(section_parent, offset) + local relatives = relations[section_parent] + if relatives then + for relative,relative_offset in pairs(relatives) do + if not related[relative] and relative ~= section then + relative_offset = relative_offset + offset + related[relative] = relative_offset + collect(relative, relative_offset) + end + end + end + end + collect(section, 0) + local location_start = section.location.start + 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 section_address = address + (section.location.start - location_start) + offset + local nwaste, ncross, nlsb = check_section_position(section, section_address) + 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 + (section.location.start - location_start) + offset + local chunk,chunk_ix = chunk_from_address(section, section.org) + chunk_reserve(section, chunk_ix) + end + end end + + for _,location in ipairs(locations) do + local position_independent_sections = location.position_independent_sections + table.sort(position_independent_sections, function(a,b) if a.size==b.size then return a.label>b.label end return a.size>b.size end) + for _,section in ipairs(position_independent_sections) do + if not position_section(section) then + error("unable to find space for section " .. section.label) + end + end + + -- unused space stats + local unused = 0 + for _,chunk in ipairs(location.chunks) do + if chunk.size ~= math.huge then + unused = unused + chunk.size + else + location.stops_at = chunk.start-1 + end + end + location.unused = unused + stats.unused = stats.unused + unused + + end +end + +M.resolve = function() + if stats.resolved_count then return end + M.link() + + stats.resolved_count = 0 + repeat local count = 0 + for k,v in pairs(symbols) do if k ~= '__index' then + local t = type(v) + if t == 'function' then v=v() t=type(v) symbols[k]=v count=count+1 end + if t == 'table' and type(v.resolve) == 'function' then symbols[k],symbolsorg[k]=v.resolve() count=count+1 end + if t == 'string' and symbols[v] then symbols[k]=symbols[v] count=count+1 end + stats.resolved_count = stats.resolved_count + count + end end until count == 0 + + -- set local label references resolver + local llresolver = { __index = function(tab,key) + 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) +end + +M.genbin = function(filler) + if #locations == 0 then return end + if not filler then filler = 0 end -- brk opcode + M.resolve() + local bin = {} + local ins,mov = table.insert,table.move + table.sort(locations, function(a,b) return a.start < b.start end) + local of0 = locations[1].start + local fill + for _,location in ipairs(locations) do + if location.start < #bin then + error(string.format("location [%04x,%04x] overlaps another", location.start, location.finish or location.stops_at)) + end + if fill then for i=#bin+of0,location.start-1 do ins(bin, filler) end end + M.size=0 M.cycles=0 + local sections = location.sections + table.sort(sections, function(a,b) return a.org < b.org end) + for _,section in ipairs(sections) do + for i=#bin+of0,section.org-1 do ins(bin, filler) end + local bin_offset = math.min(#bin, section.org-of0)+1 + for _,instruction in ipairs(section.instructions) do + local b,o = instruction.bin + if type(b) == 'function' then b,o = b(filler) end + if type(b) == 'table' then mov(b,1,#b,bin_offset,bin) bin_offset=bin_offset+#b + elseif b then bin[bin_offset]=b bin_offset=bin_offset+1 end + if o then + bin_offset=bin_offset+o + for i=#bin,bin_offset-1 do ins(bin, filler) end + end + M.size=#bin M.cycles=M.cycles+(instruction.cycles or 0) + end + end + fill = not location.nofill + if location.finish and fill then + for i=#bin+of0,location.finish do ins(bin, filler) end + end + end + stats.bin_size = #bin + return bin +end + +M.writebin = function(filename, bin) + if not filename then filename = 'main.bin' end + if not bin then bin = M.genbin() end + local f = assert(io.open(filename, "wb"), "failed to open " .. filename .. " for writing") + f:write(string.char(table.unpack(bin))) + f:close() +end + +-- return a table of entry(address, label) +M.getsym = function(entry) + local ins = table.insert + local s,sym_rev = {},{} + for k,v in pairs(symbols) do if type(v) == 'number' then ins(sym_rev,k) end end + table.sort(sym_rev, function(a,b) local x,y=symbols[a],symbols[b] if x==y then return a 1 then + ins(s, string.format(" --- Total --- %5d %5d %5d", stats.unused, stats.used, stats.bin_size)) + end + return table.concat(s, '\n') +end + +M.location = function(start, finish) + local location + if type(start) ~= 'table' then + location = { start=start, finish=finish } + else + if start.type == 'location' then + for _,v in ipairs(locations) do if v == start then + M.location_current = start + return start + end end + error("unable to find reference to location [" .. (start.start or '?') .. ", " .. (start.finish or '?') .. "]") + end + location = start + location.start = start[1] + location.finish = start[2] + if type(location.rorg) == 'number' then + local offset = location.rorg - location.start + location.rorg = function(x) return x+offset end + end + end + location.type = 'location' + 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 } } + locations[#locations+1] = location + M.location_current = location + return location +end + +M.section = function(t) + local section = {} + local name = t or 'S'..id() + if type(name) ~= 'string' then + assert(type(t) == 'table', "invalid arguments for section") + if t.type == 'section' then + for _,v in ipairs(sections) do if v == t then + M.location_current = t.location + M.section_current = t + return t + end end + error("unable to find reference to section " .. (t.label or '?')) + end + 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) + table.insert(M.sections, section) + section.location = M.location_current + M.section_current = section + section.type = 'section' + section.id = id() + section.constraints = {} + section.instructions = {} + assert(name:sub(1,1) ~= '_', "sections can't be named with a local label") + section.label = M.label(name) + section.holes = {} + section.refcount = 0 + function section:compute_size() + local instructions = self.instructions + self.size=0 self.cycles=0 + for _,instruction in ipairs(instructions) do + instruction.offset = self.size + local ins_sz = instruction.size or 0 + if type(ins_sz) == 'function' then + -- evaluation is needed to get the size (distinguish zpg/abs) + -- labels and sections are not resolved at this point, so + -- evaluation will fail if the size is not explicitly stated (.b/.w); + -- in that case, assume max size + ins_sz = ins_sz() + end + self.size = self.size + ins_sz + self.cycles = self.cycles + (instruction.cycles or 0) + end + for _,constraint in ipairs(self.constraints) do + constraint.start = instructions[constraint.from].offset + constraint.finish = constraint.to==#instructions and self.size or instructions[constraint.to+1].offset + end + end + 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) + assert(section1.type == 'section', "section1 is not a section") + assert(section2.type == 'section', "section2 is not a section") + local rel1 = relations[section1] or {} + rel1[section2] = (offset2 or offset) or 0 + relations[section1] = rel1 + local rel2 = relations[section2] or {} + rel2[section1] = (offset2 and offset) or -rel1[section2] + 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 + label = { type='label', section=section } + if not name then name='_L'..id() end + if name:sub(1,1) == '_' then -- local label + name = M.label_current .. name + else + M.label_current = name + label.bin = function() M.label_current = name end + end + if symbols[name] then error("duplicate symbol: " .. name) end + symbols[name] = label + label.label = name + label.size = function() + offset = section.size + label.size = 0 + return 0 + end + label.resolve = function() + local o = section.org + offset + return rorg(o),o + end + table.insert(section.instructions, label) + return name,label +end + +M.samepage = function() + local section = M.section_current + table.insert(section.constraints, { type='samepage', from=#section.instructions+1 }) +end +M.crosspage = function() + local section = M.section_current + table.insert(section.constraints, { type='crosspage', from=#section.instructions+1 }) +end +M.endpage = function() + local section = M.section_current + local constraint = section.constraints[#section.constraints] + assert(constraint and not constraint.to, "closing constraint, but no constraint is open") + constraint.to = #section.instructions +end + +-- skip(bytes) +-- Insert a hole in the section of 'bytes' bytes, which can be used by other +-- relocatable sections. +M.skip = function(bytes) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local ins,section = {},M.section_current + ins.size = function() + table.insert(section.holes, { start=ins.offset, size=bytes }) + return bytes + end + ins.bin = function(filler) return nil,bytes end + table.insert(section.instructions, ins) +end + +-- sleep(cycles [, noillegal]) +-- Waste 'cycles' cycles. If 'noillegal' is true, trashes NZ flags. +M.sleep = function(cycles, noillegal) + assert(cycles > 1, "can't sleep for less than 2 cycles") + if cycles & 1 ~= 0 then + if noillegal then bitzpg(0) else nopzpg(0) end + cycles = cycles - 3 + end + for i=1,cycles/2 do nopimp() end +end + +local op_resolve = function(v) + if type(v) == 'function' then v=v() end + if type(v) == 'table' and v.label then v = symbols[v.label] end + if type(v) == 'string' then v = symbols[v] end + if type(v) ~= 'number' then error("unresolved symbol: " .. tostring(v)) end + return v +end M.op_resolve = op_resolve + +local size_ref = function(v) + if type(v) == 'string' then v=symbols[v] end + if type(v) == 'table' and v.type == 'label' then v.section.refcount = 1 + (v.section.refcount or 0) end +end +M.size_ref = size_ref + +local size_dc = function(v) + if type(v) == 'function' then + local r,x = M.pcall(v) + if not r or not x then return v end + end + size_ref(v) + return v +end +M.size_dc = size_dc + +local size_op = function(late, early) + if type(late) == 'function' then + local r,x = M.pcall(late, early or 0, op_resolve) + if not r or not x then return late,early end + late=x early=nil + end + size_ref(late) size_ref(early) + return late,early +end +M.size_op = size_op + +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 + return v & 0xff +end +M.byte_normalize = byte_normalize + +local word_normalize = function(v) + if v < -0x8000 or v > 0xFFFF then error("value out of word range: " .. v) end + if v < 0 then v = v + 0x10000 end + return v & 0xffff +end +M.word_normalize = word_normalize + +local long_normalize = function(v) + if v < -0x80000000 or v > 0xFFFFFFFF then error("value out of word range: " .. v) end + if v < 0 then v = v + 0x100000000 end + return v & 0xffffffff +end +M.long_normalize = long_normalize + +-- charset([s] [, f]) +-- Set a new charset to be used for next string data in byte(). +-- Without argument, revert to Lua charset. +-- s: string of all letters of charset +-- f: letter index offset or function to transform the letter index +M.charset = function(s, f) + local st = type(s) + if st == 'nil' then M.cs = nil return s end + if st == 'table' then M.cs = s return s end + if not f then f = function(v) return v end + elseif type(f) == 'number' then f = function(v) return v + f end end + local t,i={},0 + for c in s:gmatch'.' do local v=i t[c]=function() return f(v) end i=i+1 end + M.cs=t + return t +end + +M.byte_impl = function(args, nrm) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local data,cs = {},M.cs + for k,v in ipairs(args) do + local t = type(v) + if t == 'number' or t == 'function' then data[#data+1] = v + elseif t == 'table' then table.move(v,1,#v,#data+1,data) + elseif t == 'string' then + if cs then + for c in v:gmatch'.' do + local i=cs[c] + if not i then error("character " .. c .. " is not part of current charset") end + data[#data+1]=i + end + else + local s = {v:byte(1,#v)} + table.move(s, 1, #s, #data+1, data) + end + 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 bin = function() local l65dbg=l65dbg + local b={} + for k,v in ipairs(data) do + if type(v) == 'function' then v = v() end + local vt = type(v) + if vt == 'table' and v.label then v = symbols[v.label] + elseif vt == 'string' then v = symbols[v] end + if type(v) ~= 'number' then error("unresolved symbol for dc.b, index " .. k) end + b[#b+1] = nrm(v) + end + return b + end + table.insert(M.section_current.instructions, { data=data, size=size, bin=bin }) +end +-- byte(...) +-- Declare bytes to go into the binary stream. +-- Each argument can be either: +-- * a number resolving to a valid range byte +-- * a string, converted to bytes using the charset previously defined, +-- or Lua's charset if none was defined +-- * a table, with each entry resolving to a valid range byte +-- * a function, resolving to exactly one valid range byte, evaluated +-- after symbols have been resolved +M.byte = function(...) + return M.byte_impl({...}, byte_normalize) +end +local byte_encapsulate = function(args) + for k,v in ipairs(args) do + local vt = type(v) + if vt == 'string' or vt == 'table' and (v.type == 'section' or v.type == 'label') then + args[k] = function() return v end + end + end + return args +end +M.byte_hi = function(...) + return M.byte_impl(byte_encapsulate{...}, function(v) return (v>>8)&0xff end) +end +M.byte_lo = function(...) + return M.byte_impl(byte_encapsulate{...}, function(v) return v&0xff end) +end + +-- word(...) +-- Declare words to go into the binary stream. +-- Each argument can be either: +-- * a section or a label +-- * a number resolving to a valid range word +-- * a table, with each entry resolving to a valid range word +-- * a function, resolving to exactly one valid range word, evaluated +-- after symbols have been resolved +M.word = function(...) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local args = {...} + local data = {} + for k,v in ipairs(args) do + local t = type(v) + if t == 'number' or t == 'function' or t == 'string' then data[#data+1] = v + elseif t == 'table' then + if v.type == 'section' or v.type == 'label' then data[#data+1] = function() return v end + else table.move(v,1,#v,#data+1,data) end + 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 bin = function() local l65dbg=l65dbg + local b={} + for k,v in ipairs(data) do + if type(v) == 'function' then v = v() end + local vt = type(v) + if vt == 'table' and v.label then v = symbols[v.label] + elseif vt == 'string' then v = symbols[v] end + if type(v) ~= 'number' then error("unresolved symbol for dc.w, index " .. k) end + v = word_normalize(v) + b[#b+1] = v&0xff + b[#b+1] = v>>8 + end + return b + end + table.insert(M.section_current.instructions, { data=data, size=size, bin=bin }) +end + +M.long = function(...) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local args = {...} + local data = {} + for k,v in ipairs(args) do + local t = type(v) + if t == 'number' or t == 'function' or t == 'string' then data[#data+1] = v + elseif t == 'table' then + if v.type == 'section' or v.type == 'label' then data[#data+1] = function() return v end + else table.move(v,1,#v,#data+1,data) end + 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 bin = function() local l65dbg=l65dbg + local b={} + for k,v in ipairs(data) do + if type(v) == 'function' then v = v() end + local vt = type(v) + if vt == 'table' and v.label then v = symbols[v.label] + elseif vt == 'string' then v = symbols[v] end + if type(v) ~= 'number' then error("unresolved symbol for dc.l, index " .. k) end + v = long_normalize(v) + b[#b+1] = v&0xff + b[#b+1] = (v>>8)&0xff + b[#b+1] = (v>>16)&0xff + b[#b+1] = v>>24 + end + return b + end + table.insert(M.section_current.instructions, { data=data, size=size, bin=bin }) +end + +local op = function(code, cycles, extra_on_crosspage) + return { opc=code, cycles=cycles or cycles_def, xcross=extra_on_crosspage or xcross_def } +end +M.op = op + +local op_eval = function(late, early) + local x = early or 0 + return type(late) == 'function' and late(x,op_resolve) or x+op_resolve(late) +end +M.op_eval = op_eval + +local op_eval_byte = function(late, early, nozp) + local v = op_eval(late, early) + local zpv = zeropage(v) + if not nozp and zpv then return zpv end + return byte_normalize(v) +end +M.op_eval_byte = op_eval_byte + +local op_eval_word = function(late, early) return word_normalize(op_eval(late, early)) end +M.op_eval_word = op_eval_word + +return M \ No newline at end of file diff --git a/main.c b/main.c index 16f3599..ce601b2 100644 --- a/main.c +++ b/main.c @@ -164,7 +164,7 @@ static int getembedded(lua_State *L) } } return 0; -} +} static int msghandler(lua_State *L) { @@ -189,6 +189,8 @@ int main(int argc, char *argv[]) // preload embedded lua scripts luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + luaL_loadbufferx(L, script_asm_lua, sizeof(script_asm_lua), "asm.lua", "b"); + lua_setfield(L, -2, "asm"); luaL_loadbufferx(L, script_6502_lua, sizeof(script_6502_lua), "6502.lua", "b"); lua_setfield(L, -2, "6502"); lua_pop(L, 1); From e88b89cd01f84ff5758b31c0a9c417ca8087066d Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 4 Nov 2018 22:52:47 +0100 Subject: [PATCH 02/41] Started working adding uPD7801 --- uPD7801.lua | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 uPD7801.lua diff --git a/uPD7801.lua b/uPD7801.lua new file mode 100644 index 0000000..61e98b2 --- /dev/null +++ b/uPD7801.lua @@ -0,0 +1,304 @@ +M = require "asm" + +local cycles_def,xcross_def +local opimp={ + block=M.op(0x31,13), + calb=M.op(0x63,13), + daa=M.op(0x61,4), + exa=M.op(0x10,4), + exx=M.op(0x11,4), + halt=M.op(0x01,6), + jb=M.op(0x73,4), + nop=M.op(0x00,4), + ret=M.op(0x08,11), + reti=M.op(0x62,15), + rets=M.op(0x18,11), + sio=M.op(0x09,4), + softi=M.op(0x72,19), + stm=M.op(0x19,4), + table=M.op(0x21,19) +} M.opimp = opimp +for k,v in pairs(opimp) do + M[k] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local opa={ + dcr=M.op(0x51,4), + inr=M.op(0x41,4) +} M.opa = opa +for k,v in pairs(opa) do + M[k .. 'a'] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local opb={ + dcr=M.op(0x52,4), + inr=M.op(0x42,4) +} M.opb = opb +for k,v in pairs(opb) do + M[k .. 'b'] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local opc={ + dcr=M.op(0x53,4), + inr=M.op(0x43,4), +} M.opc = opc +for k,v in pairs(opc) do + M[k .. 'c'] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local opd={ + ldaxm=M.op(0x2e,7), + ldaxp=M.op(0x2c 7), + staxm=M.op(0x3e,7), + staxp=M.op(0x3c,7), +} M.opd = opd +for k,v in pairs(opd) do + M[k .. 'd'] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local oph={ + ldaxm=M.op(0x2f,7), + ldaxp=M.op(0x2d,7), + staxm=M.op(0x3f,7), + staxp=M.op(0x3d,7) +} M.oph = oph +for k,v in pairs(oph) do + M[k .. 'h'] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local opind={ + dcxbc=M.op(0x13,7), + dcxde=M.op(0x23,7), + dcxhl=M.op(0x33,7), + inxbc=M.op(0x12,7), + inxde=M.op(0x22,7), + inxhl=M.op(0x32,7), + ldaxbc=M.op(0x29,7), + ldaxde=M.op(0x2a,7), + ldaxhl=M.op(0x2b,7), + staxbc=M.op(0x39,7), + staxde=M.op(0x3a,7), + staxhl=M.op(0x3b,7), +} M.oprwind = oprwind +for k,v in pairs(oprwind) do + M[k .. 'ind'] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local opindxx ={ + mvixbc=M.op(0x49,10), + mvixde=M.op(0x4a,10), + mvixhl=M.op(0x4b,10) +} M.opindxx = opindxx +for k,v in pairs(opindxx) do + M[k .. 'indxx'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + +local opsp={ + dcx=M.op(0x03,7), + inx=M.op(0x02,7) +} M.opsp = opsp +for k,v in pairs(opsp) do + M[k .. 'sp'] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local oprr={ + movab=M.op(0x0a,4), movac=M.op(0x0b,4), + movad=M.op(0x0c,4), movae=M.op(0x0d,4), + movah=M.op(0x0e,4), moval=M.op(0x0f,4), + movba=M.op(0x1a,4), movca=M.op(0x1b,4), + movda=M.op(0x1c,4), movea=M.op(0x1d,4), + movha=M.op(0x1e,4), movla=M.op(0x1f,4), +} M.oprr = oprr +for k,v in pairs(oprr) do + M[k] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + +local oprxx ={ + mvib=M.op(0x6a,7), + mvic=M.op(0x6b,7), + mvid=M.op(0x6c,7), + mvie=M.op(0x6d,7), + mvih=M.op(0x6e,7), + mvil=M.op(0x6f,7), + mviv=M.op(0x68,7) +} M.oprxx = oprxx +for k,v in pairs(oprxx) do + M[k .. 'xx'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + +local opaxx={ + aci=M.op(0x56,7), + adi=M.op(0x46,7), + adinc=M.op(0x26,7), + ani=M.op(0x07,7), + eqi=M.op(0x77,7), + gti=M.op(0x27,7), + lti=M.op(0x37,7), + mvi=M.op(0x69,7), + nei=M.op(0x69,7), + offi=M.op(0x57,7), + oni=M.op(0x47,7), + ori=M.op(0x17,7), + sbi=M.op(0x76,7), + sui=M.op(0x61,7), + suinb=M.op(0x36,7), + xri=M.op(0x16,7) +} M.opaxx = opaxx +for k,v in pairs(opaxx) do + M[k .. 'axx'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + +local opvind ={ + inrw=M.op(0x20,13), + ldaw=M.op(0x28,10), + dcrw=M.op(0x30,13), + staw=M.op(0x38,10), + bit0=M.op(0x58,10), + bit1=M.op(0x59,10), + bit2=M.op(0x5a,10), + bit3=M.op(0x5b,10), + bit4=M.op(0x5c,10), + bit5=M.op(0x5d,10), + bit6=M.op(0x5e,10), + bit7=M.op(0x5f,10) +} M.opvind = opvind +for k,v in pairs(opvind) do + M[k .. 'vind'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + +--[[ [todo] +local opvindxx ={ + aniw=M.op(0x05,16), + oriw=M.op(0x15,16), + gtiw=M.op(0x25,13), + ltiw=M.op(0x35,13), + oniw=M.op(0x45,13), + offiw=M.op(0x55,13), + neiw=M.op(0x65,13), + mviw=M.op(0x71,13), + eqiw=M.op(0x75,13) +} M.opvindxx = opvindxx +for k,v in pairs(opvindxx) do + M[k .. 'vindxx'] = function(late0, early0, late1, early1) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() + late0,early0 = M.size_op(late,early) + late1,early1 = M.size_op(late,early) + return 3 + end + local bin = function() + local l65dbg=l65dbg + local offset = M.op_eval_byte(late0,early0) + local x = M.op_eval_byte(late1,early1) + return { v.opc, offset, x } + end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end +]]-- + +local opwwww = { + call=M.op(0x44,16), + jmp=M.op(0x54,10), + lxisp=M.op(0x04,10), + lxibc=M.op(0x14,10), + lxide=M.op(0x24,10), + lxihl=M.op(0x34,10) +} M.opwwww = opwwww +for k,v in pairs(opwwww) do + M[k .. 'wwww'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 3 end + local bin = function() local l65dbg=l65dbg + local x = M.op_eval_word(late,early) + return { v.opc, x&0xff, x>>8 } + end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + +for i=0x80,0xbf,1 do + M['calt' .. i]=M.op(i,cycles) + table.insert(M.section_current.instructions, { size=1, cycles=19, bin=i}) +end + + +M['jr'] = function(label) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local parent,offset = M.label_current + local section,rorg = M.section_current,M.location_current.rorg + local op = { cycles=13, size=1 } + op.bin = function() local l65dbg=l65dbg + local x,l = label,label + if type(x) == 'function' then x=x() end + if type(x) == 'string' then + if x:sub(1,1) == '_' then x=parent..x l=x end + x = symbols[x] + end + if type(x) ~= 'number' then error("unresolved branch target: " .. tostring(x)) end + x = x - offset - rorg(section.org) + if x < -32 or x > 0x32 then error("branch target out of range for " .. l .. ": " .. x) end + elseif x >= 0 then + return 0xc0 + x + else + return x + end + end + table.insert(M.section_current.instructions, op) +end + +return M + +--[[ [todo] +8 bits instructions: + JRE+ 0x4e xx 17 + JRE- 0x4f xx 17 + CALF 0x78-0x75 xx 16 + +16 bits instructions: + 0x48xx + 0x4cxx + 0x4dxx + 0x60xx + 0x64xx + 0x70xx + 0x74xx +]]-- From d5c53b2f01a085794ae0e4b64acc2f1d022b79a3 Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 4 Nov 2018 23:12:28 +0100 Subject: [PATCH 03/41] op_eval_byte and op_eval_word are now arch specific. --- 6502.lua | 12 ++++++++++++ uPD7801.lua | 9 +++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/6502.lua b/6502.lua index 8c9a8c1..f105857 100644 --- a/6502.lua +++ b/6502.lua @@ -3,6 +3,17 @@ M = require "asm" -- Return a value in rage [0x00, 0xff] if x is to use zeropage addressing mode. Defaults to range [0x0000-0x00ff]. M.zeropage = function(x) if x >= -128 and x <= 0xff then return M.byte_normalize(x) end end +local op_eval_byte = function(late, early, nozp) + local v = op_eval(late, early) + local zpv = zeropage(v) + if not nozp and zpv then return zpv end + return byte_normalize(v) +end +M.op_eval_byte = op_eval_byte + +local op_eval_word = function(late, early) return word_normalize(op_eval(late, early)) end +M.op_eval_word = op_eval_word + local cycles_def,xcross_def cycles_def=2 xcross_def=0 local opimp={ @@ -31,6 +42,7 @@ for k,v in pairs(opimm) do table.insert(M.section_current.instructions, { size=size, cycles=2, bin=bin }) end end + cycles_def=3 xcross_def=0 local opzpg={ adc=M.op(0x65), ['and']=M.op(0x25), asl=M.op(0x06,5), bit=M.op(0x24), cmp=M.op(0xc5), cpx=M.op(0xe4), cpy=M.op(0xc4), dec=M.op(0xc6,5), eor=M.op(0x45), inc=M.op(0xe6,5), lda=M.op(0xa5), ldx=M.op(0xa6), ldy=M.op(0xa4), lsr=M.op(0x46,5), ora=M.op(0x05), rol=M.op(0x26,5), diff --git a/uPD7801.lua b/uPD7801.lua index 61e98b2..d66884d 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -1,6 +1,11 @@ M = require "asm" -local cycles_def,xcross_def +local op_eval_byte = function(late, early) return byte_normalize(op_eval(late, early)) end +M.op_eval_byte = op_eval_byte + +local op_eval_word = function(late, early) return word_normalize(op_eval(late, early)) end +M.op_eval_word = op_eval_word + local opimp={ block=M.op(0x31,13), calb=M.op(0x63,13), @@ -261,7 +266,7 @@ for i=0x80,0xbf,1 do end -M['jr'] = function(label) +M.jr = function(label) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local parent,offset = M.label_current local section,rorg = M.section_current,M.location_current.rorg From f8ad543033038ecdc44b7fa3f379d83efc577545 Mon Sep 17 00:00:00 2001 From: mooz Date: Tue, 6 Nov 2018 00:29:27 +0100 Subject: [PATCH 04/41] first uPD7801 assembler tests. --- asm.lua | 11 - l65.lua | 3 +- l7801.lua | 2421 +++++++++++++++++++++++++++++++++++++++++++++++++++ uPD7801.lua | 46 +- 4 files changed, 2454 insertions(+), 27 deletions(-) create mode 100644 l7801.lua diff --git a/asm.lua b/asm.lua index a8bf5a1..f1e7963 100644 --- a/asm.lua +++ b/asm.lua @@ -823,15 +823,4 @@ local op_eval = function(late, early) end M.op_eval = op_eval -local op_eval_byte = function(late, early, nozp) - local v = op_eval(late, early) - local zpv = zeropage(v) - if not nozp and zpv then return zpv end - return byte_normalize(v) -end -M.op_eval_byte = op_eval_byte - -local op_eval_word = function(late, early) return word_normalize(op_eval(late, early)) end -M.op_eval_word = op_eval_word - return M \ No newline at end of file diff --git a/l65.lua b/l65.lua index 0db5ef0..a9f2dae 100644 --- a/l65.lua +++ b/l65.lua @@ -32,7 +32,7 @@ local Keywords = lookupify{ 'return', 'then', 'true', 'until', 'while', }; --- 6502 +-------------------------------------------------------- 6502::begin local Keywords_control = { -- control keywords 'samepage', 'crosspage', @@ -168,6 +168,7 @@ local addressing_map = { iny = opcode_indirect_y, rel = opcode_relative, } +-------------------------------------------------------- 6502::end local Scope = { new = function(self, parent) diff --git a/l7801.lua b/l7801.lua new file mode 100644 index 0000000..cd68a43 --- /dev/null +++ b/l7801.lua @@ -0,0 +1,2421 @@ +#!/usr/bin/env lua + +local function lookupify(tb, dst, not_val) + if not dst then dst = tb end + local val = not not_val + for _, v in pairs(tb) do + dst[v] = val + end + return tb +end + +local WhiteChars = lookupify{' ', '\n', '\t', '\r'} +local Spaces = lookupify{' ', '\t'} +local EscapeLookup = {['\r'] = '\\r', ['\n'] = '\\n', ['\t'] = '\\t', ['"'] = '\\"', ["'"] = "\\'"} +local LowerChars = lookupify{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'} +local UpperChars = lookupify{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'} +local Digits = lookupify{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'} +local HexDigits = lookupify{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'a', 'B', 'b', 'C', 'c', 'D', 'd', 'E', 'e', 'F', 'f'} +local BinDigits = lookupify{'0', '1'} + +local Symbols = lookupify{'+', '-', '*', '/', '^', '%', ',', '{', '}', '[', ']', '(', ')', ';', '#', '&', '|', '!'} + +local Keywords = lookupify{ + 'and', 'break', 'do', 'else', 'elseif', + 'end', 'false', 'for', 'function', 'goto', 'if', + 'in', 'local', 'nil', 'not', 'or', 'repeat', + 'return', 'then', 'true', 'until', 'while', +}; + +local Keywords_control = { +} +local Keywords_data = { + 'dc', +} +local Keywords_7801 = { + 'block', 'calt', 'dcr', 'jr', 'lxi', 'mvi', 'nop' +} +local Registers_7801 = { + a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, + bc=16,de=16,hl=16,sp=16 +} + +local function syntax7801(on) + syntax7801_on = on + lookupify(Keywords_control, Keywords, not on) + lookupify(Keywords_data, Keywords, not on) + lookupify(Keywords_7801, Keywords, not on) +end +syntax7801(true) + +local opcode_arg_encapsulate_on +local function opcode_arg_encapsulate(on) + opcode_arg_encapsulate_on = not 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_alias = {} -- alternate user names for opcodes +local opcode_implied = lookupify{ + 'block', 'dcr', 'nop' +} +local opcode_immediate = lookupify{ + 'calt', 'lxi', 'mvi' +} +local opcode_relative = lookupify{ + 'jr', +} + +local addressing_map = { + imp = opcode_implied, + imm = opcode_immediate, + rel = opcode_relative, +} + +local Scope = { + new = function(self, parent) + local s = { + Parent = parent, + Locals = { }, + Globals = { }, + Children = { }, + } + + if parent then + table.insert(parent.Children, s) + end + + return setmetatable(s, { __index = self }) + end, + + AddLocal = function(self, v) + table.insert(self.Locals, v) + end, + + AddGlobal = function(self, v) + table.insert(self.Globals, v) + end, + + CreateLocal = function(self, name) + local v + v = self:GetLocal(name) + if v then return v end + v = { } + v.Scope = self + v.Name = name + v.IsGlobal = false + self:AddLocal(v) + return v + end, + + GetLocal = function(self, name) + for k, var in pairs(self.Locals) do + if var.Name == name then return var end + end + + if self.Parent then + return self.Parent:GetLocal(name) + end + end, + + CreateGlobal = function(self, name) + local v + v = self:GetGlobal(name) + if v then return v end + v = { } + v.Scope = self + v.Name = name + v.IsGlobal = true + self:AddGlobal(v) + return v + end, + + GetGlobal = function(self, name) + for k, v in pairs(self.Globals) do + if v.Name == name then return v end + end + + if self.Parent then + return self.Parent:GetGlobal(name) + end + end, +} + +local function LexLua(src) + --token dump + local tokens = {} + + local st, err = pcall(function() + --line / char / pointer tracking + local p = 1 + local line = 1 + local char = 1 + + --get / peek functions + local function get() + local c = src:sub(p,p) + if c == '\n' then + char = 1 + line = line + 1 + else + char = char + 1 + end + p = p + 1 + return c + end + local function get_n(count) for i=1,count do get() end end + local function peek(n) + n = n or 0 + return src:sub(p+n,p+n) + end + local function peek_n(sz) return src:sub(p, p+sz-1) end + local function consume(chars) + local c = peek() + for i = 1, #chars do + if c == chars:sub(i,i) then return get() end + end + end + local function get_word(spaces) + if not spaces then spaces = Spaces end + local c + repeat get() c = peek() until not spaces[c] + local start = p + repeat get() c = peek() until not (UpperChars[c] or LowerChars[c] or Digits[c] or c == '_') + return src:sub(start, p-1) + end + local function peek_ident(i, spaces) + if not spaces then spaces = Spaces end + local c + while true do c=peek(i) if not spaces[c] then break end i=i+1 end + if not (UpperChars[c] or LowerChars[c] or c == '_') then return end + local start = p+i + repeat i=i+1 c = peek(i) until not (UpperChars[c] or LowerChars[c] or Digits[c] or c == '_') + return src:sub(start, p+i-1),i,c + end + + --shared stuff + local function generateError(err) + return error(">> :"..line..":"..char..": "..err, 0) + end + + local function tryGetLongString() + local start = p + if peek() == '[' then + local equalsCount = 0 + local depth = 1 + while peek(equalsCount+1) == '=' do + equalsCount = equalsCount + 1 + end + if peek(equalsCount+1) == '[' then + --start parsing the string. Strip the starting bit + for _ = 0, equalsCount+1 do get() end + + --get the contents + local contentStart = p + while true do + --check for eof + if peek() == '' then + generateError("Expected ']"..string.rep('=', equalsCount).."]' near .", 3) + end + + --check for the end + local foundEnd = true + if peek() == ']' then + for i = 1, equalsCount do + if peek(i) ~= '=' then foundEnd = false end + end + if peek(equalsCount+1) ~= ']' then + foundEnd = false + end + else + --[[ + if peek() == '[' then + -- is there an embedded long string? + local embedded = true + for i = 1, equalsCount do + if peek(i) ~= '=' then + embedded = false + break + end + end + if peek(equalsCount + 1) == '[' and embedded then + -- oh look, there was + depth = depth + 1 + for i = 1, (equalsCount + 2) do + get() + end + end + end + ]] + foundEnd = false + end + -- + if foundEnd then + depth = depth - 1 + if depth == 0 then + break + else + for i = 1, equalsCount + 2 do + get() + end + end + else + get() + end + end + + --get the interior string + local contentString = src:sub(contentStart, p-1) + + --found the end. Get rid of the trailing bit + for i = 0, equalsCount+1 do get() end + + --get the exterior string + local longString = src:sub(start, p-1) + + --return the stuff + return contentString, longString + else + return nil + end + else + return nil + end + end + + --main token emitting loop + while true do + --get leading whitespace. The leading whitespace will include any comments + --preceding the token. This prevents the parser needing to deal with comments + --separately. + local leading = { } + local leadingWhite = '' + local longStr = false + while true do + local c = peek() + if c == '#' and peek(1) == '!' and line == 1 then + -- #! shebang for linux scripts + get() + get() + leadingWhite = "#!" + while peek() ~= '\n' and peek() ~= '' do + leadingWhite = leadingWhite .. get() + end + local token = { + Type = 'Comment', + CommentType = 'Shebang', + Data = leadingWhite, + Line = line, + Char = char + } + token.Print = function() + return "<"..(token.Type .. string.rep(' ', 7-#token.Type)).." "..(token.Data or '').." >" + end + leadingWhite = "" + table.insert(leading, token) + end + if c == ' ' or c == '\t' then + --whitespace + --leadingWhite = leadingWhite..get() + local c2 = get() -- ignore whitespace + table.insert(leading, { Type = 'Whitespace', Line = line, Char = char, Data = c2 }) + elseif c == '\n' or c == '\r' then + local nl = get() + if leadingWhite ~= "" then + local token = { + Type = 'Comment', + CommentType = longStr and 'LongComment' or 'Comment', + Data = leadingWhite, + Line = line, + Char = char, + } + token.Print = function() + return "<"..(token.Type .. string.rep(' ', 7-#token.Type)).." "..(token.Data or '').." >" + end + table.insert(leading, token) + leadingWhite = "" + end + table.insert(leading, { Type = 'Whitespace', Line = line, Char = char, Data = nl }) + elseif c == '-' and peek(1) == '-' then + --comment + get() + get() + leadingWhite = leadingWhite .. '--' + local _, wholeText = tryGetLongString() + if wholeText then + leadingWhite = leadingWhite..wholeText + longStr = true + else + while peek() ~= '\n' and peek() ~= '' do + leadingWhite = leadingWhite..get() + end + end + else + break + end + end + if leadingWhite ~= "" then + local token = { + Type = 'Comment', + CommentType = longStr and 'LongComment' or 'Comment', + Data = leadingWhite, + Line = line, + Char = char, + } + token.Print = function() + return "<"..(token.Type .. string.rep(' ', 7-#token.Type)).." "..(token.Data or '').." >" + end + table.insert(leading, token) + end + + --get the initial char + local thisLine = line + local thisChar = char + local errorAt = ":"..line..":"..char..":> " + local c = peek() + + --symbol to emit + local toEmit = nil + + --pragma + if char == 1 and peek_n(7) == '#pragma' then + get_n(7) + local dat,opt = get_word() + local onoff = function(f, noerr) + opt = get_word() + if opt == 'on' then f(true) + elseif opt == 'off' then f(false) + elseif not noerr then generateError("invalid option for pragma " .. dat .. ", expected: [on,off]") + end + return opt + end + if dat == 'encapsulate' then + local opcode = onoff(function() end, true) + if opcode then + opcode_encapsulate[opcode] = get_word() + table.insert(Keywords_7801, opcode) + Keywords[opcode] = syntax7801_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_7801, opcode) + Keywords[opcode] = syntax7801_on + toEmit = {Type = 'Symbol', Data = ';'} + elseif dat == 'alias' then + local org,new = get_word(),get_word() + opcode_alias[new] = org + table.insert(Keywords_7801, new) + Keywords[new] = syntax7801_on + toEmit = {Type = 'Symbol', Data = ';'} + else generateError("unknown pragma: " .. dat) + end + + --branch on type + elseif c == '' then + --eof + toEmit = { Type = 'Eof' } + + elseif UpperChars[c] or LowerChars[c] or c == '_' then + --ident or keyword + local start = p + repeat + get() + c = peek() + until not (UpperChars[c] or LowerChars[c] or Digits[c] or c == '_') + local dat = src:sub(start, p-1) + if Keywords[dat] then + toEmit = {Type = 'Keyword', Data = dat} + else + toEmit = {Type = 'Ident', Data = dat} + end + + elseif Digits[c] or (peek() == '.' and Digits[peek(1)]) then + --number const + local start = p + local data_override + if c == '0' and peek(1) == 'x' then + get();get() + while HexDigits[peek()] do get() end + if consume('Pp') then + consume('+-') + while Digits[peek()] do get() end + end + elseif c == '0' and peek(1) == 'b' then + get();get() + while BinDigits[peek()] do get() end + local pstart, val_s, val = p, src:sub(start+2, p-1), 0 + for i=1,#val_s do + if val_s:sub(i,i) == '1' then val = val + (1<<(#val_s-i)) end + end + if consume('Pp') then + consume('+-') + while Digits[peek()] do get() end + end + data_override = val .. src:sub(pstart, p-1) + else + while Digits[peek()] do get() end + if consume('.') then + while Digits[peek()] do get() end + end + if consume('Ee') then + consume('+-') + while Digits[peek()] do get() end + end + end + toEmit = {Type = 'Number', Data = data_override or src:sub(start, p-1)} + + elseif c == '\'' or c == '\"' then + local start = p + --string const + local delim = get() + local contentStart = p + while true do + local c = get() + if c == '\\' then + get() --get the escape char + elseif c == delim then + break + elseif c == '' then + generateError("Unfinished string near ") + end + end + local content = src:sub(contentStart, p-2) + local constant = src:sub(start, p-1) + toEmit = {Type = 'String', Data = constant, Constant = content} + + elseif c == '[' then + local content, wholetext = tryGetLongString() + if wholetext then + toEmit = {Type = 'String', Data = wholetext, Constant = content} + else + get() + toEmit = {Type = 'Symbol', Data = '['} + end + + elseif c == '<' and peek(1) == c then + get() get() + toEmit = {Type = 'Symbol', Data = '<<'} + elseif c == '>' and peek(1) == c then + get() get() + toEmit = {Type = 'Symbol', Data = '>>'} + + elseif consume('>=<') then + toEmit = {Type = 'Symbol', Data = consume('=') and c..'=' or c} + + elseif consume('~') then + toEmit = {Type = 'Symbol', Data = consume('=') and '~=' or '~'} + + elseif consume('.') then + if consume('.') then + if consume('.') then + toEmit = {Type = 'Symbol', Data = '...'} + else + toEmit = {Type = 'Symbol', Data = '..'} + end + else + toEmit = {Type = 'Symbol', Data = '.'} + end + + elseif consume(':') then + toEmit = {Type = 'Symbol', Data = consume(':') and '::' or ':'} + elseif consume('/') then + toEmit = {Type = 'Symbol', Data = consume('/') and '//' or '/'} + + elseif syntax7801_on and consume('@') then + if consume('@') then + toEmit = {Type = 'Symbol', Data = '@@'} + else + toEmit = {Type = 'Symbol', Data = '@'} + end + + elseif syntax7801_on and consume('\\') then + toEmit = {Type = 'Symbol', Data = '\\'} + + elseif Symbols[c] then + get() + toEmit = {Type = 'Symbol', Data = c} + + else + local contents, all = tryGetLongString() + if contents then + toEmit = {Type = 'String', Data = all, Constant = contents} + else + generateError("Unexpected Symbol '"..c.."' in source.", 2) + end + end + + if toEmit[1] then + toEmit[1].LeadingWhite = leading + for k,v in ipairs(toEmit) do + v.Line = thisLine + v.Char = thisChar + v.Print = function() + return "<"..(v.Type..string.rep(' ', 7-#v.Type)).." "..(v.Data or '').." >" + end + tokens[#tokens+1] = v + end + else + --add the emitted symbol, after adding some common data + toEmit.LeadingWhite = leading -- table of leading whitespace/comments + --for k, tok in pairs(leading) do + -- tokens[#tokens + 1] = tok + --end + + toEmit.Line = thisLine + toEmit.Char = thisChar + toEmit.Print = function() + return "<"..(toEmit.Type..string.rep(' ', 7-#toEmit.Type)).." "..(toEmit.Data or '').." >" + end + tokens[#tokens+1] = toEmit + + --halt after eof has been emitted + if toEmit.Type == 'Eof' then break end + end + end + end) + if not st then + return false, err + end + + --public interface: + local tok = {} + local savedP = {} + local p = 1 + + function tok:getp() + return p + end + + function tok:setp(n) + p = n + end + + function tok:getTokenList() + return tokens + end + + --getters + function tok:Peek(n) + n = n or 0 + return tokens[math.min(#tokens, p+n)] + end + function tok:Get(tokenList) + local t = tokens[p] + p = math.min(p + 1, #tokens) + if tokenList then + table.insert(tokenList, t) + end + return t + end + function tok:Is(t) + return tok:Peek().Type == t + end + + --save / restore points in the stream + function tok:Save() + savedP[#savedP+1] = p + end + function tok:Commit() + savedP[#savedP] = nil + end + function tok:Restore() + p = savedP[#savedP] + savedP[#savedP] = nil + end + + --either return a symbol if there is one, or return true if the requested + --symbol was gotten. + function tok:ConsumeSymbol(symb, tokenList) + local t = self:Peek() + if t.Type == 'Symbol' then + if symb then + if t.Data == symb then + self:Get(tokenList) + return true + else + return nil + end + else + self:Get(tokenList) + return t + end + else + return nil + end + end + + function tok:ConsumeKeyword(kw, tokenList) + local t = self:Peek() + if t.Type == 'Keyword' and t.Data == kw then + self:Get(tokenList) + return true + else + return nil + end + end + + function tok:IsKeyword(kw) + local t = tok:Peek() + return t.Type == 'Keyword' and t.Data == kw + end + + function tok:IsSymbol(s) + local t = tok:Peek() + return t.Type == 'Symbol' and t.Data == s + end + + function tok:IsEof() + return tok:Peek().Type == 'Eof' + end + + return true, tok +end + + +local function ParseLua(src, src_name) + local st, tok + if type(src) ~= 'table' then + st, tok = LexLua(src) + else + st, tok = true, src + end + if not st then + return false, tok + end + -- + local function GenerateError(msg) + local err = (src_name or '=(string)') .. ":"..tok:Peek().Line..":"..tok:Peek().Char..": "..msg.."\n " + --find the line + local lineNum = 0 + if type(src) == 'string' then + for line in src:gmatch("[^\n]*\n?") do + if line:sub(-1,-1) == '\n' then line = line:sub(1,-2) end + lineNum = lineNum+1 + if lineNum == tok:Peek().Line then + err = err..line:gsub('\t',' ').."\n" + for i = 1, tok:Peek().Char do + local c = line:sub(i,i) + if c == '\t' then + err = err..' ' + else + err = err..' ' + end + end + err = err.."^^^^" + break + end + end + end + return err + end + -- + local VarUid = 0 + local function CreateScope(parent) + local scope = Scope:new(parent) + scope.Print = function() return "" end + return scope + end + + local ParseExpr + local ParseStatementList + local ParseSimpleExpr, + ParseSubExpr, + ParsePrimaryExpr, + ParseSuffixedExpr + + local function ParseFunctionArgsAndBody(scope, tokenList) + local funcScope = CreateScope(scope) + if not tok:ConsumeSymbol('(', tokenList) then + return false, GenerateError("'(' expected") + end + + --arg list + local argList = {} + local isVarArg = false + while not tok:ConsumeSymbol(')', tokenList) do + if tok:Is('Ident') then + local arg = funcScope:CreateLocal(tok:Get(tokenList).Data) + argList[#argList+1] = arg + if not tok:ConsumeSymbol(',', tokenList) then + if tok:ConsumeSymbol(')', tokenList) then + break + else + return false, GenerateError("')' expected") + end + end + elseif tok:ConsumeSymbol('...', tokenList) then + isVarArg = true + if not tok:ConsumeSymbol(')', tokenList) then + return false, GenerateError("'...' must be the last argument of a function") + end + break + else + return false, GenerateError("Argument name or '...' expected") + end + end + + --body + local st, body = ParseStatementList(funcScope) + if not st then return false, body end + + --end + if not tok:ConsumeKeyword('end', tokenList) then + return false, GenerateError("'end' expected after function body") + end + local nodeFunc = {} + nodeFunc.AstType = 'Function' + nodeFunc.Scope = funcScope + nodeFunc.Arguments = argList + nodeFunc.Body = body + nodeFunc.VarArg = isVarArg + nodeFunc.Tokens = tokenList + -- + return true, nodeFunc + end + + + function ParsePrimaryExpr(scope) + local tokenList = {} + + if tok:ConsumeSymbol('(', tokenList) then + local st, ex = ParseExpr(scope) + if not st then return false, ex end + if not tok:ConsumeSymbol(')', tokenList) then + return false, GenerateError("')' expected") + end + if false then + --save the information about parenthesized expressions somewhere + ex.ParenCount = (ex.ParenCount or 0) + 1 + return true, ex + else + local parensExp = {} + parensExp.AstType = 'Parentheses' + parensExp.Inner = ex + parensExp.Tokens = tokenList + return true, parensExp + end + + elseif tok:Is('Ident') then + local id = tok:Get(tokenList) + local var = scope:GetLocal(id.Data) + if not var then + var = scope:GetGlobal(id.Data) + if not var then + var = scope:CreateGlobal(id.Data) + end + end + -- + local nodePrimExp = {} + nodePrimExp.AstType = 'VarExpr' + nodePrimExp.Name = id.Data + nodePrimExp.Variable = var + nodePrimExp.Tokens = tokenList + -- + return true, nodePrimExp + + else + return false, GenerateError("Primary expression expected") + end + end + + function ParseSuffixedExpr(scope, onlyDotColon) + --base primary expression + local st, prim = ParsePrimaryExpr(scope) + if not st then return false, prim end + -- + while true do + local tokenList = {} + + if tok:IsSymbol('.') or tok:IsSymbol(':') then + local symb = tok:Get(tokenList).Data + if not tok:Is('Ident') then + return false, GenerateError("Identifier expected") + end + local id = tok:Get(tokenList) + local nodeIndex = {} + nodeIndex.AstType = 'MemberExpr' + nodeIndex.Base = prim + nodeIndex.Indexer = symb + nodeIndex.Ident = id + nodeIndex.Tokens = tokenList + -- + prim = nodeIndex + + elseif not onlyDotColon and tok:ConsumeSymbol('[', tokenList) then + local st, ex = ParseExpr(scope) + if not st then return false, ex end + if not tok:ConsumeSymbol(']', tokenList) then + return false, GenerateError("']' expected") + end + local nodeIndex = {} + nodeIndex.AstType = 'IndexExpr' + nodeIndex.Base = prim + nodeIndex.Index = ex + nodeIndex.Tokens = tokenList + -- + prim = nodeIndex + + elseif not onlyDotColon and tok:ConsumeSymbol('(', tokenList) then + local args = {} + while not tok:ConsumeSymbol(')', tokenList) do + local st, ex = ParseExpr(scope) + if not st then return false, ex end + args[#args+1] = ex + if not tok:ConsumeSymbol(',', tokenList) then + if tok:ConsumeSymbol(')', tokenList) then + break + else + return false, GenerateError("')' expected") + end + end + end + local nodeCall = {} + nodeCall.AstType = 'CallExpr' + nodeCall.Base = prim + nodeCall.Arguments = args + nodeCall.Tokens = tokenList + -- + prim = nodeCall + + elseif not onlyDotColon and tok:Is('String') then + --string call + local nodeCall = {} + nodeCall.AstType = 'StringCallExpr' + nodeCall.Base = prim + nodeCall.Arguments = { tok:Get(tokenList) } + nodeCall.Tokens = tokenList + -- + prim = nodeCall + + elseif not onlyDotColon and tok:IsSymbol('{') then + --table call + local st, ex = ParseSimpleExpr(scope) + -- FIX: ParseExpr(scope) parses the table AND and any following binary expressions. + -- We just want the table + if not st then return false, ex end + local nodeCall = {} + nodeCall.AstType = 'TableCallExpr' + nodeCall.Base = prim + nodeCall.Arguments = { ex } + nodeCall.Tokens = tokenList + -- + prim = nodeCall + + else + break + end + end + return true, prim + end + + + function ParseSimpleExpr(scope) + local tokenList = {} + + if tok:Is('Number') then + local nodeNum = {} + nodeNum.AstType = 'NumberExpr' + nodeNum.Value = tok:Get(tokenList) + nodeNum.Tokens = tokenList + return true, nodeNum + + elseif tok:Is('String') then + local nodeStr = {} + nodeStr.AstType = 'StringExpr' + nodeStr.Value = tok:Get(tokenList) + nodeStr.Tokens = tokenList + return true, nodeStr + + elseif tok:ConsumeKeyword('nil', tokenList) then + local nodeNil = {} + nodeNil.AstType = 'NilExpr' + nodeNil.Tokens = tokenList + return true, nodeNil + + elseif tok:IsKeyword('false') or tok:IsKeyword('true') then + local nodeBoolean = {} + nodeBoolean.AstType = 'BooleanExpr' + nodeBoolean.Value = (tok:Get(tokenList).Data == 'true') + nodeBoolean.Tokens = tokenList + return true, nodeBoolean + + elseif tok:ConsumeSymbol('...', tokenList) then + local nodeDots = {} + nodeDots.AstType = 'DotsExpr' + nodeDots.Tokens = tokenList + return true, nodeDots + + elseif tok:ConsumeSymbol('{', tokenList) then + local v = {} + v.AstType = 'ConstructorExpr' + v.EntryList = {} + -- + while true do + if tok:IsSymbol('[', tokenList) then + --key + tok:Get(tokenList) + local st, key = ParseExpr(scope) + if not st then + return false, GenerateError("Key expression expected") + end + if not tok:ConsumeSymbol(']', tokenList) then + return false, GenerateError("']' expected") + end + if not tok:ConsumeSymbol('=', tokenList) then + return false, GenerateError("'=' expected") + end + local st, value = ParseExpr(scope) + if not st then + return false, GenerateError("Value expression expected") + end + v.EntryList[#v.EntryList+1] = { + Type = 'Key'; + Key = key; + Value = value; + } + + elseif tok:Is('Ident') then + --value or key + local lookahead = tok:Peek(1) + if lookahead.Type == 'Symbol' and lookahead.Data == '=' then + --we are a key + local key = tok:Get(tokenList) + if not tok:ConsumeSymbol('=', tokenList) then + return false, GenerateError("'=' expected") + end + local st, value = ParseExpr(scope) + if not st then + return false, GenerateError("Value expression expected") + end + v.EntryList[#v.EntryList+1] = { + Type = 'KeyString'; + Key = key.Data; + Value = value; + } + + else + --we are a value + local st, value = ParseExpr(scope) + if not st then + return false, GenerateError("Value expected") + end + v.EntryList[#v.EntryList+1] = { + Type = 'Value'; + Value = value; + } + + end + elseif tok:ConsumeSymbol('}', tokenList) then + break + + else + --value + local st, value = ParseExpr(scope) + v.EntryList[#v.EntryList+1] = { + Type = 'Value'; + Value = value; + } + if not st then + return false, GenerateError("Value expected") + end + end + + if tok:ConsumeSymbol(';', tokenList) or tok:ConsumeSymbol(',', tokenList) then + --all is good + elseif tok:ConsumeSymbol('}', tokenList) then + break + else + return false, GenerateError("'}' or table entry expected") + end + end + v.Tokens = tokenList + return true, v + + elseif tok:ConsumeKeyword('function', tokenList) then + local st, func = ParseFunctionArgsAndBody(scope, tokenList) + if not st then return false, func end + -- + func.IsLocal = true + return true, func + + elseif tok:ConsumeSymbol('\\', tokenList) then -- short lambdas \params(expr) + local funcScope = CreateScope(scope) + + local argList = {} + if not tok:ConsumeSymbol('(', tokenList) then while true do + if not tok:Is('Ident') then return false, GenerateError("Identifier expected") end + argList[#argList+1] = funcScope:CreateLocal(tok:Get(tokenList).Data) + if tok:ConsumeSymbol('(', tokenList) then break end + if not tok:ConsumeSymbol(',', tokenList) then return false, GenerateError("'(' expected") end + end end + local st, body = ParseExpr(funcScope) + if not st then return false, body end + if not tok:ConsumeSymbol(')', tokenList) then return false, GenerateError("')' expected after lambda body") end + + local last_tok = body.Tokens[1] + local last_char,last_line = last_tok.Char,last_tok.Line + local space = { Char=last_char, Line=last_line, Data=' ', Type='Whitespace' } + local ret = { AstType='ReturnStatement', Arguments={body}, TrailingWhite=true, Tokens={ + { Char=last_char, Line=last_line, Print=function() return '' end, LeadingWhite={space}, Type='Keyword', Data='return' } + }} + local statList = { AstType='Statlist', Scope=CreateScope(funcScope), Tokens={}, Body={ret} } + + local tok_first = tokenList[1] + tok_first.Type = 'Keyword' + tok_first.Data = 'function' + tok_first.Print=function() return '' end + + local ntokl = {} + local paren_ix = 2 + math.max(0, #argList*2-1) + table.insert(ntokl, tokenList[1]) + table.insert(ntokl, tokenList[paren_ix]) + for i=2,paren_ix-1 do table.insert(ntokl, tokenList[i]) end + table.insert(ntokl, tokenList[#tokenList]) + table.insert(ntokl, { Char=last_char, Line=last_line, Type='Keyword', Data='end', Print=function() return '' end, LeadingWhite={space} }) + + local func = { AstType='Function', Scope=funcScope, Arguments=argList, Body=statList, VarArg=false, Tokens=ntokl, isLocal=true } + return true, func + + else + return ParseSuffixedExpr(scope) + end + end + + + local unops = lookupify{'-', 'not', '#', '~'} + local unopprio = 12 + local priority = { + ['^'] = {14,13}; + ['%'] = {11,11}; + ['//'] = {11,11}; + ['/'] = {11,11}; + ['*'] = {11,11}; + ['+'] = {10,10}; + ['-'] = {10,10}; + ['..'] = {9,8}; + ['>>'] = {7,7}; + ['<<'] = {7,7}; + ['&'] = {6,6}; + ['~'] = {5,5}; + ['|'] = {4,4}; + ['=='] = {3,3}; + ['<'] = {3,3}; + ['<='] = {3,3}; + ['~='] = {3,3}; + ['>'] = {3,3}; + ['>='] = {3,3}; + ['and'] = {2,2}; + ['or'] = {1,1}; + } + function ParseSubExpr(scope, level) + --base item, possibly with unop prefix + local st, exp + if unops[tok:Peek().Data] then + local tokenList = {} + local op = tok:Get(tokenList).Data + st, exp = ParseSubExpr(scope, unopprio) + if not st then return false, exp end + local nodeEx = {} + nodeEx.AstType = 'UnopExpr' + nodeEx.Rhs = exp + nodeEx.Op = op + nodeEx.OperatorPrecedence = unopprio + nodeEx.Tokens = tokenList + exp = nodeEx + else + st, exp = ParseSimpleExpr(scope) + if not st then return false, exp end + end + + --next items in chain + while true do + local prio = priority[tok:Peek().Data] + if prio and prio[1] > level then + local tokenList = {} + local op = tok:Get(tokenList).Data + local st, rhs = ParseSubExpr(scope, prio[2]) + if not st then return false, rhs end + local nodeEx = {} + nodeEx.AstType = 'BinopExpr' + nodeEx.Lhs = exp + nodeEx.Op = op + nodeEx.OperatorPrecedence = prio[1] + nodeEx.Rhs = rhs + nodeEx.Tokens = tokenList + -- + exp = nodeEx + else + break + end + end + + return true, exp + end + + + ParseExpr = function(scope) + return ParseSubExpr(scope, 0) + end + + + local pragma_map = { + encapsulate_on = function() opcode_arg_encapsulate(true) end, + encapsulate_off = function() opcode_arg_encapsulate(false) end, + syntax7801k_on = function() syntax7801k(true) end, + syntax7801k_off = function() syntax7801k(false) end, + } + local function ParseStatement(scope) + local stat = nil + local tokenList = {} + local commaTokenList = {} + local l,c = function() return tokenList[1].Line end, function() return tokenList[1].Char end + 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_7801[t.Data] end end + + local function emit_call(params) + local name,args,inverse_encapsulate = params.name, params.args or {}, params.inverse_encapsulate + if not params.func_white then params.func_white = tokenList[1].LeadingWhite end + local space = { Char=c(), Line=l(), Data=' ', Type='Whitespace' } + local op_var = { + AstType='VarExpr', Name=name, Variable={ IsGlobal=true, Name=name, Scope=CreateScope(scope) }, Tokens = { t('Ident', name, params.func_white) } + } + local encapsulate = params.encapsulate + if encapsulate == nil then encapsulate = opcode_arg_encapsulate_on end + if type(inverse_encapsulate) == 'table' then + -- this is a list of arguments, where each can be encapsulated + for arg_ix,arg in ipairs(args) do + if ( (encapsulate and not inverse_encapsulate[arg_ix]) or (not encapsulate and inverse_encapsulate[arg_ix]) ) and not no_encapsulation[arg.AstType] then + local inner_call_scope = CreateScope(op_var.Variable.Scope) + local inner_call_body = { + AstType='StatList', Scope=CreateScope(inner_call_scope), Tokens={}, Body={ + { AstType='ReturnStatement', Arguments={arg}, Tokens={ t('Keyword', 'return', {space}) } } + } + } + local 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}) } + } + if #arg.Tokens[1].LeadingWhite == 0 then table.insert(arg.Tokens[1].LeadingWhite, space) end + args[arg_ix] = inner_call + end + 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,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}) } } + } + } + 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}) } + } + 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 = { + AstType = 'CallExpr', Base = op_var, Arguments = args, Tokens = { + t('Symbol', '(', params.paren_open_white), t('Symbol', ')', params.paren_close_white) + } + } + do + local j=#commaTokenList + for i=2,#args do + assert(j > 0) + table.insert(exp_call.Tokens, i, commaTokenList[j]) + j = j - 1 + end + end + return { AstType = 'CallStatement', Expression = exp_call, Tokens = {} } + end + + local function as_string_expr(expr, s) + local ss = '"'..s..'"' + local lw = expr.Tokens and #expr.Tokens > 0 and expr.Tokens[1].LeadingWhite or {} + local p = function() return '' end + local v = { LeadingWhite=lw, Type='String', Data=ss, Constant=s, Char=c(), Line=l(), Print=p } + return { AstType = 'StringExpr', Value = v, Tokens = {v} } + end + + -- parser pragmas + 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 + if not stat then + if tok:ConsumeSymbol('@@', tokenList) then + if not tok:Is('Ident') then return false, GenerateError("Identifier expected") end + local label_name = tok:Get(tokenList) + label_name = as_string_expr(label_name, label_name.Data) + stat = emit_call{name = 'section', args = {label_name}, encapsulate=false} + elseif tok:ConsumeSymbol('@', tokenList) then + if not tok:Is('Ident') then return false, GenerateError("Identifier expected") end + local label_name = tok:Get(tokenList) + label_name = as_string_expr(label_name, label_name.Data) + stat = emit_call{name = 'label', args = {label_name}, encapsulate=false} + end end + + -- new statements + if not stat then + local pagestat = function(fpage) + local st, nodeBlock = ParseStatementList(scope) + if not st then return false, nodeBlock end + if not tok:ConsumeKeyword('end', tokenList) then + return false, GenerateError("'end' expected") + end + + local nodeDoStat = {} + nodeDoStat.AstType = 'DoStatement' + nodeDoStat.Body = nodeBlock + nodeDoStat.Tokens = tokenList + stat = nodeDoStat + + tokenList[1].Data = 'do' + + local space = {{ Char=c(), Line=l(), Data=' ', Type='Whitespace' }} + local opencall,closecall = emit_call{name=fpage,func_white=space},emit_call{name='endpage',func_white=space} + table.insert(nodeBlock.Body, 1, opencall) + table.insert(nodeBlock.Body, closecall) + end + if tok:ConsumeKeyword('samepage', tokenList) then pagestat('samepage') + elseif tok:ConsumeKeyword('crosspage', tokenList) then pagestat('crosspage') + end + end + + -- declare data + if not stat then + if tok:ConsumeKeyword('dc', tokenList) then + 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 return false, GenerateError("'b', 'w' or 'l' expected") end + local inverse_encapsulate={} + inverse_encapsulate[1] = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) + if not st then return false, expr end + if inverse_encapsulate[1] then + local d = expr.Tokens[1].LeadingWhite + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(d, v) end + end + local exprs = { expr } + while tok:ConsumeSymbol(',', tokenList) do + commaTokenList[#commaTokenList+1] = tokenList[#tokenList] + inverse_encapsulate[#exprs+1] = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) + if not st then return false, expr end + if inverse_encapsulate[#exprs+1] then + local d = expr.Tokens[1].LeadingWhite + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(d, v) end + end + exprs[#exprs+1] = expr + end + stat = emit_call{name=func, args=exprs, inverse_encapsulate=inverse_encapsulate} + end end + + -- 7801 opcodes + if not stat then + local mod_st, mod_expr, inverse_encapsulate + for _,op in pairs(Keywords_7801) do + if tok:ConsumeKeyword(op, tokenList) then + if 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) + end + stat = emit_call{name=op, args={expr}, encapsulate=false} break + end + if opcode_immediate[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 + if tok:ConsumeSymbol(',', tokenList) then + commaTokenList[1] = tokenList[#tokenList] + mod_st, mod_expr = ParseExpr(scope) + if not mod_st then return false, mod_expr end + end + stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + end + if opcode_implied[op] then stat = emit_call{name=op} break end + error("internal error: unable to find addressing of valid opcode " .. op) -- should not happen + end + end end + + if stat then -- nothing + elseif tok:ConsumeKeyword('if', tokenList) then + --setup + local nodeIfStat = {} + nodeIfStat.AstType = 'IfStatement' + nodeIfStat.Clauses = {} + + --clauses + repeat + local st, nodeCond = ParseExpr(scope) + if not st then return false, nodeCond end + if not tok:ConsumeKeyword('then', tokenList) then + return false, GenerateError("'then' expected") + end + local st, nodeBody = ParseStatementList(scope) + if not st then return false, nodeBody end + nodeIfStat.Clauses[#nodeIfStat.Clauses+1] = { + Condition = nodeCond; + Body = nodeBody; + } + until not tok:ConsumeKeyword('elseif', tokenList) + + --else clause + if tok:ConsumeKeyword('else', tokenList) then + local st, nodeBody = ParseStatementList(scope) + if not st then return false, nodeBody end + nodeIfStat.Clauses[#nodeIfStat.Clauses+1] = { + Body = nodeBody; + } + end + + --end + if not tok:ConsumeKeyword('end', tokenList) then + return false, GenerateError("'end' expected") + end + + nodeIfStat.Tokens = tokenList + stat = nodeIfStat + + elseif tok:ConsumeKeyword('while', tokenList) then + --setup + local nodeWhileStat = {} + nodeWhileStat.AstType = 'WhileStatement' + + --condition + local st, nodeCond = ParseExpr(scope) + if not st then return false, nodeCond end + + --do + if not tok:ConsumeKeyword('do', tokenList) then + return false, GenerateError("'do' expected") + end + + --body + local st, nodeBody = ParseStatementList(scope) + if not st then return false, nodeBody end + + --end + if not tok:ConsumeKeyword('end', tokenList) then + return false, GenerateError("'end' expected") + end + + --return + nodeWhileStat.Condition = nodeCond + nodeWhileStat.Body = nodeBody + nodeWhileStat.Tokens = tokenList + stat = nodeWhileStat + + elseif tok:ConsumeKeyword('do', tokenList) then + --do block + local st, nodeBlock = ParseStatementList(scope) + if not st then return false, nodeBlock end + if not tok:ConsumeKeyword('end', tokenList) then + return false, GenerateError("'end' expected") + end + + local nodeDoStat = {} + nodeDoStat.AstType = 'DoStatement' + nodeDoStat.Body = nodeBlock + nodeDoStat.Tokens = tokenList + stat = nodeDoStat + + elseif tok:ConsumeKeyword('for', tokenList) then + --for block + if not tok:Is('Ident') then + return false, GenerateError("Identifier expected") + end + local baseVarName = tok:Get(tokenList) + if tok:ConsumeSymbol('=', tokenList) then + --numeric for + local forScope = CreateScope(scope) + local forVar = forScope:CreateLocal(baseVarName.Data) + -- + local st, startEx = ParseExpr(scope) + if not st then return false, startEx end + if not tok:ConsumeSymbol(',', tokenList) then + return false, GenerateError("',' expected") + end + local st, endEx = ParseExpr(scope) + if not st then return false, endEx end + local st, stepEx; + if tok:ConsumeSymbol(',', tokenList) then + st, stepEx = ParseExpr(scope) + if not st then return false, stepEx end + end + if not tok:ConsumeKeyword('do', tokenList) then + return false, GenerateError("'do' expected") + end + -- + local st, body = ParseStatementList(forScope) + if not st then return false, body end + if not tok:ConsumeKeyword('end', tokenList) then + return false, GenerateError("'end' expected") + end + -- + local nodeFor = {} + nodeFor.AstType = 'NumericForStatement' + nodeFor.Scope = forScope + nodeFor.Variable = forVar + nodeFor.Start = startEx + nodeFor.End = endEx + nodeFor.Step = stepEx + nodeFor.Body = body + nodeFor.Tokens = tokenList + stat = nodeFor + else + --generic for + local forScope = CreateScope(scope) + -- + local varList = { forScope:CreateLocal(baseVarName.Data) } + while tok:ConsumeSymbol(',', tokenList) do + if not tok:Is('Ident') then + return false, GenerateError("for variable expected.") + end + varList[#varList+1] = forScope:CreateLocal(tok:Get(tokenList).Data) + end + if not tok:ConsumeKeyword('in', tokenList) then + return false, GenerateError("'in' expected") + end + local generators = {} + local st, firstGenerator = ParseExpr(scope) + if not st then return false, firstGenerator end + generators[#generators+1] = firstGenerator + while tok:ConsumeSymbol(',', tokenList) do + local st, gen = ParseExpr(scope) + if not st then return false, gen end + generators[#generators+1] = gen + end + if not tok:ConsumeKeyword('do', tokenList) then + return false, GenerateError("'do' expected") + end + local st, body = ParseStatementList(forScope) + if not st then return false, body end + if not tok:ConsumeKeyword('end', tokenList) then + return false, GenerateError("'end' expected") + end + -- + local nodeFor = {} + nodeFor.AstType = 'GenericForStatement' + nodeFor.Scope = forScope + nodeFor.VariableList = varList + nodeFor.Generators = generators + nodeFor.Body = body + nodeFor.Tokens = tokenList + stat = nodeFor + end + + elseif tok:ConsumeKeyword('repeat', tokenList) then + local st, body = ParseStatementList(scope) + if not st then return false, body end + -- + if not tok:ConsumeKeyword('until', tokenList) then + return false, GenerateError("'until' expected") + end + -- FIX: Used to parse in parent scope + -- Now parses in repeat scope + local st, cond = ParseExpr(body.Scope) + if not st then return false, cond end + -- + local nodeRepeat = {} + nodeRepeat.AstType = 'RepeatStatement' + nodeRepeat.Condition = cond + nodeRepeat.Body = body + nodeRepeat.Tokens = tokenList + stat = nodeRepeat + + elseif tok:ConsumeKeyword('function', tokenList) then + if not tok:Is('Ident') then + return false, GenerateError("function name expected") + end + local st, name = ParseSuffixedExpr(scope, true) --true => only dots and colons + if not st then return false, name end + -- + local st, func = ParseFunctionArgsAndBody(scope, tokenList) + if not st then return false, func end + -- + func.IsLocal = false + func.Name = name + stat = func + + elseif tok:ConsumeKeyword('local', tokenList) then + if tok:Is('Ident') then + local varList = { tok:Get(tokenList).Data } + while tok:ConsumeSymbol(',', tokenList) do + if not tok:Is('Ident') then + return false, GenerateError("local var name expected") + end + varList[#varList+1] = tok:Get(tokenList).Data + end + + local initList = {} + if tok:ConsumeSymbol('=', tokenList) then + repeat + local st, ex = ParseExpr(scope) + if not st then return false, ex end + initList[#initList+1] = ex + until not tok:ConsumeSymbol(',', tokenList) + end + + --now patch var list + --we can't do this before getting the init list, because the init list does not + --have the locals themselves in scope. + for i, v in pairs(varList) do + varList[i] = scope:CreateLocal(v) + end + + local nodeLocal = {} + nodeLocal.AstType = 'LocalStatement' + nodeLocal.LocalList = varList + nodeLocal.InitList = initList + nodeLocal.Tokens = tokenList + -- + stat = nodeLocal + + elseif tok:ConsumeKeyword('function', tokenList) then + if not tok:Is('Ident') then + return false, GenerateError("function name expected") + end + local name = tok:Get(tokenList).Data + local localVar = scope:CreateLocal(name) + -- + local st, func = ParseFunctionArgsAndBody(scope, tokenList) + if not st then return false, func end + -- + func.Name = localVar + func.IsLocal = true + stat = func + + else + return false, GenerateError("local var or function def expected") + end + + elseif tok:ConsumeSymbol('::', tokenList) then + if not tok:Is('Ident') then + return false, GenerateError('Label name expected') + end + local label = tok:Get(tokenList).Data + if not tok:ConsumeSymbol('::', tokenList) then + return false, GenerateError("'::' expected") + end + local nodeLabel = {} + nodeLabel.AstType = 'LabelStatement' + nodeLabel.Label = label + nodeLabel.Tokens = tokenList + stat = nodeLabel + + elseif tok:ConsumeKeyword('return', tokenList) then + local exList = {} + if not tok:IsKeyword('end') then + local st, firstEx = ParseExpr(scope) + if st then + exList[1] = firstEx + while tok:ConsumeSymbol(',', tokenList) do + local st, ex = ParseExpr(scope) + if not st then return false, ex end + exList[#exList+1] = ex + end + end + end + + local nodeReturn = {} + nodeReturn.AstType = 'ReturnStatement' + nodeReturn.Arguments = exList + nodeReturn.Tokens = tokenList + stat = nodeReturn + + elseif tok:ConsumeKeyword('break', tokenList) then + local nodeBreak = {} + nodeBreak.AstType = 'BreakStatement' + nodeBreak.Tokens = tokenList + stat = nodeBreak + + elseif tok:ConsumeKeyword('goto', tokenList) then + if not tok:Is('Ident') then + return false, GenerateError("Label expected") + end + local label = tok:Get(tokenList).Data + local nodeGoto = {} + nodeGoto.AstType = 'GotoStatement' + nodeGoto.Label = label + nodeGoto.Tokens = tokenList + stat = nodeGoto + + elseif tok:IsSymbol(';') then + stat = { AstType='SemicolonStatement', Tokens={} } + + else + + --statementParseExpr + local st, suffixed = ParseSuffixedExpr(scope) + if not st then return false, suffixed end + + --assignment or call? + if tok:IsSymbol(',') or tok:IsSymbol('=') then + --check that it was not parenthesized, making it not an lvalue + if (suffixed.ParenCount or 0) > 0 then + return false, GenerateError("Can not assign to parenthesized expression, is not an lvalue") + end + + --more processing needed + local lhs = { suffixed } + while tok:ConsumeSymbol(',', tokenList) do + local st, lhsPart = ParseSuffixedExpr(scope) + if not st then return false, lhsPart end + lhs[#lhs+1] = lhsPart + end + + --equals + if not tok:ConsumeSymbol('=', tokenList) then + return false, GenerateError("'=' expected") + end + + --rhs + local rhs = {} + local st, firstRhs = ParseExpr(scope) + if not st then return false, firstRhs end + rhs[1] = firstRhs + while tok:ConsumeSymbol(',', tokenList) do + local st, rhsPart = ParseExpr(scope) + if not st then return false, rhsPart end + rhs[#rhs+1] = rhsPart + end + + --done + local nodeAssign = {} + nodeAssign.AstType = 'AssignmentStatement' + nodeAssign.Lhs = lhs + nodeAssign.Rhs = rhs + nodeAssign.Tokens = tokenList + stat = nodeAssign + + elseif suffixed.AstType == 'CallExpr' or + suffixed.AstType == 'TableCallExpr' or + suffixed.AstType == 'StringCallExpr' + then + --it's a call statement + local nodeCall = {} + nodeCall.AstType = 'CallStatement' + nodeCall.Expression = suffixed + nodeCall.Tokens = tokenList + stat = nodeCall + else + return false, GenerateError("Assignment statement expected") + end + end + + if tok:IsSymbol(';') then + stat.Semicolon = tok:Get( stat.Tokens ) + end + return true, stat + end + + + local statListCloseKeywords = lookupify{'end', 'else', 'elseif', 'until'} + + ParseStatementList = function(scope) + local nodeStatlist = {} + nodeStatlist.Scope = CreateScope(scope) + nodeStatlist.AstType = 'Statlist' + nodeStatlist.Body = { } + nodeStatlist.Tokens = { } + -- + --local stats = {} + -- + while not statListCloseKeywords[tok:Peek().Data] and not tok:IsEof() do + local st, nodeStatement = ParseStatement(nodeStatlist.Scope) + if not st then return false, nodeStatement end + --stats[#stats+1] = nodeStatement + nodeStatlist.Body[#nodeStatlist.Body + 1] = nodeStatement + end + + if tok:IsEof() then + local nodeEof = {} + nodeEof.AstType = 'Eof' + nodeEof.Tokens = { tok:Get() } + nodeStatlist.Body[#nodeStatlist.Body + 1] = nodeEof + end + + -- + --nodeStatlist.Body = stats + return true, nodeStatlist + end + + + local function mainfunc() + local topScope = CreateScope() + return ParseStatementList(topScope) + end + + local st, main = mainfunc() + return st, main +end + + +local function Format65(ast) + local function splitLines(str) + if str:match("\n") then + local lines = {} + for line in str:gmatch("[^\n]*") do + table.insert(lines, line) + end + assert(#lines > 0) + return lines + else + return { str } + end + end + + local formatStatlist, formatExpr + local out = { + rope = {}, -- List of strings + line = 1, + char = 1, + + appendStr = function(self, str) + table.insert(self.rope, str) + + local lines = splitLines(str) + if #lines == 1 then + self.char = self.char + #str + else + self.line = self.line + #lines - 1 + local lastLine = lines[#lines] + self.char = #lastLine + end + end, + + appendToken = function(self, token) + self:appendWhite(token) + self:appendStr(token.Data) + end, + + appendTokens = function(self, tokens) + for _,token in ipairs(tokens) do + self:appendToken( token ) + end + end, + + appendWhite = function(self, token) + if token.LeadingWhite then + self:appendTokens( token.LeadingWhite ) + end + end + } + formatExpr = function(expr) + local tok_it = 1 + local function appendNextToken(str) + local tok = expr.Tokens[tok_it]; + if str and tok.Data ~= str then + error("Expected token '" .. str .. "'.") + end + out:appendToken( tok ) + tok_it = tok_it + 1 + end + local function appendToken(token) + out:appendToken( token ) + tok_it = tok_it + 1 + end + local function appendWhite() + local tok = expr.Tokens[tok_it]; + if not tok then error("Missing token") end + out:appendWhite( tok ) + tok_it = tok_it + 1 + end + local function appendStr(str) + appendWhite() + out:appendStr(str) + end + local function peek() + if tok_it < #expr.Tokens then + return expr.Tokens[tok_it].Data + end + end + local function appendComma(mandatory, seperators) + seperators = seperators or { "," } + seperators = lookupify( seperators ) + if not mandatory and not seperators[peek()] then + return + end + assert(seperators[peek()], "Missing comma or semicolon") + appendNextToken() + end + + if expr.AstType == 'VarExpr' then + if expr.Variable then + appendStr( expr.Variable.Name ) + else + appendStr( expr.Name ) + end + + elseif expr.AstType == 'NumberExpr' then + appendToken( expr.Value ) + + elseif expr.AstType == 'StringExpr' then + appendToken( expr.Value ) + + elseif expr.AstType == 'BooleanExpr' then + appendNextToken( expr.Value and "true" or "false" ) + + elseif expr.AstType == 'NilExpr' then + appendNextToken( "nil" ) + + elseif expr.AstType == 'BinopExpr' then + formatExpr(expr.Lhs) + appendStr( expr.Op ) + formatExpr(expr.Rhs) + + elseif expr.AstType == 'UnopExpr' then + appendStr( expr.Op ) + formatExpr(expr.Rhs) + + elseif expr.AstType == 'DotsExpr' then + appendNextToken( "..." ) + + elseif expr.AstType == 'CallExpr' then + formatExpr(expr.Base) + appendNextToken( "(" ) + for i,arg in ipairs( expr.Arguments ) do + formatExpr(arg) + appendComma( i ~= #expr.Arguments ) + end + appendNextToken( ")" ) + + elseif expr.AstType == 'TableCallExpr' then + formatExpr( expr.Base ) + formatExpr( expr.Arguments[1] ) + + elseif expr.AstType == 'StringCallExpr' then + formatExpr(expr.Base) + appendToken( expr.Arguments[1] ) + + elseif expr.AstType == 'IndexExpr' then + formatExpr(expr.Base) + appendNextToken( "[" ) + formatExpr(expr.Index) + appendNextToken( "]" ) + + elseif expr.AstType == 'MemberExpr' then + formatExpr(expr.Base) + appendNextToken() -- . or : + appendToken(expr.Ident) + + elseif expr.AstType == 'Function' then + -- anonymous function + appendNextToken( "function" ) + appendNextToken( "(" ) + if #expr.Arguments > 0 then + for i = 1, #expr.Arguments do + appendStr( expr.Arguments[i].Name ) + if i ~= #expr.Arguments then + appendNextToken(",") + elseif expr.VarArg then + appendNextToken(",") + appendNextToken("...") + end + end + elseif expr.VarArg then + appendNextToken("...") + end + appendNextToken(")") + formatStatlist(expr.Body) + appendNextToken("end") + + elseif expr.AstType == 'ConstructorExpr' then + appendNextToken( "{" ) + for i = 1, #expr.EntryList do + local entry = expr.EntryList[i] + if entry.Type == 'Key' then + appendNextToken( "[" ) + formatExpr(entry.Key) + appendNextToken( "]" ) + appendNextToken( "=" ) + formatExpr(entry.Value) + elseif entry.Type == 'Value' then + formatExpr(entry.Value) + elseif entry.Type == 'KeyString' then + appendStr(entry.Key) + appendNextToken( "=" ) + formatExpr(entry.Value) + end + appendComma( i ~= #expr.EntryList, { ",", ";" } ) + end + appendNextToken( "}" ) + + elseif expr.AstType == 'Parentheses' then + appendNextToken( "(" ) + formatExpr(expr.Inner) + appendNextToken( ")" ) + + else + error(string.format("Unknown AST Type: %s\n", tostring(statement.AstType))) + end + + assert(tok_it == #expr.Tokens + 1) + end + + + local formatStatement = function(statement) + local tok_it = 1 + local function appendNextToken(str) + local tok = statement.Tokens[tok_it]; + assert(tok, string.format("Not enough tokens for %q. First token at %i:%i", + str, statement.Tokens[1].Line, statement.Tokens[1].Char)) + assert(tok.Data == str, + string.format('Expected token %q, got %q', str, tok.Data)) + out:appendToken( tok ) + tok_it = tok_it + 1 + end + local function appendToken(token) + out:appendToken( str ) + tok_it = tok_it + 1 + end + local function appendWhite() + local tok = statement.Tokens[tok_it]; + out:appendWhite( tok ) + tok_it = tok_it + 1 + end + local function appendStr(str) + appendWhite() + out:appendStr(str) + end + local function appendComma(mandatory) + if mandatory + or (tok_it < #statement.Tokens and statement.Tokens[tok_it].Data == ",") then + appendNextToken( "," ) + end + end + + if statement.AstType == 'AssignmentStatement' then + for i,v in ipairs(statement.Lhs) do + formatExpr(v) + appendComma( i ~= #statement.Lhs ) + end + if #statement.Rhs > 0 then + appendNextToken( "=" ) + for i,v in ipairs(statement.Rhs) do + formatExpr(v) + appendComma( i ~= #statement.Rhs ) + end + end + + elseif statement.AstType == 'CallStatement' then + formatExpr(statement.Expression) + + elseif statement.AstType == 'LocalStatement' then + appendNextToken( "local" ) + for i = 1, #statement.LocalList do + appendStr( statement.LocalList[i].Name ) + appendComma( i ~= #statement.LocalList ) + end + if #statement.InitList > 0 then + appendNextToken( "=" ) + for i = 1, #statement.InitList do + formatExpr(statement.InitList[i]) + appendComma( i ~= #statement.InitList ) + end + end + + elseif statement.AstType == 'IfStatement' then + appendNextToken( "if" ) + formatExpr( statement.Clauses[1].Condition ) + appendNextToken( "then" ) + formatStatlist( statement.Clauses[1].Body ) + for i = 2, #statement.Clauses do + local st = statement.Clauses[i] + if st.Condition then + appendNextToken( "elseif" ) + formatExpr(st.Condition) + appendNextToken( "then" ) + else + appendNextToken( "else" ) + end + formatStatlist(st.Body) + end + appendNextToken( "end" ) + + elseif statement.AstType == 'WhileStatement' then + appendNextToken( "while" ) + formatExpr(statement.Condition) + appendNextToken( "do" ) + formatStatlist(statement.Body) + appendNextToken( "end" ) + + elseif statement.AstType == 'DoStatement' then + appendNextToken( "do" ) + formatStatlist(statement.Body) + appendNextToken( "end" ) + + elseif statement.AstType == 'ReturnStatement' then + appendNextToken( "return" ) + if statement.TrailingWhite then out:appendStr(' ') end + for i = 1, #statement.Arguments do + formatExpr(statement.Arguments[i]) + appendComma( i ~= #statement.Arguments ) + end + + elseif statement.AstType == 'BreakStatement' then + appendNextToken( "break" ) + + elseif statement.AstType == 'RepeatStatement' then + appendNextToken( "repeat" ) + formatStatlist(statement.Body) + appendNextToken( "until" ) + formatExpr(statement.Condition) + + elseif statement.AstType == 'Function' then + if statement.IsLocal then + appendNextToken( "local" ) + end + appendNextToken( "function" ) + + if statement.IsLocal then + appendStr(statement.Name.Name) + else + formatExpr(statement.Name) + end + + appendNextToken( "(" ) + if #statement.Arguments > 0 then + for i = 1, #statement.Arguments do + appendStr( statement.Arguments[i].Name ) + appendComma( i ~= #statement.Arguments or statement.VarArg ) + if i == #statement.Arguments and statement.VarArg then + appendNextToken( "..." ) + end + end + elseif statement.VarArg then + appendNextToken( "..." ) + end + appendNextToken( ")" ) + + formatStatlist(statement.Body) + appendNextToken( "end" ) + + elseif statement.AstType == 'GenericForStatement' then + appendNextToken( "for" ) + for i = 1, #statement.VariableList do + appendStr( statement.VariableList[i].Name ) + appendComma( i ~= #statement.VariableList ) + end + appendNextToken( "in" ) + for i = 1, #statement.Generators do + formatExpr(statement.Generators[i]) + appendComma( i ~= #statement.Generators ) + end + appendNextToken( "do" ) + formatStatlist(statement.Body) + appendNextToken( "end" ) + + elseif statement.AstType == 'NumericForStatement' then + appendNextToken( "for" ) + appendStr( statement.Variable.Name ) + appendNextToken( "=" ) + formatExpr(statement.Start) + appendNextToken( "," ) + formatExpr(statement.End) + if statement.Step then + appendNextToken( "," ) + formatExpr(statement.Step) + end + appendNextToken( "do" ) + formatStatlist(statement.Body) + appendNextToken( "end" ) + + elseif statement.AstType == 'LabelStatement' then + appendNextToken( "::" ) + appendStr( statement.Label ) + appendNextToken( "::" ) + + elseif statement.AstType == 'GotoStatement' then + appendNextToken( "goto" ) + appendStr( statement.Label ) + + elseif statement.AstType == 'Eof' then + appendWhite() + + elseif statement.AstType == 'SemicolonStatement' then + + else + error(string.format("Unknown AST Type: %s\n", tostring(statement.AstType))) + end + + if statement.Semicolon then + appendNextToken(";") + end + + assert(tok_it == #statement.Tokens + 1) + end + + formatStatlist = function(statList) + for _, stat in ipairs(statList.Body) do + formatStatement(stat) + end + end + + formatStatlist(ast) + + return table.concat(out.rope) +end + +local dirsep = package.config:sub(1,1) +local dirl65 = (string.match(arg[0], "(.*[\\/]).*") or ''):gsub('/',dirsep) +local searchl65 = '' +if #dirl65 > 0 then + searchl65 = string.format(";%s?;%s?.l65", dirl65, dirl65) + package.path = package.path .. string.format(";%s?.lua", dirl65) +end +l65_def = { + parse = ParseLua, + format = Format65, + searcher_index = 2, + search_path = string.format(".%s?;.%s?.l65%s", dirsep, dirsep, searchl65), + load_org = load, + loadfile_org = loadfile, + dofile_org = dofile, +} +if not l65 then l65 = l65_def else for k,v in pairs(l65_def) do l65[k]=v end end +l65.report = function(success, ...) + if success then return success,... end + local message=... io.stderr:write(tostring(message)..'\n') + 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) + trace_cur = trace_cur:gsub('%[string "(.-%.l65)"%]', '%1') -- [string "xxx.l65"] -> xxx.l65 + trace_cur = trace_cur:gsub('stack traceback:', '') + + local i=2 + while debug.getinfo(i) do + local j = 1 + while true do + local n,v = debug.getlocal(i, j) + if not n then break end + if n == 'l65dbg' then + o(string.format("%s\n", msg)) + if trace_cur:find("in local 'late'") then + local lines = {} + for line in trace_cur:gmatch("[^\n]+") do + if line:find("in local 'late'") then break end + table.insert(lines, line) + end + 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:', '') + o(trace .. '\n') + os.exit(-2) + end + j = j + 1 + end + i = i + 1 + end + + trace_cur = trace_cur:match(".-\n(.*)\n.-'xpcall'") + o(string.format("%s\n%s\n", msg, trace_cur)) + os.exit(-3) +end +do + local getembedded = type(arg[-1]) == 'function' and arg[-1] + l65.load_embedded = function(name) + if not getembedded then return end + local src,isl65 = getembedded(name) + if not src then return end + if isl65 then + name = name .. '.l65' + local st, ast = l65.report(l65.parse(src, name)) + src = l65.format(ast) + else + name = name .. '.lua' + end + local bc = assert(l65.load_org(src, name)) + return bc, name + end +end +l65.searcher = function(name) + local filename,err = package.searchpath(name, l65.search_path, '.', '.') + if not filename then return err end + local file = assert(io.open(filename, 'rb')) + local src = file:read('*a') + file:close() + local st, ast = l65.report(l65.parse(src, filename)) + local bc = assert(l65.load_org(l65.format(ast), filename)) + return bc, filename +end +l65.load = function(chunk, chunkname, mode, ...) + local chunk_t,s = type(chunk) + if chunk_t == 'string' then s = chunk + elseif chunk_t == 'function' then + s={} for x in chunk do if #x==0 then break end s[#s+1]=x end + s = table.concat(s) + else return nil, string.format("invalid type for chunk %s: %s", chunkname or "=(load)", chunk_t) + end + if s:sub(1,4) == "\x1bLua" then -- a binary file + return l65.load_org(s, chunkname, mode, ...) + end + local st, ast = l65.report(l65.parse(s, chunkname or "=(load)")) + return l65.load_org(l65.format(ast), chunkname, 't', ...) +end +l65.loadfile = function(filename, mode, ...) + local s + if not filename then s = io.read('*a') + else + local file = io.open(filename, 'rb') + if not file then return nil,"failed to open " .. filename .. " for reading" end + s = file:read('*a') + file:close() + end + return l65.load(s, filename, mode, ...) +end +l65.dofile = function(filename) + local f = l65.report(l65.loadfile(filename)) + return f() +end +l65.installhooks = function() + if package.searchers[l65.searcher_index] ~= l65.searcher then + table.insert(package.searchers, l65.searcher_index, l65.searcher) + end + if not l65.hooks_installed then l65.hooks_installed = true + load = l65.load + loadfile = l65.loadfile + dofile = l65.dofile + end +end +l65.uninstallhooks = function() + for k,v in ipairs(package.searchers) do + if v == l65.searcher then table.remove(package.searchers, k) break end + end + if l65.hooks_installed then l65.hooks_installed = nil + load = l65.load_org + loadfile = l65.loadfile_org + dofile = l65.dofile_org + end +end +table.insert(package.searchers, l65.searcher_index, l65.load_embedded) +l65.installhooks() + +function getopt(optstring, ...) + local opts = { } + local args = { ... } + for optc, optv in optstring:gmatch"(%a)(:?)" do + opts[optc] = { hasarg = optv == ":" } + end + return coroutine.wrap(function() + local yield = coroutine.yield + local i = 1 + while i <= #args do + local arg,argi = args[i], i + i = i + 1 + if arg == "--" then + break + elseif arg:sub(1, 1) == "-" then + for j = 2, #arg do + local opt = arg:sub(j, j) + if opts[opt] then + if opts[opt].hasarg then + if j == #arg then + if args[i] then yield(opt, args[i], argi) i=i+1 + elseif optstring:sub(1, 1) == ":" then yield(':', opt, argi) + else yield('?', opt, argi) end + else yield(opt, arg:sub(j + 1), argi) end + break + else yield(opt, false, argi) end + else yield('?', opt, argi) end + end + else yield(false, arg, argi) end + end + for i = i, #args do yield(false, args[i], i) end + end) +end + +local cfg=require"l65cfg" l65.cfg=cfg +local version = function() + print(string.format("l65 %s", cfg.version)) +end +local usage = function(f) + if not f then f = io.stdout end + f:write(string.format([[ +Usage: %s [options] file [args] +Options: + -d Dump the Lua code after l65 parsing into file + -h Display this information + -v Display the release version +]], arg[0])) +end +local invalid_usage = function() + io.stderr:write("Invalid usage.\n") + usage(io.stderr) +end + +local inf,dump,optix +for opt,arg,i in getopt("d:hv", ...) do + if opt == '?' then return invalid_usage() end + if opt == 'h' then return usage() end + if opt == 'v' then return version() end + if opt == 'd' then dump = arg end + if opt == false then inf=arg optix=i+1 break end +end +if not inf then return invalid_usage() end +if dump then l65.format = function(ast) + local s=Format65(ast) l65.format = Format65 + local f = assert(io.open(dump, 'wb')) f:write(s) f:close() + return s +end end + +local fn='' for i=#inf,1,-1 do local c=inf:sub(i,i) if c==dirsep or c=='/' then break end fn=c..fn if c=='.' then fn='' end end filename=fn +local f = l65.report(l65.loadfile(inf)) +return xpcall(f, l65.msghandler, select(optix, ...)) diff --git a/uPD7801.lua b/uPD7801.lua index d66884d..e0142d0 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -1,9 +1,9 @@ M = require "asm" -local op_eval_byte = function(late, early) return byte_normalize(op_eval(late, early)) end +local op_eval_byte = function(late, early) return M.byte_normalize(M.op_eval(late, early)) end M.op_eval_byte = op_eval_byte -local op_eval_word = function(late, early) return word_normalize(op_eval(late, early)) end +local op_eval_word = function(late, early) return M.word_normalize(M.op_eval(late, early)) end M.op_eval_word = op_eval_word local opimp={ @@ -61,9 +61,9 @@ end local opd={ ldaxm=M.op(0x2e,7), - ldaxp=M.op(0x2c 7), + ldaxp=M.op(0x2c,7), staxm=M.op(0x3e,7), - staxp=M.op(0x3c,7), + staxp=M.op(0x3c,7) } M.opd = opd for k,v in pairs(opd) do M[k .. 'd'] = function() @@ -83,7 +83,7 @@ for k,v in pairs(oph) do end end -local opind={ +local oprwind={ dcxbc=M.op(0x13,7), dcxde=M.op(0x23,7), dcxhl=M.op(0x33,7), @@ -260,18 +260,33 @@ for k,v in pairs(opwwww) do end end -for i=0x80,0xbf,1 do - M['calt' .. i]=M.op(i,cycles) - table.insert(M.section_current.instructions, { size=1, cycles=19, bin=i}) +M.calt = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local op = { cycles=19 } + op.size = function() late,early = M.size_op(late,early) return 1 end + op.bin = function() + local l65dbg=l65dbg + local x = M.op_eval_byte(late,early) + if (x%2 == 1) then error("offset should be even : " .. x) end + if x < 0x80 or x > 0xfe then error("offset out of range : " .. x) end + x = (x>>1) + 0x40 + return x + end + table.insert(M.section_current.instructions, op) end - M.jr = function(label) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local parent,offset = M.label_current local section,rorg = M.section_current,M.location_current.rorg - local op = { cycles=13, size=1 } - op.bin = function() local l65dbg=l65dbg + local op = { cycles=13 } + op.size = function() + offset = section.size + label = M.size_dc(label) + return 1 + end + op.bin = function() + local l65dbg=l65dbg local x,l = label,label if type(x) == 'function' then x=x() end if type(x) == 'string' then @@ -279,12 +294,13 @@ M.jr = function(label) x = symbols[x] end if type(x) ~= 'number' then error("unresolved branch target: " .. tostring(x)) end - x = x - offset - rorg(section.org) - if x < -32 or x > 0x32 then error("branch target out of range for " .. l .. ": " .. x) end + x = x-1 - offset - rorg(section.org) + if x < -32 or x > 0x32 then error("branch target out of range for " .. l .. ": " .. x) elseif x >= 0 then - return 0xc0 + x + x = 0xc0 + x + return else - return x + return x & 0xff end end table.insert(M.section_current.instructions, op) From e56a44afa95442d2ce88525d30c087d0197b3f7a Mon Sep 17 00:00:00 2001 From: mooz Date: Wed, 7 Nov 2018 20:28:48 +0100 Subject: [PATCH 05/41] Added CALF instruction. --- l7801.lua | 4 ++-- uPD7801.lua | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/l7801.lua b/l7801.lua index cd68a43..59bc296 100644 --- a/l7801.lua +++ b/l7801.lua @@ -38,7 +38,7 @@ local Keywords_data = { 'dc', } local Keywords_7801 = { - 'block', 'calt', 'dcr', 'jr', 'lxi', 'mvi', 'nop' + 'block', 'calf', 'calt', 'dcr', 'jr', 'lxi', 'mvi', 'nop' } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -65,7 +65,7 @@ local opcode_implied = lookupify{ 'block', 'dcr', 'nop' } local opcode_immediate = lookupify{ - 'calt', 'lxi', 'mvi' + 'calf', 'calt', 'lxi', 'mvi' } local opcode_relative = lookupify{ 'jr', diff --git a/uPD7801.lua b/uPD7801.lua index e0142d0..9c4da8d 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -275,6 +275,19 @@ M.calt = function(late, early) table.insert(M.section_current.instructions, op) end +M.calf = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local op = { cycles=16 } + op.size = function() late,early = M.size_op(late,early) return 2 end + op.bin = function() local l65dbg=l65dbg + local x = 0 + M.op_eval_word(late,early) + if x < 0x0800 or x > 0xffff then error("subroutine address out of range [0x0800-0xffff]: " .. x) end + x = x - 0x0800; + return { 0x78 | ((x>>8) & 0x07), x&0xff } + end + table.insert(M.section_current.instructions, op) +end + M.jr = function(label) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local parent,offset = M.label_current @@ -312,7 +325,6 @@ return M 8 bits instructions: JRE+ 0x4e xx 17 JRE- 0x4f xx 17 - CALF 0x78-0x75 xx 16 16 bits instructions: 0x48xx From 6fafc034a08397e3992bdeaa12100f4960b21001 Mon Sep 17 00:00:00 2001 From: mooz Date: Wed, 7 Nov 2018 22:42:48 +0100 Subject: [PATCH 06/41] Added support for single register addressing. --- l7801.lua | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/l7801.lua b/l7801.lua index 59bc296..9127721 100644 --- a/l7801.lua +++ b/l7801.lua @@ -70,11 +70,20 @@ local opcode_immediate = lookupify{ local opcode_relative = lookupify{ 'jr', } +local opcode_reg = lookupify{ + 'dcr', 'inr' +} +local opcode_reg_list = { + a = lookupify{'dcr','inr'}, + b = lookupify{'dcr','inr'}, + c = lookupify{'dcr','inr'}, +} local addressing_map = { imp = opcode_implied, imm = opcode_immediate, rel = opcode_relative, + reg = opcode_reg, } local Scope = { @@ -1382,6 +1391,14 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end + if opcode_reg[op] then + local register_name = tok:Get(tokenList).Data + if not Registers_7801[register_name] then return false, GenerateError(register_name .. " is not a valid register") end + if not opcode_reg_list[register_name] and opcode_reg_list[register_name][op] then + return false, GenerateError("Opcode " .. op " doesn't support " .. register_name .. " register") + end + stat = emit_call{name=op .. register_name, args={expr}, encapsulate=false} break + end if opcode_implied[op] then stat = emit_call{name=op} break end error("internal error: unable to find addressing of valid opcode " .. op) -- should not happen end From 564746133a8e5905d5a67c59175254f4604bceb6 Mon Sep 17 00:00:00 2001 From: mooz Date: Thu, 8 Nov 2018 01:11:17 +0100 Subject: [PATCH 07/41] Added LXI instruction. --- l7801.lua | 55 ++++++++++++++++++++++++++++++++++++++++++++--------- uPD7801.lua | 16 ++++++++-------- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/l7801.lua b/l7801.lua index 9127721..6305759 100644 --- a/l7801.lua +++ b/l7801.lua @@ -38,7 +38,9 @@ local Keywords_data = { 'dc', } local Keywords_7801 = { - 'block', 'calf', 'calt', 'dcr', 'jr', 'lxi', 'mvi', 'nop' + 'block', 'calb', 'calf', 'calt', 'daa', 'dcr', 'exa', 'exx', + 'halt', 'jb', 'jr', 'lxi', 'mvi', 'nop', 'ret', 'reti', + 'rets', 'sio', 'softi', 'stm', 'table', } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -62,10 +64,10 @@ opcode_arg_encapsulate(true) local opcode_encapsulate = {} -- additionnal opcode, to have basic encapsulation (function(a) return a end) local opcode_alias = {} -- alternate user names for opcodes local opcode_implied = lookupify{ - 'block', 'dcr', 'nop' + 'block', 'calb', 'daa', 'exa', 'exx', 'halt', 'jb', 'nop', 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table' } local opcode_immediate = lookupify{ - 'calf', 'calt', 'lxi', 'mvi' + 'calf', 'calt' } local opcode_relative = lookupify{ 'jr', @@ -73,10 +75,17 @@ local opcode_relative = lookupify{ local opcode_reg = lookupify{ 'dcr', 'inr' } +local opcode_regw = lookupify{ + 'lxi' +} local opcode_reg_list = { a = lookupify{'dcr','inr'}, b = lookupify{'dcr','inr'}, c = lookupify{'dcr','inr'}, + bc = lookupify{'lxi'}, + de = lookupify{'lxi'}, + hl = lookupify{'lxi'}, + sp = lookupify{'lxi'}, } local addressing_map = { @@ -84,6 +93,7 @@ local addressing_map = { imm = opcode_immediate, rel = opcode_relative, reg = opcode_reg, + regw = opcode_regw, } local Scope = { @@ -1391,13 +1401,40 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end - if opcode_reg[op] then + if opcode_reg[op] or opcode_regw[op] then + tok:Save() local register_name = tok:Get(tokenList).Data - if not Registers_7801[register_name] then return false, GenerateError(register_name .. " is not a valid register") end - if not opcode_reg_list[register_name] and opcode_reg_list[register_name][op] then - return false, GenerateError("Opcode " .. op " doesn't support " .. register_name .. " register") - end - stat = emit_call{name=op .. register_name, args={expr}, encapsulate=false} break + local call_args = {name=op..register_name} + if not Registers_7801[register_name] then tok:Restore() + return false, GenerateError(register_name .. " is not a valid register") + end + if not opcode_reg_list[register_name] and opcode_reg_list[register_name][op] then tok:Restore() + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + if opcode_regw[op] then + if not tok:ConsumeSymbol(',', tokenList) then tok:Restore() + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + local inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) if not st then tok:Restore() + 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 + if tok:ConsumeSymbol(',', tokenList) then + commaTokenList[1] = tokenList[#tokenList] + mod_st, mod_expr = ParseExpr(scope) + if not mod_st then tok:Restore() + return false, mod_expr + end + end + call_args.args={expr, mod_expr} + call_args.inverse_encapsulate=inverse_encapsulate + call_args.paren_open_white=paren_open_whites + end + tok:Commit() + stat = emit_call(call_args) break end if opcode_implied[op] then stat = emit_call{name=op} break end error("internal error: unable to find addressing of valid opcode " .. op) -- should not happen diff --git a/uPD7801.lua b/uPD7801.lua index 9c4da8d..aa7dd5f 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -209,8 +209,8 @@ for k,v in pairs(opvind) do end end ---[[ [todo] -local opvindxx ={ +--[[ +local opviwaxx ={ aniw=M.op(0x05,16), oriw=M.op(0x15,16), gtiw=M.op(0x25,13), @@ -220,8 +220,8 @@ local opvindxx ={ neiw=M.op(0x65,13), mviw=M.op(0x71,13), eqiw=M.op(0x75,13) -} M.opvindxx = opvindxx -for k,v in pairs(opvindxx) do +} M.opvwaxx = opvwaxx +for k,v in pairs(opvwaxx) do M[k .. 'vindxx'] = function(late0, early0, late1, early1) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() @@ -240,16 +240,16 @@ for k,v in pairs(opvindxx) do end ]]-- -local opwwww = { +local opw = { call=M.op(0x44,16), jmp=M.op(0x54,10), lxisp=M.op(0x04,10), lxibc=M.op(0x14,10), lxide=M.op(0x24,10), lxihl=M.op(0x34,10) -} M.opwwww = opwwww -for k,v in pairs(opwwww) do - M[k .. 'wwww'] = function(late, early) +} M.opw = opw +for k,v in pairs(opw) do + M[k] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 3 end local bin = function() local l65dbg=l65dbg From 6efbd07034e7740623a19d4dbf94c3903cf90bb5 Mon Sep 17 00:00:00 2001 From: mooz Date: Fri, 9 Nov 2018 19:04:44 +0100 Subject: [PATCH 08/41] Added 16 bits implied instructions (ei, di, etc...). --- l7801.lua | 26 +++++++++++------ samples/scv_hello.l65 | 40 ++++++++++++++++++++++++++ uPD7801.lua | 65 ++++++++++++++++++++----------------------- 3 files changed, 87 insertions(+), 44 deletions(-) create mode 100644 samples/scv_hello.l65 diff --git a/l7801.lua b/l7801.lua index 6305759..a5aebc7 100644 --- a/l7801.lua +++ b/l7801.lua @@ -38,9 +38,9 @@ local Keywords_data = { 'dc', } local Keywords_7801 = { - 'block', 'calb', 'calf', 'calt', 'daa', 'dcr', 'exa', 'exx', - 'halt', 'jb', 'jr', 'lxi', 'mvi', 'nop', 'ret', 'reti', - 'rets', 'sio', 'softi', 'stm', 'table', + 'block', 'calb', 'calf', 'calt', 'ei', 'daa', 'di', 'dcr', + 'exa', 'exx', 'halt', 'jb', 'jr', 'lxi', 'mvi', 'nop', + 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table', } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -64,7 +64,7 @@ opcode_arg_encapsulate(true) local opcode_encapsulate = {} -- additionnal opcode, to have basic encapsulation (function(a) return a end) local opcode_alias = {} -- alternate user names for opcodes local opcode_implied = lookupify{ - 'block', 'calb', 'daa', 'exa', 'exx', 'halt', 'jb', 'nop', 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table' + 'block', 'calb', 'ei', 'daa', 'di', 'exa', 'exx', 'halt', 'jb', 'nop', 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table' } local opcode_immediate = lookupify{ 'calf', 'calt' @@ -75,13 +75,20 @@ local opcode_relative = lookupify{ local opcode_reg = lookupify{ 'dcr', 'inr' } +local opcode_regb = lookupify{ + 'mvi' +} local opcode_regw = lookupify{ 'lxi' } local opcode_reg_list = { - a = lookupify{'dcr','inr'}, - b = lookupify{'dcr','inr'}, - c = lookupify{'dcr','inr'}, + a = lookupify{'dcr','inr', 'mvi'}, + b = lookupify{'dcr','inr', 'mvi'}, + c = lookupify{'dcr','inr', 'mvi'}, + d = lookupify{'mvi'}, + e = lookupify{'mvi'}, + h = lookupify{'mvi'}, + l = lookupify{'mvi'}, bc = lookupify{'lxi'}, de = lookupify{'lxi'}, hl = lookupify{'lxi'}, @@ -93,6 +100,7 @@ local addressing_map = { imm = opcode_immediate, rel = opcode_relative, reg = opcode_reg, + regb = opcode_regb, regw = opcode_regw, } @@ -1401,7 +1409,7 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end - if opcode_reg[op] or opcode_regw[op] then + if opcode_reg[op] or opcode_regb[op] or opcode_regw[op] then tok:Save() local register_name = tok:Get(tokenList).Data local call_args = {name=op..register_name} @@ -1411,7 +1419,7 @@ local function ParseLua(src, src_name) if not opcode_reg_list[register_name] and opcode_reg_list[register_name][op] then tok:Restore() return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - if opcode_regw[op] then + if opcode_regw[op] or opcode_regb[op] then if not tok:ConsumeSymbol(',', tokenList) then tok:Restore() return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end diff --git a/samples/scv_hello.l65 b/samples/scv_hello.l65 new file mode 100644 index 0000000..1129fa1 --- /dev/null +++ b/samples/scv_hello.l65 @@ -0,0 +1,40 @@ +require 'scv' +location(0x8000, 0x8FFF) +section{"rom", org=0x8000} + dc.b 'H' +@main + di + lxi sp,0xFFD2 + ei + calt 0x8C + + lxi hl,vdc_data + lxi de,0x3400 + mvi c,0x03 + block + + lxi hl,message + lxi de,0x3043 + lxi bc,0x01ff + +@loop_0 + block + dcr b + jr loop_0 + + -- beep + lxi hl,0x3600 + calf 0xfb0 + +@loop_1 + nop + jr loop_1 + +section{"vdc_data", org=0x8030} + dc.b 0xC0,0x00,0x00,0xF2 + +section{"message", org=0x8040} + dc.b "hello world" + dc.b 0x00 + +writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index aa7dd5f..21597bf 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -141,7 +141,7 @@ for k,v in pairs(oprr) do end end -local oprxx ={ +local opregb ={ mvib=M.op(0x6a,7), mvic=M.op(0x6b,7), mvid=M.op(0x6c,7), @@ -149,9 +149,9 @@ local oprxx ={ mvih=M.op(0x6e,7), mvil=M.op(0x6f,7), mviv=M.op(0x68,7) -} M.oprxx = oprxx -for k,v in pairs(oprxx) do - M[k .. 'xx'] = function(late, early) +} M.opregb = opregb +for k,v in pairs(opregb) do + M[k] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 2 end local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end @@ -209,37 +209,6 @@ for k,v in pairs(opvind) do end end ---[[ -local opviwaxx ={ - aniw=M.op(0x05,16), - oriw=M.op(0x15,16), - gtiw=M.op(0x25,13), - ltiw=M.op(0x35,13), - oniw=M.op(0x45,13), - offiw=M.op(0x55,13), - neiw=M.op(0x65,13), - mviw=M.op(0x71,13), - eqiw=M.op(0x75,13) -} M.opvwaxx = opvwaxx -for k,v in pairs(opvwaxx) do - M[k .. 'vindxx'] = function(late0, early0, late1, early1) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() - late0,early0 = M.size_op(late,early) - late1,early1 = M.size_op(late,early) - return 3 - end - local bin = function() - local l65dbg=l65dbg - local offset = M.op_eval_byte(late0,early0) - local x = M.op_eval_byte(late1,early1) - return { v.opc, offset, x } - end - table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) - end -end -]]-- - local opw = { call=M.op(0x44,16), jmp=M.op(0x54,10), @@ -319,12 +288,38 @@ M.jr = function(label) table.insert(M.section_current.instructions, op) end +local op48imm = { + ei=M.op(0x20,8), + di=M.op(0x24,8), + clc=M.op(0x2a,8), + stc=M.op(0x2b,8), + pen=M.op(0x2c,11), + per=M.op(0x3c,11), + pex=M.op(0x2d,11), + rld=M.op(0x38,17), + rrd=M.op(0x39,17), +} M.op48imm = op48imm +for k,v in pairs(op48imm) do + M[k] = function() + table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x48, v.opc } }) + end +end + return M --[[ [todo] 8 bits instructions: JRE+ 0x4e xx 17 JRE- 0x4f xx 17 + ani + ori + gti + lti + oni + offi + nei + mvi + eqi 16 bits instructions: 0x48xx From 6fc00c2b6345b4df27a39f4ba2cede207a650d9c Mon Sep 17 00:00:00 2001 From: mooz Date: Fri, 9 Nov 2018 21:55:21 +0100 Subject: [PATCH 09/41] Fixed table opcode. --- l7801.lua | 6 +- uPD7801.lua | 216 +++++++++++++++++++++------------------------------- 2 files changed, 90 insertions(+), 132 deletions(-) diff --git a/l7801.lua b/l7801.lua index a5aebc7..efd5655 100644 --- a/l7801.lua +++ b/l7801.lua @@ -39,7 +39,7 @@ local Keywords_data = { } local Keywords_7801 = { 'block', 'calb', 'calf', 'calt', 'ei', 'daa', 'di', 'dcr', - 'exa', 'exx', 'halt', 'jb', 'jr', 'lxi', 'mvi', 'nop', + 'ex', 'exx', 'halt', 'jb', 'jr', 'lxi', 'mvi', 'nop', 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table', } local Registers_7801 = { @@ -64,7 +64,7 @@ opcode_arg_encapsulate(true) local opcode_encapsulate = {} -- additionnal opcode, to have basic encapsulation (function(a) return a end) local opcode_alias = {} -- alternate user names for opcodes local opcode_implied = lookupify{ - 'block', 'calb', 'ei', 'daa', 'di', 'exa', 'exx', 'halt', 'jb', 'nop', 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table' + 'block', 'calb', 'ei', 'daa', 'di', 'ex', 'exx', 'halt', 'jb', 'nop', 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table' } local opcode_immediate = lookupify{ 'calf', 'calt' @@ -1444,7 +1444,7 @@ local function ParseLua(src, src_name) tok:Commit() stat = emit_call(call_args) break end - if opcode_implied[op] then stat = emit_call{name=op} break end + if opcode_implied[op] then stat = emit_call{name=op .. 'imp'} break end error("internal error: unable to find addressing of valid opcode " .. op) -- should not happen end end end diff --git a/uPD7801.lua b/uPD7801.lua index 21597bf..a6ff7ba 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -10,7 +10,7 @@ local opimp={ block=M.op(0x31,13), calb=M.op(0x63,13), daa=M.op(0x61,4), - exa=M.op(0x10,4), + ex=M.op(0x10,4), exx=M.op(0x11,4), halt=M.op(0x01,6), jb=M.op(0x73,4), @@ -21,10 +21,10 @@ local opimp={ sio=M.op(0x09,4), softi=M.op(0x72,19), stm=M.op(0x19,4), - table=M.op(0x21,19) + ['table']=M.op(0x21,19) } M.opimp = opimp for k,v in pairs(opimp) do - M[k] = function() + M[k .. 'imp' ] = function() table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) end end @@ -59,64 +59,6 @@ for k,v in pairs(opc) do end end -local opd={ - ldaxm=M.op(0x2e,7), - ldaxp=M.op(0x2c,7), - staxm=M.op(0x3e,7), - staxp=M.op(0x3c,7) -} M.opd = opd -for k,v in pairs(opd) do - M[k .. 'd'] = function() - table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) - end -end - -local oph={ - ldaxm=M.op(0x2f,7), - ldaxp=M.op(0x2d,7), - staxm=M.op(0x3f,7), - staxp=M.op(0x3d,7) -} M.oph = oph -for k,v in pairs(oph) do - M[k .. 'h'] = function() - table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) - end -end - -local oprwind={ - dcxbc=M.op(0x13,7), - dcxde=M.op(0x23,7), - dcxhl=M.op(0x33,7), - inxbc=M.op(0x12,7), - inxde=M.op(0x22,7), - inxhl=M.op(0x32,7), - ldaxbc=M.op(0x29,7), - ldaxde=M.op(0x2a,7), - ldaxhl=M.op(0x2b,7), - staxbc=M.op(0x39,7), - staxde=M.op(0x3a,7), - staxhl=M.op(0x3b,7), -} M.oprwind = oprwind -for k,v in pairs(oprwind) do - M[k .. 'ind'] = function() - table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) - end -end - -local opindxx ={ - mvixbc=M.op(0x49,10), - mvixde=M.op(0x4a,10), - mvixhl=M.op(0x4b,10) -} M.opindxx = opindxx -for k,v in pairs(opindxx) do - M[k .. 'indxx'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = M.size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end - table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) - end -end - local opsp={ dcx=M.op(0x03,7), inx=M.op(0x02,7) @@ -127,20 +69,6 @@ for k,v in pairs(opsp) do end end -local oprr={ - movab=M.op(0x0a,4), movac=M.op(0x0b,4), - movad=M.op(0x0c,4), movae=M.op(0x0d,4), - movah=M.op(0x0e,4), moval=M.op(0x0f,4), - movba=M.op(0x1a,4), movca=M.op(0x1b,4), - movda=M.op(0x1c,4), movea=M.op(0x1d,4), - movha=M.op(0x1e,4), movla=M.op(0x1f,4), -} M.oprr = oprr -for k,v in pairs(oprr) do - M[k] = function() - table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) - end -end - local opregb ={ mvib=M.op(0x6a,7), mvic=M.op(0x6b,7), @@ -159,56 +87,6 @@ for k,v in pairs(opregb) do end end -local opaxx={ - aci=M.op(0x56,7), - adi=M.op(0x46,7), - adinc=M.op(0x26,7), - ani=M.op(0x07,7), - eqi=M.op(0x77,7), - gti=M.op(0x27,7), - lti=M.op(0x37,7), - mvi=M.op(0x69,7), - nei=M.op(0x69,7), - offi=M.op(0x57,7), - oni=M.op(0x47,7), - ori=M.op(0x17,7), - sbi=M.op(0x76,7), - sui=M.op(0x61,7), - suinb=M.op(0x36,7), - xri=M.op(0x16,7) -} M.opaxx = opaxx -for k,v in pairs(opaxx) do - M[k .. 'axx'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = M.size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end - table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) - end -end - -local opvind ={ - inrw=M.op(0x20,13), - ldaw=M.op(0x28,10), - dcrw=M.op(0x30,13), - staw=M.op(0x38,10), - bit0=M.op(0x58,10), - bit1=M.op(0x59,10), - bit2=M.op(0x5a,10), - bit3=M.op(0x5b,10), - bit4=M.op(0x5c,10), - bit5=M.op(0x5d,10), - bit6=M.op(0x5e,10), - bit7=M.op(0x5f,10) -} M.opvind = opvind -for k,v in pairs(opvind) do - M[k .. 'vind'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = M.size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end - table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) - end -end - local opw = { call=M.op(0x44,16), jmp=M.op(0x54,10), @@ -288,7 +166,7 @@ M.jr = function(label) table.insert(M.section_current.instructions, op) end -local op48imm = { +local op48imp = { ei=M.op(0x20,8), di=M.op(0x24,8), clc=M.op(0x2a,8), @@ -298,9 +176,9 @@ local op48imm = { pex=M.op(0x2d,11), rld=M.op(0x38,17), rrd=M.op(0x39,17), -} M.op48imm = op48imm -for k,v in pairs(op48imm) do - M[k] = function() +} M.op48imp = op48imp +for k,v in pairs(op48imp) do + M[k .. 'imp'] = function() table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x48, v.opc } }) end end @@ -321,6 +199,86 @@ return M mvi eqi + -- d + ldaxm=M.op(0x2e,7), + ldaxp=M.op(0x2c,7), + staxm=M.op(0x3e,7), + staxp=M.op(0x3c,7) + + -- h + ldaxm=M.op(0x2f,7), + ldaxp=M.op(0x2d,7), + staxm=M.op(0x3f,7), + staxp=M.op(0x3d,7) + + -- wa = v+xx + inrw=M.op(0x20,13), + ldaw=M.op(0x28,10), + dcrw=M.op(0x30,13), + staw=M.op(0x38,10), + bit0=M.op(0x58,10), + bit1=M.op(0x59,10), + bit2=M.op(0x5a,10), + bit3=M.op(0x5b,10), + bit4=M.op(0x5c,10), + bit5=M.op(0x5d,10), + bit6=M.op(0x5e,10), + bit7=M.op(0x5f,10) + + -- xx + aci=M.op(0x56,7), + adi=M.op(0x46,7), + adinc=M.op(0x26,7), + ani=M.op(0x07,7), + eqi=M.op(0x77,7), + gti=M.op(0x27,7), + lti=M.op(0x37,7), + mvi=M.op(0x69,7), + nei=M.op(0x69,7), + offi=M.op(0x57,7), + oni=M.op(0x47,7), + ori=M.op(0x17,7), + sbi=M.op(0x76,7), + sui=M.op(0x61,7), + suinb=M.op(0x36,7), + xri=M.op(0x16,7) + + -- r8,r8 + movab=M.op(0x0a,4), movac=M.op(0x0b,4), + movad=M.op(0x0c,4), movae=M.op(0x0d,4), + movah=M.op(0x0e,4), moval=M.op(0x0f,4), + movba=M.op(0x1a,4), movca=M.op(0x1b,4), + movda=M.op(0x1c,4), movea=M.op(0x1d,4), + movha=M.op(0x1e,4), movla=M.op(0x1f,4), + + -- hhll + call=M.op(0x44,16), + jmp=M.op(0x54,10), + lxisp=M.op(0x04,10), + lxibc=M.op(0x14,10), + lxide=M.op(0x24,10), + lxihl=M.op(0x34,10) + + -- (r16),hhll + mvixbc=M.op(0x49,10), + mvixde=M.op(0x4a,10), + mvixhl=M.op(0x4b,10) + + - (r16) + dcxbc=M.op(0x13,7), + dcxde=M.op(0x23,7), + dcxhl=M.op(0x33,7), + inxbc=M.op(0x12,7), + inxde=M.op(0x22,7), + inxhl=M.op(0x32,7), + ldaxbc=M.op(0x29,7), + ldaxde=M.op(0x2a,7), + ldaxhl=M.op(0x2b,7), + staxbc=M.op(0x39,7), + staxde=M.op(0x3a,7), + staxhl=M.op(0x3b,7), + + 16 bits instructions: 0x48xx 0x4cxx From 6708ddaecc060419fa78e83d8020ff79e3bece0b Mon Sep 17 00:00:00 2001 From: mooz Date: Fri, 9 Nov 2018 23:40:05 +0100 Subject: [PATCH 10/41] Added and tested a bunch of opcodes. --- l7801.lua | 28 +++++++++++------- samples/scv_test.l65 | 68 ++++++++++++++++++++++++++++++++++++++++++++ scv.l65 | 3 ++ uPD7801.lua | 57 +++++++++++++++++++++---------------- 4 files changed, 121 insertions(+), 35 deletions(-) create mode 100644 samples/scv_test.l65 create mode 100644 scv.l65 diff --git a/l7801.lua b/l7801.lua index efd5655..c87a5fc 100644 --- a/l7801.lua +++ b/l7801.lua @@ -38,10 +38,13 @@ local Keywords_data = { 'dc', } local Keywords_7801 = { - 'block', 'calb', 'calf', 'calt', 'ei', 'daa', 'di', 'dcr', - 'ex', 'exx', 'halt', 'jb', 'jr', 'lxi', 'mvi', 'nop', - 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table', + 'aci','adi','adinc','ani', + 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcx', + 'ex','exx','gti','halt','inr','inx','jb','jmp','jr','lti','lxi','mvi','nei','nop', + 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','stc','stm', + 'sbi','sui','suinb','table','xri', } + local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, bc=16,de=16,hl=16,sp=16 @@ -64,35 +67,38 @@ opcode_arg_encapsulate(true) local opcode_encapsulate = {} -- additionnal opcode, to have basic encapsulation (function(a) return a end) local opcode_alias = {} -- alternate user names for opcodes local opcode_implied = lookupify{ - 'block', 'calb', 'ei', 'daa', 'di', 'ex', 'exx', 'halt', 'jb', 'nop', 'ret', 'reti', 'rets', 'sio', 'softi', 'stm', 'table' + 'block','calb','clc','ei','daa','dcr','di','ex','exx','halt','inr','jb','nop','pen', + 'per','pex','ret','reti','rets','rld','rrd','sio','softi','stc','stm','table' } + local opcode_immediate = lookupify{ - 'calf', 'calt' + 'calf', 'calt','call','jmp' } local opcode_relative = lookupify{ 'jr', } local opcode_reg = lookupify{ - 'dcr', 'inr' + 'dcr','dcx','inr','inx' } local opcode_regb = lookupify{ - 'mvi' + 'aci','adi','adinc','ani','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri', } local opcode_regw = lookupify{ 'lxi' } local opcode_reg_list = { - a = lookupify{'dcr','inr', 'mvi'}, - b = lookupify{'dcr','inr', 'mvi'}, - c = lookupify{'dcr','inr', 'mvi'}, + a = lookupify{'aci','adi','adinc','ani','dcr','inr','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri'}, + b = lookupify{'dcr','inr','mvi'}, + c = lookupify{'dcr','inr','mvi'}, d = lookupify{'mvi'}, e = lookupify{'mvi'}, h = lookupify{'mvi'}, l = lookupify{'mvi'}, + v = lookupify{'mvi'}, bc = lookupify{'lxi'}, de = lookupify{'lxi'}, hl = lookupify{'lxi'}, - sp = lookupify{'lxi'}, + sp = lookupify{'dcx','inx','lxi'}, } local addressing_map = { diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 new file mode 100644 index 0000000..abcce1c --- /dev/null +++ b/samples/scv_test.l65 @@ -0,0 +1,68 @@ +require 'scv' +location(0x8000, 0x8FFF) +section{"rom", org=0x8000} + dc.b 'H' +@main + block + calb + ei + daa + di + ex + exx + halt + jb + nop + ret + reti + rets + sio + softi + stm + table + dcr a + dcr b + dcr c + inr a + inr b + inr c + dcx sp + inx sp + mvi a,0xca + mvi b,0xfe + mvi c,0xbe + mvi d,0xef + mvi e,0xf0 + mvi h,0x0d + mvi l,0x78 + mvi v,0x01 + aci a,0x0f + adi a,0x1e + adinc a,0x2d + ani a,0x3c + eqi a,0x4b + gti a,0x5a + lti a,0x69 + nei a,0x87 + offi a,0x96 + oni a,0xa5 + ori a,0xb4 + sbi a,0xc3 + sui a,0xd2 + suinb a,0xe1 + xri a,0xf0 + lxi bc,0xabcd + lxi de,0xbeef + lxi hl,0xcafe + lxi sp,0xf00d + call 0xd701 + jmp 0x8e07 + clc + pen + per + pex + rld + rrd + stc + +writebin(filename .. '.bin') \ No newline at end of file diff --git a/scv.l65 b/scv.l65 new file mode 100644 index 0000000..c92d5cd --- /dev/null +++ b/scv.l65 @@ -0,0 +1,3 @@ +cpu = require 'uPD7801' +setmetatable(_ENV, cpu) + diff --git a/uPD7801.lua b/uPD7801.lua index a6ff7ba..a16130f 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -31,7 +31,7 @@ end local opa={ dcr=M.op(0x51,4), - inr=M.op(0x41,4) + inr=M.op(0x41,4), } M.opa = opa for k,v in pairs(opa) do M[k .. 'a'] = function() @@ -41,7 +41,7 @@ end local opb={ dcr=M.op(0x52,4), - inr=M.op(0x42,4) + inr=M.op(0x42,4), } M.opb = opb for k,v in pairs(opb) do M[k .. 'b'] = function() @@ -69,7 +69,7 @@ for k,v in pairs(opsp) do end end -local opregb ={ +local opregxx ={ mvib=M.op(0x6a,7), mvic=M.op(0x6b,7), mvid=M.op(0x6c,7), @@ -77,8 +77,8 @@ local opregb ={ mvih=M.op(0x6e,7), mvil=M.op(0x6f,7), mviv=M.op(0x68,7) -} M.opregb = opregb -for k,v in pairs(opregb) do +} M.opregxx = opregxx +for k,v in pairs(opregxx) do M[k] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 2 end @@ -87,6 +87,33 @@ for k,v in pairs(opregb) do end end +local opaxx ={ + aci=M.op(0x56,7), + adi=M.op(0x46,7), + adinc=M.op(0x26,7), + ani=M.op(0x07,7), + eqi=M.op(0x77,7), + gti=M.op(0x27,7), + lti=M.op(0x37,7), + mvi=M.op(0x69,7), + nei=M.op(0x67,7), + offi=M.op(0x57,7), + oni=M.op(0x47,7), + ori=M.op(0x17,7), + sbi=M.op(0x76,7), + sui=M.op(0x66,7), + suinb=M.op(0x36,7), + xri=M.op(0x16,7) +} M.opaxx = opaxx +for k,v in pairs(opaxx) do + M[k .. 'a'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + local opw = { call=M.op(0x44,16), jmp=M.op(0x54,10), @@ -170,12 +197,12 @@ local op48imp = { ei=M.op(0x20,8), di=M.op(0x24,8), clc=M.op(0x2a,8), - stc=M.op(0x2b,8), pen=M.op(0x2c,11), per=M.op(0x3c,11), pex=M.op(0x2d,11), rld=M.op(0x38,17), rrd=M.op(0x39,17), + stc=M.op(0x2b,8), } M.op48imp = op48imp for k,v in pairs(op48imp) do M[k .. 'imp'] = function() @@ -225,24 +252,6 @@ return M bit6=M.op(0x5e,10), bit7=M.op(0x5f,10) - -- xx - aci=M.op(0x56,7), - adi=M.op(0x46,7), - adinc=M.op(0x26,7), - ani=M.op(0x07,7), - eqi=M.op(0x77,7), - gti=M.op(0x27,7), - lti=M.op(0x37,7), - mvi=M.op(0x69,7), - nei=M.op(0x69,7), - offi=M.op(0x57,7), - oni=M.op(0x47,7), - ori=M.op(0x17,7), - sbi=M.op(0x76,7), - sui=M.op(0x61,7), - suinb=M.op(0x36,7), - xri=M.op(0x16,7) - -- r8,r8 movab=M.op(0x0a,4), movac=M.op(0x0b,4), movad=M.op(0x0c,4), movae=M.op(0x0d,4), From 2d96e4e1d27993343b8fd2f5c5e7fee52943269d Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 10 Nov 2018 00:23:56 +0100 Subject: [PATCH 11/41] Added MOV (8 bits version) instruction. --- l7801.lua | 56 ++++++++++++++++++++++++++++++++++++++++++-- samples/scv_test.l65 | 15 +++++++++++- uPD7801.lua | 33 ++++++++++++-------------- 3 files changed, 83 insertions(+), 21 deletions(-) diff --git a/l7801.lua b/l7801.lua index c87a5fc..b080f16 100644 --- a/l7801.lua +++ b/l7801.lua @@ -40,7 +40,7 @@ local Keywords_data = { local Keywords_7801 = { 'aci','adi','adinc','ani', 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcx', - 'ex','exx','gti','halt','inr','inx','jb','jmp','jr','lti','lxi','mvi','nei','nop', + 'ex','exx','gti','halt','inr','inx','jb','jmp','jr','lti','lxi','mov','mvi','nei','nop', 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','stc','stm', 'sbi','sui','suinb','table','xri', } @@ -80,6 +80,9 @@ local opcode_relative = lookupify{ local opcode_reg = lookupify{ 'dcr','dcx','inr','inx' } +local opcode_reg_reg = lookupify{ + 'mov' +} local opcode_regb = lookupify{ 'aci','adi','adinc','ani','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri', } @@ -101,6 +104,36 @@ local opcode_reg_list = { sp = lookupify{'dcx','inx','lxi'}, } +local opcode_reg_reg_list = { + a = { + b = lookupify{'mov'}, + c = lookupify{'mov'}, + d = lookupify{'mov'}, + e = lookupify{'mov'}, + h = lookupify{'mov'}, + l = lookupify{'mov'}, + }, + b = { + a = lookupify{'mov'}, + }, + c = { + a = lookupify{'mov'}, + }, + d = { + a = lookupify{'mov'}, + }, + e = { + a = lookupify{'mov'}, + }, + h = { + a = lookupify{'mov'}, + }, + l = { + a = lookupify{'mov'}, + }, + v = {}, +} + local addressing_map = { imp = opcode_implied, imm = opcode_immediate, @@ -1415,7 +1448,26 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end - if opcode_reg[op] or opcode_regb[op] or opcode_regw[op] then + if opcode_reg_reg[op] then + tok:Save() + local r0_name = tok:Get(tokenList).Data + if not Registers_7801[r0_name] then tok:Restore() + return false, GenerateError(r0_name .. " is not a valid register") + end + if not tok:ConsumeSymbol(',', tokenList) then tok:Restore() + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + local r1_name = tok:Get(tokenList).Data + if not Registers_7801[r1_name] then tok:Restore() + return false, GenerateError(r0_name .. " is not a valid register") + end + if not (opcode_reg_reg_list[r0_name] and opcode_reg_reg_list[r0_name][r1_name] and opcode_reg_reg_list[r0_name][r1_name][op]) then + tok:Restore() + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + tok:Commit() + stat = emit_call{name=op .. r0_name .. r1_name} break + elseif opcode_reg[op] or opcode_regb[op] or opcode_regw[op] then tok:Save() local register_name = tok:Get(tokenList).Data local call_args = {name=op..register_name} diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index abcce1c..3a1f3cd 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -64,5 +64,18 @@ section{"rom", org=0x8000} rld rrd stc - + mov a,b + mov a,c + mov a,d + mov a,e + mov a,h + mov a,l + mov b,a + mov c,a + mov d,a + mov e,a + mov h,a + mov l,a + + writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index a16130f..4df0675 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -114,6 +114,20 @@ for k,v in pairs(opaxx) do end end +local opr8r8 ={ + movab=M.op(0x0a,4), movac=M.op(0x0b,4), + movad=M.op(0x0c,4), movae=M.op(0x0d,4), + movah=M.op(0x0e,4), moval=M.op(0x0f,4), + movba=M.op(0x1a,4), movca=M.op(0x1b,4), + movda=M.op(0x1c,4), movea=M.op(0x1d,4), + movha=M.op(0x1e,4), movla=M.op(0x1f,4), +} M.opr8r8 = opr8r8 +for k,v in pairs(opr8r8) do + M[k] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + local opw = { call=M.op(0x44,16), jmp=M.op(0x54,10), @@ -216,16 +230,7 @@ return M 8 bits instructions: JRE+ 0x4e xx 17 JRE- 0x4f xx 17 - ani - ori - gti - lti - oni - offi - nei - mvi - eqi - + -- d ldaxm=M.op(0x2e,7), ldaxp=M.op(0x2c,7), @@ -252,14 +257,6 @@ return M bit6=M.op(0x5e,10), bit7=M.op(0x5f,10) - -- r8,r8 - movab=M.op(0x0a,4), movac=M.op(0x0b,4), - movad=M.op(0x0c,4), movae=M.op(0x0d,4), - movah=M.op(0x0e,4), moval=M.op(0x0f,4), - movba=M.op(0x1a,4), movca=M.op(0x1b,4), - movda=M.op(0x1c,4), movea=M.op(0x1d,4), - movha=M.op(0x1e,4), movla=M.op(0x1f,4), - -- hhll call=M.op(0x44,16), jmp=M.op(0x54,10), From f917afff6aae33a2853689373d9931bf3be76722 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 10 Nov 2018 12:50:03 +0100 Subject: [PATCH 12/41] Added JRE instruction. --- l7801.lua | 6 +++--- samples/scv_hello.l65 | 4 ++-- samples/scv_test.l65 | 21 +++++++++++++++++++-- uPD7801.lua | 37 +++++++++++++++++++++++++++---------- 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/l7801.lua b/l7801.lua index b080f16..874b7a1 100644 --- a/l7801.lua +++ b/l7801.lua @@ -40,7 +40,7 @@ local Keywords_data = { local Keywords_7801 = { 'aci','adi','adinc','ani', 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcx', - 'ex','exx','gti','halt','inr','inx','jb','jmp','jr','lti','lxi','mov','mvi','nei','nop', + 'ex','exx','gti','halt','inr','inx','jb','jmp','jr','jre','lti','lxi','mov','mvi','nei','nop', 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','stc','stm', 'sbi','sui','suinb','table','xri', } @@ -72,10 +72,10 @@ local opcode_implied = lookupify{ } local opcode_immediate = lookupify{ - 'calf', 'calt','call','jmp' + 'calf','calt','call','jmp' } local opcode_relative = lookupify{ - 'jr', + 'jr','jre' } local opcode_reg = lookupify{ 'dcr','dcx','inr','inx' diff --git a/samples/scv_hello.l65 b/samples/scv_hello.l65 index 1129fa1..725e08b 100644 --- a/samples/scv_hello.l65 +++ b/samples/scv_hello.l65 @@ -14,7 +14,7 @@ section{"rom", org=0x8000} block lxi hl,message - lxi de,0x3043 + lxi de,0x3044 lxi bc,0x01ff @loop_0 @@ -34,7 +34,7 @@ section{"vdc_data", org=0x8030} dc.b 0xC0,0x00,0x00,0xF2 section{"message", org=0x8040} - dc.b "hello world" + dc.b "\t\t\t\t Hello world! \t\t\t\t" dc.b 0x00 writebin(filename .. '.bin') \ No newline at end of file diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 3a1f3cd..edd5877 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -76,6 +76,23 @@ section{"rom", org=0x8000} mov e,a mov h,a mov l,a - - +@l0 jre l0 +@l1 nop + jre l1 +@l2 nop nop + jre l2 +@l3 nop nop nop + jre l3 +@l4 nop nop nop nop + jre l4 + jre l5 +@l5 jre l6 + nop +@l6 jre l7 + nop nop +@l7 jre l8 + nop nop nop +@l8 jre l9 + nop nop nop nop +@l9 writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 4df0675..5bf0ee7 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -207,6 +207,33 @@ M.jr = function(label) table.insert(M.section_current.instructions, op) end +M.jre = function(label) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local parent,offset = M.label_current + local section,rorg = M.section_current,M.location_current.rorg + local op = { cycles=17 } + op.size = function() + offset = section.size + label = M.size_dc(label) + return 2 + end + op.bin = function() + local l65dbg=l65dbg + local x,l = label,label + if type(x) == 'function' then x=x() end + if type(x) == 'string' then + if x:sub(1,1) == '_' then x=parent..x l=x end + x = symbols[x] + end + if type(x) ~= 'number' then error("unresolved branch target: " .. tostring(x)) end + x = x-2 - offset - rorg(section.org) + if x < -128 or x > 127 then error("branch target out of range for " .. l .. ": " .. x) end + local opcode = x >= 0 and 0x4e or 0x4f + return { opcode, x&0xff } + end + table.insert(M.section_current.instructions, op) +end + local op48imp = { ei=M.op(0x20,8), di=M.op(0x24,8), @@ -228,8 +255,6 @@ return M --[[ [todo] 8 bits instructions: - JRE+ 0x4e xx 17 - JRE- 0x4f xx 17 -- d ldaxm=M.op(0x2e,7), @@ -257,14 +282,6 @@ return M bit6=M.op(0x5e,10), bit7=M.op(0x5f,10) - -- hhll - call=M.op(0x44,16), - jmp=M.op(0x54,10), - lxisp=M.op(0x04,10), - lxibc=M.op(0x14,10), - lxide=M.op(0x24,10), - lxihl=M.op(0x34,10) - -- (r16),hhll mvixbc=M.op(0x49,10), mvixde=M.op(0x4a,10), From 4ef0a69e8e11f0e85aea5159fc85678e38a01733 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 10 Nov 2018 14:22:38 +0100 Subject: [PATCH 13/41] Added INRW, LDAW, DCRW and STAW instructions. --- l7801.lua | 38 +++++++++++++++++++++++++++++++++----- uPD7801.lua | 39 +++++++++++++++++++++++---------------- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/l7801.lua b/l7801.lua index 874b7a1..d4b5805 100644 --- a/l7801.lua +++ b/l7801.lua @@ -38,10 +38,10 @@ local Keywords_data = { 'dc', } local Keywords_7801 = { - 'aci','adi','adinc','ani', - 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcx', - 'ex','exx','gti','halt','inr','inx','jb','jmp','jr','jre','lti','lxi','mov','mvi','nei','nop', - 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','stc','stm', + 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', + 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcrw','dcx', + 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','lti','lxi','mov','mvi','nei','nop', + 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','staw','stc','stm', 'sbi','sui','suinb','table','xri', } @@ -72,7 +72,10 @@ local opcode_implied = lookupify{ } local opcode_immediate = lookupify{ - 'calf','calt','call','jmp' + 'calf','calt','call','jmp', +} +local opcode_wa = lookupify{ + 'inrw','ldaw','dcrw','staw' } local opcode_relative = lookupify{ 'jr','jre' @@ -136,6 +139,7 @@ local opcode_reg_reg_list = { local addressing_map = { imp = opcode_implied, + wa = opcode_wa, imm = opcode_immediate, rel = opcode_relative, reg = opcode_reg, @@ -1448,6 +1452,30 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end + if opcode_wa[op] then + if not tok:ConsumeSymbol('(', tokenList) then + return false, GenerateError("Unexpected character") + end + if not (tok:Get(tokenList).Data == 'v') then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + if not tok:ConsumeSymbol(',', tokenList) then + return false, GenerateError("Unexpected character") + end + 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 + if tok:ConsumeSymbol(',', tokenList) then + commaTokenList[1] = tokenList[#tokenList] + mod_st, mod_expr = ParseExpr(scope) + if not mod_st then return false, mod_expr end + end + if not tok:ConsumeSymbol(')', tokenList) then return false, expr + end + stat = emit_call{name=op .. "wa", args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + end if opcode_reg_reg[op] then tok:Save() local r0_name = tok:Get(tokenList).Data diff --git a/uPD7801.lua b/uPD7801.lua index 5bf0ee7..a89cb3d 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -234,6 +234,29 @@ M.jre = function(label) table.insert(M.section_current.instructions, op) end +local opwa = { + inrw=M.op(0x20,13), + ldaw=M.op(0x28,10), + dcrw=M.op(0x30,13), + staw=M.op(0x38,10), + bit0=M.op(0x58,10), + bit1=M.op(0x59,10), + bit2=M.op(0x5a,10), + bit3=M.op(0x5b,10), + bit4=M.op(0x5c,10), + bit5=M.op(0x5d,10), + bit6=M.op(0x5e,10), + bit7=M.op(0x5f,10) +} M.opwa = opwa +for k,v in pairs(opwa) do + M[k .. 'wa'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + local op48imp = { ei=M.op(0x20,8), di=M.op(0x24,8), @@ -255,7 +278,6 @@ return M --[[ [todo] 8 bits instructions: - -- d ldaxm=M.op(0x2e,7), ldaxp=M.op(0x2c,7), @@ -268,20 +290,6 @@ return M staxm=M.op(0x3f,7), staxp=M.op(0x3d,7) - -- wa = v+xx - inrw=M.op(0x20,13), - ldaw=M.op(0x28,10), - dcrw=M.op(0x30,13), - staw=M.op(0x38,10), - bit0=M.op(0x58,10), - bit1=M.op(0x59,10), - bit2=M.op(0x5a,10), - bit3=M.op(0x5b,10), - bit4=M.op(0x5c,10), - bit5=M.op(0x5d,10), - bit6=M.op(0x5e,10), - bit7=M.op(0x5f,10) - -- (r16),hhll mvixbc=M.op(0x49,10), mvixde=M.op(0x4a,10), @@ -301,7 +309,6 @@ return M staxde=M.op(0x3a,7), staxhl=M.op(0x3b,7), - 16 bits instructions: 0x48xx 0x4cxx From b04ff787d4ba00191e1453be00d5cb3d2a59d1d4 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 10 Nov 2018 17:03:38 +0100 Subject: [PATCH 14/41] Added BITx instructions. --- l7801.lua | 3 ++- samples/scv_test.l65 | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/l7801.lua b/l7801.lua index d4b5805..f5a48d1 100644 --- a/l7801.lua +++ b/l7801.lua @@ -75,7 +75,8 @@ local opcode_immediate = lookupify{ 'calf','calt','call','jmp', } local opcode_wa = lookupify{ - 'inrw','ldaw','dcrw','staw' + 'inrw','ldaw','dcrw','staw', + 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', } local opcode_relative = lookupify{ 'jr','jre' diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index edd5877..dee1774 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -95,4 +95,17 @@ section{"rom", org=0x8000} @l8 jre l9 nop nop nop nop @l9 + inrw (v,0x01) + ldaw (v,0x23) + dcrw (v,0x45) + staw (v,0x67) + bit0 (v,0x89) + bit1 (v,0xab) + bit2 (v,0xcd) + bit3 (v,0xef) + bit4 (v,0xfe) + bit5 (v,0xdc) + bit6 (v,0xba) + bit7 (v,0x98) + writebin(filename .. '.bin') \ No newline at end of file From 93ffdf28dd04ea4c0ab19fdb5dbaf3bc2c7ace2b Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 10 Nov 2018 17:15:00 +0100 Subject: [PATCH 15/41] Added DCX and INX instructions. --- l7801.lua | 2 +- samples/scv_test.l65 | 7 ++++++- uPD7801.lua | 23 ++++++++++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/l7801.lua b/l7801.lua index f5a48d1..1ca9314 100644 --- a/l7801.lua +++ b/l7801.lua @@ -104,7 +104,7 @@ local opcode_reg_list = { v = lookupify{'mvi'}, bc = lookupify{'lxi'}, de = lookupify{'lxi'}, - hl = lookupify{'lxi'}, + hl = lookupify{'dcx','inx','lxi'}, sp = lookupify{'dcx','inx','lxi'}, } diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index dee1774..e0ef9e3 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -107,5 +107,10 @@ section{"rom", org=0x8000} bit5 (v,0xdc) bit6 (v,0xba) bit7 (v,0x98) - + dcx bc + dcx de + dcx hl + inx bc + inx de + inx hl writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index a89cb3d..2ddc021 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -69,6 +69,21 @@ for k,v in pairs(opsp) do end end +local opr16={ + dcxbc=M.op(0x13,7), + dcxde=M.op(0x23,7), + dcxhl=M.op(0x33,7), + inxbc=M.op(0x12,7), + inxde=M.op(0x22,7), + inxhl=M.op(0x32,7), +} M.opr16 = opr16 +for k,v in pairs(opr16) do + M[k] = function() + table.insert(M.section_current.instructions, { size=1, cycles=v.cycles, bin=v.opc }) + end +end + + local opregxx ={ mvib=M.op(0x6a,7), mvic=M.op(0x6b,7), @@ -294,14 +309,8 @@ return M mvixbc=M.op(0x49,10), mvixde=M.op(0x4a,10), mvixhl=M.op(0x4b,10) - + - (r16) - dcxbc=M.op(0x13,7), - dcxde=M.op(0x23,7), - dcxhl=M.op(0x33,7), - inxbc=M.op(0x12,7), - inxde=M.op(0x22,7), - inxhl=M.op(0x32,7), ldaxbc=M.op(0x29,7), ldaxde=M.op(0x2a,7), ldaxhl=M.op(0x2b,7), From 09a45eaffb4b53f690a16d3171e1ab579387686e Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 10 Nov 2018 17:48:14 +0100 Subject: [PATCH 16/41] Added MVIX instruction. --- l7801.lua | 39 +++++++++++++++++++++++++++++++++++---- samples/scv_test.l65 | 4 ++++ uPD7801.lua | 13 +++++++------ 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/l7801.lua b/l7801.lua index 1ca9314..502bf25 100644 --- a/l7801.lua +++ b/l7801.lua @@ -40,7 +40,7 @@ local Keywords_data = { local Keywords_7801 = { 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcrw','dcx', - 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','lti','lxi','mov','mvi','nei','nop', + 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','lti','lxi','mov','mvi','mvix','nei','nop', 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','staw','stc','stm', 'sbi','sui','suinb','table','xri', } @@ -90,6 +90,9 @@ local opcode_reg_reg = lookupify{ local opcode_regb = lookupify{ 'aci','adi','adinc','ani','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri', } +local opcode_regb_ind = lookupify{ + 'mvix' +} local opcode_regw = lookupify{ 'lxi' } @@ -102,9 +105,9 @@ local opcode_reg_list = { h = lookupify{'mvi'}, l = lookupify{'mvi'}, v = lookupify{'mvi'}, - bc = lookupify{'lxi'}, - de = lookupify{'lxi'}, - hl = lookupify{'dcx','inx','lxi'}, + bc = lookupify{'lxi','mvix'}, + de = lookupify{'lxi','mvix'}, + hl = lookupify{'dcx','inx','lxi','mvix'}, sp = lookupify{'dcx','inx','lxi'}, } @@ -146,6 +149,7 @@ local addressing_map = { reg = opcode_reg, regb = opcode_regb, regw = opcode_regw, + regb_ind = opcode_regb_ind, } local Scope = { @@ -1453,6 +1457,33 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end + if opcode_regb_ind[op] then + if not tok:ConsumeSymbol('(', tokenList) then + return false, GenerateError("Unexpected character") + end + local register_name = tok:Get(tokenList).Data + if not Registers_7801[register_name] then + return false, GenerateError(register_name .. " is not a valid register") + end + if not (opcode_reg_list[register_name] and opcode_reg_list[register_name][op]) then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + if not tok:ConsumeSymbol(')', tokenList) + or not tok:ConsumeSymbol(',', tokenList) then + return false, GenerateError("Unexpected character") + end + 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 + if tok:ConsumeSymbol(',', tokenList) then + commaTokenList[1] = tokenList[#tokenList] + mod_st, mod_expr = ParseExpr(scope) + if not mod_st then return false, mod_expr end + end + stat = emit_call{name=op .. register_name, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + end if opcode_wa[op] then if not tok:ConsumeSymbol('(', tokenList) then return false, GenerateError("Unexpected character") diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index e0ef9e3..b4dd6af 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -113,4 +113,8 @@ section{"rom", org=0x8000} inx bc inx de inx hl + mvix (bc),0xf9 + mvix (de),0xe8 + mvix (hl),0xd7 + writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 2ddc021..b8b2bec 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -91,7 +91,10 @@ local opregxx ={ mvie=M.op(0x6d,7), mvih=M.op(0x6e,7), mvil=M.op(0x6f,7), - mviv=M.op(0x68,7) + mviv=M.op(0x68,7), + mvixbc=M.op(0x49,10), + mvixde=M.op(0x4a,10), + mvixhl=M.op(0x4b,10), } M.opregxx = opregxx for k,v in pairs(opregxx) do M[k] = function(late, early) @@ -305,11 +308,6 @@ return M staxm=M.op(0x3f,7), staxp=M.op(0x3d,7) - -- (r16),hhll - mvixbc=M.op(0x49,10), - mvixde=M.op(0x4a,10), - mvixhl=M.op(0x4b,10) - - (r16) ldaxbc=M.op(0x29,7), ldaxde=M.op(0x2a,7), @@ -318,6 +316,9 @@ return M staxde=M.op(0x3a,7), staxhl=M.op(0x3b,7), + -- (wa),xx + mviw (v,xx),xx 0x71 3 13 + 16 bits instructions: 0x48xx 0x4cxx From b9a9b9027d1afa72c62c28dbbbf77aaf52456e7b Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 10 Nov 2018 21:41:42 +0100 Subject: [PATCH 17/41] Added LDAX and STAX instructions. --- l7801.lua | 31 +++++++++++++++++++++---------- samples/scv_test.l65 | 8 +++++++- uPD7801.lua | 20 +++++++++----------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/l7801.lua b/l7801.lua index 502bf25..845653d 100644 --- a/l7801.lua +++ b/l7801.lua @@ -40,8 +40,8 @@ local Keywords_data = { local Keywords_7801 = { 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcrw','dcx', - 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','lti','lxi','mov','mvi','mvix','nei','nop', - 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','staw','stc','stm', + 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','ldax','lti','lxi','mov','mvi','mvix','nei','nop', + 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','staw','stax','stc','stm', 'sbi','sui','suinb','table','xri', } @@ -90,7 +90,11 @@ local opcode_reg_reg = lookupify{ local opcode_regb = lookupify{ 'aci','adi','adinc','ani','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri', } -local opcode_regb_ind = lookupify{ +local opcode_reg_ind = lookupify{ + 'ldax', + 'stax', +} +local opcode_reg_ind_ex = lookupify{ 'mvix' } local opcode_regw = lookupify{ @@ -105,9 +109,9 @@ local opcode_reg_list = { h = lookupify{'mvi'}, l = lookupify{'mvi'}, v = lookupify{'mvi'}, - bc = lookupify{'lxi','mvix'}, - de = lookupify{'lxi','mvix'}, - hl = lookupify{'dcx','inx','lxi','mvix'}, + bc = lookupify{'ldax','lxi','mvix','stax'}, + de = lookupify{'ldax','lxi','mvix','stax'}, + hl = lookupify{'dcx','inx','ldax','lxi','mvix','stax'}, sp = lookupify{'dcx','inx','lxi'}, } @@ -149,7 +153,8 @@ local addressing_map = { reg = opcode_reg, regb = opcode_regb, regw = opcode_regw, - regb_ind = opcode_regb_ind, + reg_ind = opcode_reg_ind, + reg_ind_ex = opcode_reg_ind_ex, } local Scope = { @@ -1457,7 +1462,7 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end - if opcode_regb_ind[op] then + if opcode_reg_ind[op] or opcode_reg_ind_ex[op] then if not tok:ConsumeSymbol('(', tokenList) then return false, GenerateError("Unexpected character") end @@ -1468,10 +1473,16 @@ local function ParseLua(src, src_name) if not (opcode_reg_list[register_name] and opcode_reg_list[register_name][op]) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - if not tok:ConsumeSymbol(')', tokenList) - or not tok:ConsumeSymbol(',', tokenList) then + if not tok:ConsumeSymbol(')', tokenList) then return false, GenerateError("Unexpected character") end + if opcode_reg_ind[op] then + stat = emit_call{name=op .. register_name} break + end + if not tok:ConsumeSymbol(',', tokenList) then + return false, GenerateError("Unexpected character") + end + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) local st, expr = ParseExpr(scope) if not st then return false, expr end local paren_open_whites = {} diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index b4dd6af..408f87b 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -116,5 +116,11 @@ section{"rom", org=0x8000} mvix (bc),0xf9 mvix (de),0xe8 mvix (hl),0xd7 - + ldax (bc) + ldax (de) + ldax (hl) + stax (bc) + stax (de) + stax (hl) + writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index b8b2bec..d41cc96 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -76,6 +76,12 @@ local opr16={ inxbc=M.op(0x12,7), inxde=M.op(0x22,7), inxhl=M.op(0x32,7), + ldaxbc=M.op(0x29,7), + ldaxde=M.op(0x2a,7), + ldaxhl=M.op(0x2b,7), + staxbc=M.op(0x39,7), + staxde=M.op(0x3a,7), + staxhl=M.op(0x3b,7), } M.opr16 = opr16 for k,v in pairs(opr16) do M[k] = function() @@ -83,7 +89,6 @@ for k,v in pairs(opr16) do end end - local opregxx ={ mvib=M.op(0x6a,7), mvic=M.op(0x6b,7), @@ -307,18 +312,11 @@ return M ldaxp=M.op(0x2d,7), staxm=M.op(0x3f,7), staxp=M.op(0x3d,7) - - - (r16) - ldaxbc=M.op(0x29,7), - ldaxde=M.op(0x2a,7), - ldaxhl=M.op(0x2b,7), - staxbc=M.op(0x39,7), - staxde=M.op(0x3a,7), - staxhl=M.op(0x3b,7), - + -- (wa),xx mviw (v,xx),xx 0x71 3 13 - + eqiw (v,xx),xx 0x75 3 13 + 16 bits instructions: 0x48xx 0x4cxx From fe3cdabf4f021d0c007c3ab3746dab835746cba5 Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 11 Nov 2018 01:04:16 +0100 Subject: [PATCH 18/41] Added MVWI and EQIW instructions. --- l7801.lua | 92 +++++++++++++++++++++++++++----------------- samples/scv_test.l65 | 2 + uPD7801.lua | 26 ++++++++++--- 3 files changed, 79 insertions(+), 41 deletions(-) diff --git a/l7801.lua b/l7801.lua index 845653d..b8520df 100644 --- a/l7801.lua +++ b/l7801.lua @@ -39,8 +39,8 @@ local Keywords_data = { } local Keywords_7801 = { 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', - 'block','calb','calf','call','calt','clc','ei','eqi','daa','di','dcr','dcrw','dcx', - 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','ldax','lti','lxi','mov','mvi','mvix','nei','nop', + 'block','calb','calf','call','calt','clc','ei','eqi','eqiw','daa','di','dcr','dcrw','dcx', + 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','ldax','lti','lxi','mov','mvi','mviw','mvix','nei','nop', 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','staw','stax','stc','stm', 'sbi','sui','suinb','table','xri', } @@ -78,6 +78,9 @@ local opcode_wa = lookupify{ 'inrw','ldaw','dcrw','staw', 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', } +local opcode_wab = lookupify{ + 'mviw','eqiw' +} local opcode_relative = lookupify{ 'jr','jre' } @@ -148,6 +151,7 @@ local opcode_reg_reg_list = { local addressing_map = { imp = opcode_implied, wa = opcode_wa, + wab = opcode_wab, imm = opcode_immediate, rel = opcode_relative, reg = opcode_reg, @@ -1449,6 +1453,15 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr}, encapsulate=false} break end + if opcode_alias[op] then op = opcode_alias[op] end + 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 + end if opcode_immediate[op] then inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) local st, expr = ParseExpr(scope) if not st then return false, expr end @@ -1466,6 +1479,10 @@ local function ParseLua(src, src_name) if not tok:ConsumeSymbol('(', tokenList) then return false, GenerateError("Unexpected character") end + + local paren_open_whites,paren_close_whites = {},{} + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end + local register_name = tok:Get(tokenList).Data if not Registers_7801[register_name] then return false, GenerateError(register_name .. " is not a valid register") @@ -1473,32 +1490,32 @@ local function ParseLua(src, src_name) if not (opcode_reg_list[register_name] and opcode_reg_list[register_name][op]) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end if not tok:ConsumeSymbol(')', tokenList) then return false, GenerateError("Unexpected character") end if opcode_reg_ind[op] then - stat = emit_call{name=op .. register_name} break + for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + stat = emit_call{name=op .. register_name, paren_open_white=paren_open_whites} break end if not tok:ConsumeSymbol(',', tokenList) then return false, GenerateError("Unexpected character") end - 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 - if tok:ConsumeSymbol(',', tokenList) then - commaTokenList[1] = tokenList[#tokenList] - mod_st, mod_expr = ParseExpr(scope) - if not mod_st then return false, mod_expr end - end - stat = emit_call{name=op .. register_name, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + if inverse_encapsulate then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + stat = emit_call{name=op .. register_name, args={expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break end - if opcode_wa[op] then + if opcode_wa[op] or opcode_wab[op] then if not tok:ConsumeSymbol('(', tokenList) then return false, GenerateError("Unexpected character") end + + local paren_open_whites,paren_close_whites = {},{} + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end + if not (tok:Get(tokenList).Data == 'v') then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end @@ -1507,53 +1524,57 @@ local function ParseLua(src, src_name) end 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 - if tok:ConsumeSymbol(',', tokenList) then - commaTokenList[1] = tokenList[#tokenList] - mod_st, mod_expr = ParseExpr(scope) - if not mod_st then return false, mod_expr end + if not tok:ConsumeSymbol(')', tokenList) then return false, expr end + if opcode_wa[op] then + for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + stat = emit_call{name=op .. "wa", args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end - if not tok:ConsumeSymbol(')', tokenList) then return false, expr + if not tok:ConsumeSymbol(',', tokenList) then + return false, GenerateError("Unexpected character") end - stat = emit_call{name=op .. "wa", args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + commaTokenList[1] = tokenList[#tokenList] + local inverse_encapsulates = { inverse_encapsulate } + local exprs = { expr } + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + inverse_encapsulates[#inverse_encapsulates+1] = inverse_encapsulate + if inverse_encapsulate then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + st, expr = ParseExpr(scope) if not st then return false, expr end + exprs[#exprs+1] = expr + stat = emit_call{name=op .. "waxx", args=exprs, inverse_encapsulate=inverse_encapsulates, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break end if opcode_reg_reg[op] then - tok:Save() local r0_name = tok:Get(tokenList).Data - if not Registers_7801[r0_name] then tok:Restore() + if not Registers_7801[r0_name] then return false, GenerateError(r0_name .. " is not a valid register") end - if not tok:ConsumeSymbol(',', tokenList) then tok:Restore() + if not tok:ConsumeSymbol(',', tokenList) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end local r1_name = tok:Get(tokenList).Data - if not Registers_7801[r1_name] then tok:Restore() + if not Registers_7801[r1_name] then return false, GenerateError(r0_name .. " is not a valid register") end if not (opcode_reg_reg_list[r0_name] and opcode_reg_reg_list[r0_name][r1_name] and opcode_reg_reg_list[r0_name][r1_name][op]) then - tok:Restore() return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - tok:Commit() stat = emit_call{name=op .. r0_name .. r1_name} break elseif opcode_reg[op] or opcode_regb[op] or opcode_regw[op] then - tok:Save() local register_name = tok:Get(tokenList).Data local call_args = {name=op..register_name} - if not Registers_7801[register_name] then tok:Restore() + if not Registers_7801[register_name] then return false, GenerateError(register_name .. " is not a valid register") end - if not opcode_reg_list[register_name] and opcode_reg_list[register_name][op] then tok:Restore() + if not opcode_reg_list[register_name] and opcode_reg_list[register_name][op] then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end if opcode_regw[op] or opcode_regb[op] then - if not tok:ConsumeSymbol(',', tokenList) then tok:Restore() + if not tok:ConsumeSymbol(',', tokenList) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end local inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) - local st, expr = ParseExpr(scope) if not st then tok:Restore() + local st, expr = ParseExpr(scope) if not st then return false, expr end local paren_open_whites = {} @@ -1562,7 +1583,7 @@ local function ParseLua(src, src_name) if tok:ConsumeSymbol(',', tokenList) then commaTokenList[1] = tokenList[#tokenList] mod_st, mod_expr = ParseExpr(scope) - if not mod_st then tok:Restore() + if not mod_st then return false, mod_expr end end @@ -1570,7 +1591,6 @@ local function ParseLua(src, src_name) call_args.inverse_encapsulate=inverse_encapsulate call_args.paren_open_white=paren_open_whites end - tok:Commit() stat = emit_call(call_args) break end if opcode_implied[op] then stat = emit_call{name=op .. 'imp'} break end diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 408f87b..8ddcb55 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -122,5 +122,7 @@ section{"rom", org=0x8000} stax (bc) stax (de) stax (hl) + mviw (v,0x9a),0x3f + eqiw (v,0xc5),0x1b writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index d41cc96..3502e73 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -280,6 +280,26 @@ for k,v in pairs(opwa) do end end +local opwaxx = { + mviw=M.op(0x71,3,13), + eqiw=M.op(0x75,3,13), +} M.opwaxx = opwaxx +for k,v in pairs(opwaxx) do + M[k .. 'waxx'] = function(late_offset, late_data, early_offset, early_data) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() + late_offset,early_offset = M.size_op(late_offset,early_offset) + late_data,early_data = M.size_op(late_data,early_data) + return 3 + end + local bin = function() + local l65dbg=l65dbg + return { v.opc, M.op_eval_byte(late_offset,early_offset), M.op_eval_byte(late_data,early_data) } + end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + local op48imp = { ei=M.op(0x20,8), di=M.op(0x24,8), @@ -312,11 +332,7 @@ return M ldaxp=M.op(0x2d,7), staxm=M.op(0x3f,7), staxp=M.op(0x3d,7) - - -- (wa),xx - mviw (v,xx),xx 0x71 3 13 - eqiw (v,xx),xx 0x75 3 13 - + 16 bits instructions: 0x48xx 0x4cxx From 77b69902c29b4c7eed6eb0124b1012608c94288a Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 11 Nov 2018 15:54:56 +0100 Subject: [PATCH 19/41] Added LDAX+, LDAX-, STAX+ and STAX- (renamed ldaxi, ldaxd, staxi, staxd). --- l7801.lua | 26 +++++++++++++++----------- samples/scv_test.l65 | 10 +++++++++- uPD7801.lua | 20 ++++++++------------ 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/l7801.lua b/l7801.lua index b8520df..6a96c81 100644 --- a/l7801.lua +++ b/l7801.lua @@ -38,11 +38,16 @@ local Keywords_data = { 'dc', } local Keywords_7801 = { - 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', - 'block','calb','calf','call','calt','clc','ei','eqi','eqiw','daa','di','dcr','dcrw','dcx', - 'ex','exx','gti','halt','inr','inrw','inx','jb','jmp','jr','jre','ldaw','ldax','lti','lxi','mov','mvi','mviw','mvix','nei','nop', - 'offi','oni','ori','pen','per','pex','ret','reti','rets','rld','rrd','sio','softi','staw','stax','stc','stm', - 'sbi','sui','suinb','table','xri', + 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3', + 'bit4','bit5','bit6','bit7','block','calb','calf','call', + 'calt','clc','ei','eqi','eqiw','daa','di','dcr', + 'dcrw','dcx','ex','exx','gti','halt','inr','inrw', + 'inx','jb','jmp','jr','jre','ldaw','ldax','ldaxd', + 'ldaxi','lti','lxi','mov','mvi','mviw','mvix','nei', + 'nop','offi','oni','ori','pen','per','pex','ret', + 'reti','rets','rld','rrd','sio','softi','staw','stax', + 'staxd','staxi','stc','stm','sbi','sui','suinb','table', + 'xri', } local Registers_7801 = { @@ -94,8 +99,8 @@ local opcode_regb = lookupify{ 'aci','adi','adinc','ani','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri', } local opcode_reg_ind = lookupify{ - 'ldax', - 'stax', + 'ldax','ldaxd','ldaxi', + 'stax','staxd','staxi', } local opcode_reg_ind_ex = lookupify{ 'mvix' @@ -113,8 +118,8 @@ local opcode_reg_list = { l = lookupify{'mvi'}, v = lookupify{'mvi'}, bc = lookupify{'ldax','lxi','mvix','stax'}, - de = lookupify{'ldax','lxi','mvix','stax'}, - hl = lookupify{'dcx','inx','ldax','lxi','mvix','stax'}, + de = lookupify{'ldax','ldaxd','ldaxi','lxi','mvix','stax','staxd','staxi'}, + hl = lookupify{'dcx','inx','ldax','ldaxd','ldaxi','lxi','mvix','stax','staxd','staxi'}, sp = lookupify{'dcx','inx','lxi'}, } @@ -1490,14 +1495,13 @@ local function ParseLua(src, src_name) if not (opcode_reg_list[register_name] and opcode_reg_list[register_name][op]) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end if not tok:ConsumeSymbol(')', tokenList) then return false, GenerateError("Unexpected character") end if opcode_reg_ind[op] then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end - stat = emit_call{name=op .. register_name, paren_open_white=paren_open_whites} break + stat = emit_call{name=op .. register_name, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break end if not tok:ConsumeSymbol(',', tokenList) then return false, GenerateError("Unexpected character") diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 8ddcb55..4ce2009 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -124,5 +124,13 @@ section{"rom", org=0x8000} stax (hl) mviw (v,0x9a),0x3f eqiw (v,0xc5),0x1b - + ldaxd (de) + ldaxi (de) + ldaxd (hl) + ldaxi (hl) + staxd (de) + staxi (de) + staxd (hl) + staxi (hl) + writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 3502e73..88a027e 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -77,11 +77,19 @@ local opr16={ inxde=M.op(0x22,7), inxhl=M.op(0x32,7), ldaxbc=M.op(0x29,7), + ldaxdde=M.op(0x2e,7), ldaxde=M.op(0x2a,7), ldaxhl=M.op(0x2b,7), + ldaxide=M.op(0x2c,7), + ldaxdhl=M.op(0x2f,7), + ldaxihl=M.op(0x2d,7), staxbc=M.op(0x39,7), staxde=M.op(0x3a,7), + staxdde=M.op(0x3e,7), + staxdhl=M.op(0x3f,7), staxhl=M.op(0x3b,7), + staxide=M.op(0x3c,7), + staxihl=M.op(0x3d,7), } M.opr16 = opr16 for k,v in pairs(opr16) do M[k] = function() @@ -320,18 +328,6 @@ end return M --[[ [todo] -8 bits instructions: - -- d - ldaxm=M.op(0x2e,7), - ldaxp=M.op(0x2c,7), - staxm=M.op(0x3e,7), - staxp=M.op(0x3c,7) - - -- h - ldaxm=M.op(0x2f,7), - ldaxp=M.op(0x2d,7), - staxm=M.op(0x3f,7), - staxp=M.op(0x3d,7) 16 bits instructions: 0x48xx From 636b5297c10c9261fb485a9ac9d56305f15751c4 Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 11 Nov 2018 22:26:30 +0100 Subject: [PATCH 20/41] Added PUSH and POP. --- l7801.lua | 114 ++++++++++++++++++++----------------------- samples/scv_test.l65 | 21 +++++--- uPD7801.lua | 74 ++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 68 deletions(-) diff --git a/l7801.lua b/l7801.lua index 6a96c81..7172b8e 100644 --- a/l7801.lua +++ b/l7801.lua @@ -44,7 +44,7 @@ local Keywords_7801 = { 'dcrw','dcx','ex','exx','gti','halt','inr','inrw', 'inx','jb','jmp','jr','jre','ldaw','ldax','ldaxd', 'ldaxi','lti','lxi','mov','mvi','mviw','mvix','nei', - 'nop','offi','oni','ori','pen','per','pex','ret', + 'nop','offi','oni','ori','pen','per','pex','pop','push','ret', 'reti','rets','rld','rrd','sio','softi','staw','stax', 'staxd','staxi','stc','stm','sbi','sui','suinb','table', 'xri', @@ -90,7 +90,7 @@ local opcode_relative = lookupify{ 'jr','jre' } local opcode_reg = lookupify{ - 'dcr','dcx','inr','inx' + 'dcr','dcx','inr','inx','pop','push', } local opcode_reg_reg = lookupify{ 'mov' @@ -116,10 +116,12 @@ local opcode_reg_list = { e = lookupify{'mvi'}, h = lookupify{'mvi'}, l = lookupify{'mvi'}, - v = lookupify{'mvi'}, - bc = lookupify{'ldax','lxi','mvix','stax'}, - de = lookupify{'ldax','ldaxd','ldaxi','lxi','mvix','stax','staxd','staxi'}, - hl = lookupify{'dcx','inx','ldax','ldaxd','ldaxi','lxi','mvix','stax','staxd','staxi'}, + v = lookupify{'inrw','ldaw','dcrw','eqiw','mvi','mviw','pop','push','staw', + 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', + }, + bc = lookupify{'ldax','lxi','mvix','pop','push','stax'}, + de = lookupify{'ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, + hl = lookupify{'dcx','inx','ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, sp = lookupify{'dcx','inx','lxi'}, } @@ -1480,14 +1482,11 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end - if opcode_reg_ind[op] or opcode_reg_ind_ex[op] then - if not tok:ConsumeSymbol('(', tokenList) then - return false, GenerateError("Unexpected character") - end - + + if (opcode_wa[op] or opcode_wab[op] or opcode_reg_ind[op] or opcode_reg_ind_ex[op]) and tok:ConsumeSymbol('(', tokenList) then local paren_open_whites,paren_close_whites = {},{} for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end - + local register_name = tok:Get(tokenList).Data if not Registers_7801[register_name] then return false, GenerateError(register_name .. " is not a valid register") @@ -1495,58 +1494,51 @@ local function ParseLua(src, src_name) if not (opcode_reg_list[register_name] and opcode_reg_list[register_name][op]) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - if not tok:ConsumeSymbol(')', tokenList) then - return false, GenerateError("Unexpected character") - end - if opcode_reg_ind[op] then - for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end + + if (opcode_wa[op] or opcode_wab[op]) and tok:ConsumeSymbol(',', tokenList) then + if not (register_name == 'v') + or not (opcode_wa[op] or opcode_wab[op]) then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) if not st then return false, expr end + if not tok:ConsumeSymbol(')', tokenList) then + return false, GenerateError("Unexpected character") + end + if opcode_wa[op] then + for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + stat = emit_call{name=op .. "wa", args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + end + if not tok:ConsumeSymbol(',', tokenList) then + return false, GenerateError("Unexpected character") + end + commaTokenList[1] = tokenList[#tokenList] + local inverse_encapsulates = { inverse_encapsulate } + local exprs = { expr } + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + inverse_encapsulates[#inverse_encapsulates+1] = inverse_encapsulate + if inverse_encapsulate then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end end for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end - stat = emit_call{name=op .. register_name, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break + st, expr = ParseExpr(scope) if not st then return false, expr end + exprs[#exprs+1] = expr + stat = emit_call{name=op .. "waxx", args=exprs, inverse_encapsulate=inverse_encapsulates, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break end - if not tok:ConsumeSymbol(',', tokenList) then - return false, GenerateError("Unexpected character") + if (opcode_reg_ind[op] or opcode_reg_ind_ex[op]) and tok:ConsumeSymbol(')', tokenList) then + if opcode_reg_ind[op] then + for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + stat = emit_call{name=op .. register_name, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break + end + if opcode_reg_ind_ex[op] and tok:ConsumeSymbol(',', tokenList) then + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) if not st then return false, expr end + if inverse_encapsulate then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + stat = emit_call{name=op .. register_name, args={expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break + end + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) - local st, expr = ParseExpr(scope) if not st then return false, expr end - if inverse_encapsulate then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end end - for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end - stat = emit_call{name=op .. register_name, args={expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break - end - if opcode_wa[op] or opcode_wab[op] then - if not tok:ConsumeSymbol('(', tokenList) then - return false, GenerateError("Unexpected character") - end - - local paren_open_whites,paren_close_whites = {},{} - for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end - - if not (tok:Get(tokenList).Data == 'v') then - return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") - end - if not tok:ConsumeSymbol(',', tokenList) then - return false, GenerateError("Unexpected character") - end - inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) - local st, expr = ParseExpr(scope) if not st then return false, expr end - if not tok:ConsumeSymbol(')', tokenList) then return false, expr end - if opcode_wa[op] then - for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end - for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end - stat = emit_call{name=op .. "wa", args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break - end - if not tok:ConsumeSymbol(',', tokenList) then - return false, GenerateError("Unexpected character") - end - commaTokenList[1] = tokenList[#tokenList] - local inverse_encapsulates = { inverse_encapsulate } - local exprs = { expr } - inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) - inverse_encapsulates[#inverse_encapsulates+1] = inverse_encapsulate - if inverse_encapsulate then for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end end - for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end - st, expr = ParseExpr(scope) if not st then return false, expr end - exprs[#exprs+1] = expr - stat = emit_call{name=op .. "waxx", args=exprs, inverse_encapsulate=inverse_encapsulates, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break end if opcode_reg_reg[op] then local r0_name = tok:Get(tokenList).Data diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 4ce2009..adadbfc 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -95,6 +95,12 @@ section{"rom", org=0x8000} @l8 jre l9 nop nop nop nop @l9 + ldax (bc) + ldax (de) + ldax (hl) + stax (bc) + stax (de) + stax (hl) inrw (v,0x01) ldaw (v,0x23) dcrw (v,0x45) @@ -116,12 +122,6 @@ section{"rom", org=0x8000} mvix (bc),0xf9 mvix (de),0xe8 mvix (hl),0xd7 - ldax (bc) - ldax (de) - ldax (hl) - stax (bc) - stax (de) - stax (hl) mviw (v,0x9a),0x3f eqiw (v,0xc5),0x1b ldaxd (de) @@ -132,5 +132,12 @@ section{"rom", org=0x8000} staxi (de) staxd (hl) staxi (hl) - + push bc + push de + push hl + pop hl + pop de + pop bc + push v + pop v writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 88a027e..048f1c7 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -325,12 +325,86 @@ for k,v in pairs(op48imp) do end end +local op48r16={ + pushbc=M.op(0x1e,17), + pushde=M.op(0x2e,17), + pushhl=M.op(0x3e,17), + pushv=M.op(0x0e,17), + popbc=M.op(0x1f,15), + popde=M.op(0x2f,15), + pophl=M.op(0x3f,15), + popv=M.op(0x0f,15), +} M.op48r16 = op48r16 +for k,v in pairs(op48r16) do + M[k] = function() + table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x48, v.opc } }) + end +end + return M --[[ [todo] 16 bits instructions: 0x48xx + case 0x00: my_stprintf_s(buffer, buffer_len, _T("skit intf0")); break; + case 0x01: my_stprintf_s(buffer, buffer_len, _T("skit intft")); break; + case 0x02: my_stprintf_s(buffer, buffer_len, _T("skit intf1")); break; + case 0x03: my_stprintf_s(buffer, buffer_len, _T("skit intf2")); break; + case 0x04: my_stprintf_s(buffer, buffer_len, _T("skit intfs")); break; + case 0x0a: my_stprintf_s(buffer, buffer_len, _T("sk cy")); break; + case 0x0c: my_stprintf_s(buffer, buffer_len, _T("sk z")); break; + case 0x10: my_stprintf_s(buffer, buffer_len, _T("sknit f0")); break; + case 0x11: my_stprintf_s(buffer, buffer_len, _T("sknit ft")); break; + case 0x12: my_stprintf_s(buffer, buffer_len, _T("sknit f1")); break; + case 0x13: my_stprintf_s(buffer, buffer_len, _T("sknit f2")); break; + case 0x14: my_stprintf_s(buffer, buffer_len, _T("sknit fs")); break; + case 0x1a: my_stprintf_s(buffer, buffer_len, _T("skn cy")); break; + case 0x1c: my_stprintf_s(buffer, buffer_len, _T("skn z")); break; + case 0x30: my_stprintf_s(buffer, buffer_len, _T("rll a")); break; + case 0x31: my_stprintf_s(buffer, buffer_len, _T("rlr a")); break; + case 0x32: my_stprintf_s(buffer, buffer_len, _T("rll c")); break; + case 0x33: my_stprintf_s(buffer, buffer_len, _T("rlr c")); break; + case 0x34: my_stprintf_s(buffer, buffer_len, _T("sll a")); break; + case 0x35: my_stprintf_s(buffer, buffer_len, _T("slr a")); break; + case 0x36: my_stprintf_s(buffer, buffer_len, _T("sll c")); break; + case 0x37: my_stprintf_s(buffer, buffer_len, _T("sll c")); break; + + {&upd7810_device::SKIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKIT_FT0, 2, 8, 8,L0|L1}, + {&upd7810_device::SKIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::SKIT_F2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SK_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SK_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + {&upd7810_device::SKNIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKNIT_FT0, 2, 8, 8,L0|L1}, + {&upd7810_device::SKNIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::SKNIT_F2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKNIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal, 2, 8, 8,L0|L1}, + {&upd7810_device::SKN_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::SKN_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + /* 0x20 - 0x3F */ + {&upd7810_device::EI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::DI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::CLC, 2, 8, 8,L0|L1}, {&upd7810_device::STC, 2, 8, 8,L0|L1}, + {&upd7810_device::PEN, 2,11,11,L0|L1}, {&upd7810_device::PEX, 2,11,11,L0|L1}, + + {&upd7810_device::RLL_A, 2, 8, 8,L0|L1}, {&upd7810_device::RLR_A, 2, 8, 8,L0|L1}, + {&upd7810_device::RLL_C, 2, 8, 8,L0|L1}, {&upd7810_device::RLR_C, 2, 8, 8,L0|L1}, + {&upd7810_device::SLL_A, 2, 8, 8,L0|L1}, {&upd7810_device::SLR_A, 2, 8, 8,L0|L1}, + {&upd7810_device::SLL_C, 2, 8, 8,L0|L1}, {&upd7810_device::SLR_C, 2, 8, 8,L0|L1}, + {&upd7810_device::RLD, 2,17,17,L0|L1}, {&upd7810_device::RRD, 2,17,17,L0|L1}, + {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + {&upd7810_device::PER, 2,11,11,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, + + + 0x4cxx 0x4dxx 0x60xx From 711fe67574f899710e768c00436866546ba5b81b Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 11 Nov 2018 22:29:06 +0100 Subject: [PATCH 21/41] PUSH V and POP V were changed to PUSH VA and POP VA. --- l7801.lua | 5 +++-- samples/scv_test.l65 | 4 ++-- uPD7801.lua | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/l7801.lua b/l7801.lua index 7172b8e..9a21fb8 100644 --- a/l7801.lua +++ b/l7801.lua @@ -52,7 +52,7 @@ local Keywords_7801 = { local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, - bc=16,de=16,hl=16,sp=16 + bc=16,de=16,hl=16,sp=16,va=16 } local function syntax7801(on) @@ -116,13 +116,14 @@ local opcode_reg_list = { e = lookupify{'mvi'}, h = lookupify{'mvi'}, l = lookupify{'mvi'}, - v = lookupify{'inrw','ldaw','dcrw','eqiw','mvi','mviw','pop','push','staw', + v = lookupify{'inrw','ldaw','dcrw','eqiw','mvi','mviw','staw', 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', }, bc = lookupify{'ldax','lxi','mvix','pop','push','stax'}, de = lookupify{'ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, hl = lookupify{'dcx','inx','ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, sp = lookupify{'dcx','inx','lxi'}, + va = lookupify{'pop','push'}, } local opcode_reg_reg_list = { diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index adadbfc..1cb1c51 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -138,6 +138,6 @@ section{"rom", org=0x8000} pop hl pop de pop bc - push v - pop v + push va + pop va writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 048f1c7..7d1e154 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -329,11 +329,11 @@ local op48r16={ pushbc=M.op(0x1e,17), pushde=M.op(0x2e,17), pushhl=M.op(0x3e,17), - pushv=M.op(0x0e,17), + pushva=M.op(0x0e,17), popbc=M.op(0x1f,15), popde=M.op(0x2f,15), pophl=M.op(0x3f,15), - popv=M.op(0x0f,15), + popva=M.op(0x0f,15), } M.op48r16 = op48r16 for k,v in pairs(op48r16) do M[k] = function() From 283c4256f500eba6065be8f11ecb9a2187436222 Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 11 Nov 2018 23:31:52 +0100 Subject: [PATCH 22/41] Added SKIT, SKNIT, RLL, RLR, SKC, SKZ, SKNC and SKNZ. --- l7801.lua | 36 +++++++++++----- samples/scv_test.l65 | 23 +++++++++++ uPD7801.lua | 97 +++++++++++++++++--------------------------- 3 files changed, 86 insertions(+), 70 deletions(-) diff --git a/l7801.lua b/l7801.lua index 9a21fb8..dcf9988 100644 --- a/l7801.lua +++ b/l7801.lua @@ -45,15 +45,18 @@ local Keywords_7801 = { 'inx','jb','jmp','jr','jre','ldaw','ldax','ldaxd', 'ldaxi','lti','lxi','mov','mvi','mviw','mvix','nei', 'nop','offi','oni','ori','pen','per','pex','pop','push','ret', - 'reti','rets','rld','rrd','sio','softi','staw','stax', - 'staxd','staxi','stc','stm','sbi','sui','suinb','table', - 'xri', + 'reti','rets','rld','rll','rlr','rrd','sbi','sio','skc', + 'skit','sknit','skz','sknc','sknz','sll','slr','softi', + 'staw','stax','staxd','staxi','stc','stm','sui','suinb', + 'table','xri', } - local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, bc=16,de=16,hl=16,sp=16,va=16 } +local Interrupts_7801 = lookupify{ + 'f0','ft','f1','f2','fs' +} local function syntax7801(on) syntax7801_on = on @@ -73,9 +76,9 @@ local opcode_encapsulate = {} -- additionnal opcode, to have basic encapsulation local opcode_alias = {} -- alternate user names for opcodes local opcode_implied = lookupify{ 'block','calb','clc','ei','daa','dcr','di','ex','exx','halt','inr','jb','nop','pen', - 'per','pex','ret','reti','rets','rld','rrd','sio','softi','stc','stm','table' + 'per','pex','ret','reti','rets','rld','rrd','sio','skc','skz','sknc','sknz','softi', + 'stc','stm','table' } - local opcode_immediate = lookupify{ 'calf','calt','call','jmp', } @@ -90,7 +93,7 @@ local opcode_relative = lookupify{ 'jr','jre' } local opcode_reg = lookupify{ - 'dcr','dcx','inr','inx','pop','push', + 'dcr','dcx','inr','inx','pop','push','rll','rlr','sll','slr', } local opcode_reg_reg = lookupify{ 'mov' @@ -108,10 +111,13 @@ local opcode_reg_ind_ex = lookupify{ local opcode_regw = lookupify{ 'lxi' } +local opcode_timer = lookupify{ + 'skit','sknit', +} local opcode_reg_list = { - a = lookupify{'aci','adi','adinc','ani','dcr','inr','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri'}, + a = lookupify{'aci','adi','adinc','ani','dcr','inr','eqi','gti','lti','mvi','nei','offi','oni','ori','rll','rlr','sbi','sll','slr','sui','suinb','xri'}, b = lookupify{'dcr','inr','mvi'}, - c = lookupify{'dcr','inr','mvi'}, + c = lookupify{'dcr','inr','mvi','rll','rlr','sll','slr'}, d = lookupify{'mvi'}, e = lookupify{'mvi'}, h = lookupify{'mvi'}, @@ -167,6 +173,7 @@ local addressing_map = { regw = opcode_regw, reg_ind = opcode_reg_ind, reg_ind_ex = opcode_reg_ind_ex, + timer=opcode_timer, } local Scope = { @@ -1483,7 +1490,6 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end - if (opcode_wa[op] or opcode_wab[op] or opcode_reg_ind[op] or opcode_reg_ind_ex[op]) and tok:ConsumeSymbol('(', tokenList) then local paren_open_whites,paren_close_whites = {},{} for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end @@ -1557,7 +1563,8 @@ local function ParseLua(src, src_name) return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end stat = emit_call{name=op .. r0_name .. r1_name} break - elseif opcode_reg[op] or opcode_regb[op] or opcode_regw[op] then + end + if opcode_reg[op] or opcode_regb[op] or opcode_regw[op] then local register_name = tok:Get(tokenList).Data local call_args = {name=op..register_name} if not Registers_7801[register_name] then @@ -1590,6 +1597,13 @@ local function ParseLua(src, src_name) end stat = emit_call(call_args) break end + if opcode_timer[op] then + local timer_name = tok:Get(tokenList).Data + if not Interrupts_7801[timer_name] then + return false, GenerateError(timer_name .. " is not a valid interrupt name") + end + stat = emit_call{name=op .. timer_name} break + end if opcode_implied[op] then stat = emit_call{name=op .. 'imp'} break end error("internal error: unable to find addressing of valid opcode " .. op) -- should not happen end diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 1cb1c51..1eba337 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -140,4 +140,27 @@ section{"rom", org=0x8000} pop bc push va pop va + rll a + rlr a + rll c + rlr c + sll a + slr a + sll c + slr c + skc + skz + sknc + sknz + skit f0 + skit ft + skit f1 + skit f2 + skit fs + sknit f0 + sknit ft + sknit f1 + sknit f2 + sknit fs + writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 7d1e154..f0274b1 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -317,6 +317,10 @@ local op48imp = { pex=M.op(0x2d,11), rld=M.op(0x38,17), rrd=M.op(0x39,17), + skc=M.op(0x0a,8), + skz=M.op(0x0c,8), + sknc=M.op(0x1a,8), + sknz=M.op(0x1c,8), stc=M.op(0x2b,8), } M.op48imp = op48imp for k,v in pairs(op48imp) do @@ -325,6 +329,22 @@ for k,v in pairs(op48imp) do end end +local op48r8={ + rlla=M.op(0x30,8), + rlra=M.op(0x31,8), + rllc=M.op(0x32,8), + rlrc=M.op(0x33,8), + slla=M.op(0x34,8), + slra=M.op(0x35,8), + sllc=M.op(0x36,8), + slrc=M.op(0x37,8), +} M.op48r8 = op48r8 +for k,v in pairs(op48r8) do + M[k] = function() + table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x48, v.opc } }) + end +end + local op48r16={ pushbc=M.op(0x1e,17), pushde=M.op(0x2e,17), @@ -341,70 +361,29 @@ for k,v in pairs(op48r16) do end end +local op48int={ + skitf0=M.op(0x00,8), + skitft=M.op(0x01,8), + skitf1=M.op(0x02,8), + skitf2=M.op(0x03,8), + skitfs=M.op(0x04,8), + sknitf0=M.op(0x10,8), + sknitft=M.op(0x11,8), + sknitf1=M.op(0x12,8), + sknitf2=M.op(0x13,8), + sknitfs=M.op(0x14,8), +} M.op48int = op48int +for k,v in pairs(op48int) do + M[k] = function() + table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x48, v.opc } }) + end +end + return M --[[ [todo] 16 bits instructions: - 0x48xx - case 0x00: my_stprintf_s(buffer, buffer_len, _T("skit intf0")); break; - case 0x01: my_stprintf_s(buffer, buffer_len, _T("skit intft")); break; - case 0x02: my_stprintf_s(buffer, buffer_len, _T("skit intf1")); break; - case 0x03: my_stprintf_s(buffer, buffer_len, _T("skit intf2")); break; - case 0x04: my_stprintf_s(buffer, buffer_len, _T("skit intfs")); break; - case 0x0a: my_stprintf_s(buffer, buffer_len, _T("sk cy")); break; - case 0x0c: my_stprintf_s(buffer, buffer_len, _T("sk z")); break; - case 0x10: my_stprintf_s(buffer, buffer_len, _T("sknit f0")); break; - case 0x11: my_stprintf_s(buffer, buffer_len, _T("sknit ft")); break; - case 0x12: my_stprintf_s(buffer, buffer_len, _T("sknit f1")); break; - case 0x13: my_stprintf_s(buffer, buffer_len, _T("sknit f2")); break; - case 0x14: my_stprintf_s(buffer, buffer_len, _T("sknit fs")); break; - case 0x1a: my_stprintf_s(buffer, buffer_len, _T("skn cy")); break; - case 0x1c: my_stprintf_s(buffer, buffer_len, _T("skn z")); break; - case 0x30: my_stprintf_s(buffer, buffer_len, _T("rll a")); break; - case 0x31: my_stprintf_s(buffer, buffer_len, _T("rlr a")); break; - case 0x32: my_stprintf_s(buffer, buffer_len, _T("rll c")); break; - case 0x33: my_stprintf_s(buffer, buffer_len, _T("rlr c")); break; - case 0x34: my_stprintf_s(buffer, buffer_len, _T("sll a")); break; - case 0x35: my_stprintf_s(buffer, buffer_len, _T("slr a")); break; - case 0x36: my_stprintf_s(buffer, buffer_len, _T("sll c")); break; - case 0x37: my_stprintf_s(buffer, buffer_len, _T("sll c")); break; - - {&upd7810_device::SKIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKIT_FT0, 2, 8, 8,L0|L1}, - {&upd7810_device::SKIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::SKIT_F2, 2, 8, 8,L0|L1}, - {&upd7810_device::SKIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::SK_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::SK_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - - {&upd7810_device::SKNIT_F0, 2, 8, 8,L0|L1}, {&upd7810_device::SKNIT_FT0, 2, 8, 8,L0|L1}, - {&upd7810_device::SKNIT_F1, 2, 8, 8,L0|L1}, {&upd7810_device::SKNIT_F2, 2, 8, 8,L0|L1}, - {&upd7810_device::SKNIT_FST, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal, 2, 8, 8,L0|L1}, - {&upd7810_device::SKN_CY, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::SKN_Z, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - - /* 0x20 - 0x3F */ - {&upd7810_device::EI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::DI, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::CLC, 2, 8, 8,L0|L1}, {&upd7810_device::STC, 2, 8, 8,L0|L1}, - {&upd7810_device::PEN, 2,11,11,L0|L1}, {&upd7810_device::PEX, 2,11,11,L0|L1}, - - {&upd7810_device::RLL_A, 2, 8, 8,L0|L1}, {&upd7810_device::RLR_A, 2, 8, 8,L0|L1}, - {&upd7810_device::RLL_C, 2, 8, 8,L0|L1}, {&upd7810_device::RLR_C, 2, 8, 8,L0|L1}, - {&upd7810_device::SLL_A, 2, 8, 8,L0|L1}, {&upd7810_device::SLR_A, 2, 8, 8,L0|L1}, - {&upd7810_device::SLL_C, 2, 8, 8,L0|L1}, {&upd7810_device::SLR_C, 2, 8, 8,L0|L1}, - {&upd7810_device::RLD, 2,17,17,L0|L1}, {&upd7810_device::RRD, 2,17,17,L0|L1}, - {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - {&upd7810_device::PER, 2,11,11,L0|L1}, {&upd7810_device::illegal2, 2, 8, 8,L0|L1}, - - - 0x4cxx 0x4dxx 0x60xx From c09a04964ad11425046852634c22a0166cd0a5ae Mon Sep 17 00:00:00 2001 From: mooz Date: Mon, 12 Nov 2018 23:27:09 +0100 Subject: [PATCH 23/41] Added IN and OUT instructions. --- l7801.lua | 8 ++++---- samples/scv_test.l65 | 8 +++++++- uPD7801.lua | 41 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/l7801.lua b/l7801.lua index dcf9988..677a6a1 100644 --- a/l7801.lua +++ b/l7801.lua @@ -41,10 +41,10 @@ local Keywords_7801 = { 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3', 'bit4','bit5','bit6','bit7','block','calb','calf','call', 'calt','clc','ei','eqi','eqiw','daa','di','dcr', - 'dcrw','dcx','ex','exx','gti','halt','inr','inrw', + 'dcrw','dcx','ex','exx','gti','halt','in','inr','inrw', 'inx','jb','jmp','jr','jre','ldaw','ldax','ldaxd', 'ldaxi','lti','lxi','mov','mvi','mviw','mvix','nei', - 'nop','offi','oni','ori','pen','per','pex','pop','push','ret', + 'nop','offi','oni','ori','out','pen','per','pex','pop','push','ret', 'reti','rets','rld','rll','rlr','rrd','sbi','sio','skc', 'skit','sknit','skz','sknc','sknz','sll','slr','softi', 'staw','stax','staxd','staxi','stc','stm','sui','suinb', @@ -80,7 +80,7 @@ local opcode_implied = lookupify{ 'stc','stm','table' } local opcode_immediate = lookupify{ - 'calf','calt','call','jmp', + 'calf','calt','call','in','jmp','out', } local opcode_wa = lookupify{ 'inrw','ldaw','dcrw','staw', @@ -1488,7 +1488,7 @@ local function ParseLua(src, src_name) mod_st, mod_expr = ParseExpr(scope) if not mod_st then return false, mod_expr end end - stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + stat = emit_call{name=op .. 'imm', args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end if (opcode_wa[op] or opcode_wab[op] or opcode_reg_ind[op] or opcode_reg_ind_ex[op]) and tok:ConsumeSymbol('(', tokenList) then local paren_open_whites,paren_close_whites = {},{} diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 1eba337..507573b 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -162,5 +162,11 @@ section{"rom", org=0x8000} sknit f1 sknit f2 sknit fs - + in 0x00 + in 0xa7 + in 0xbf + out 0x00 + out 0x5a + out 0xbf + writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index f0274b1..09624df 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -162,12 +162,26 @@ end local opw = { call=M.op(0x44,16), jmp=M.op(0x54,10), +} M.opw = opw +for k,v in pairs(opw) do + M[k .. 'imm'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 3 end + local bin = function() local l65dbg=l65dbg + local x = M.op_eval_word(late,early) + return { v.opc, x&0xff, x>>8 } + end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + +local opr16w = { lxisp=M.op(0x04,10), lxibc=M.op(0x14,10), lxide=M.op(0x24,10), lxihl=M.op(0x34,10) -} M.opw = opw -for k,v in pairs(opw) do +} M.opr16w = opr16w +for k,v in pairs(opr16w) do M[k] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 3 end @@ -179,7 +193,8 @@ for k,v in pairs(opw) do end end -M.calt = function(late, early) + +M['calt' .. 'imm'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local op = { cycles=19 } op.size = function() late,early = M.size_op(late,early) return 1 end @@ -194,7 +209,7 @@ M.calt = function(late, early) table.insert(M.section_current.instructions, op) end -M.calf = function(late, early) +M['calf' .. 'imm'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local op = { cycles=16 } op.size = function() late,early = M.size_op(late,early) return 2 end @@ -379,6 +394,24 @@ for k,v in pairs(op48int) do end end +-- IN/OUT +local opinout={ + ['in']=M.op(0x4c,10), + out=M.op(0x4d,10), +} M.opinout = op4inout +for k,v in pairs(opinout) do + M[k .. 'imm'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local op = { cycles=v.cycles } + op.size = function() late,early = M.size_op(late,early) return 2 end + op.bin = function() local l65dbg=l65dbg + local x = 0x00 + M.op_eval_byte(late,early) + return { v.opc, 0x00, x } + end + table.insert(M.section_current.instructions, op) + end +end + return M --[[ [todo] From 0d66e70a6924a8114fae2b0bb89f77e8c78cba1a Mon Sep 17 00:00:00 2001 From: mooz Date: Thu, 15 Nov 2018 19:25:57 +0100 Subject: [PATCH 24/41] Added 0x4Cxx MOV instructions. --- l7801.lua | 12 +++++++++++- samples/scv_hello.l65 | 20 ++++++++++---------- samples/scv_test.l65 | 9 +++++++++ uPD7801.lua | 20 ++++++++++++++++++++ 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/l7801.lua b/l7801.lua index 677a6a1..cce6ffe 100644 --- a/l7801.lua +++ b/l7801.lua @@ -52,7 +52,8 @@ local Keywords_7801 = { } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, - bc=16,de=16,hl=16,sp=16,va=16 + bc=16,de=16,hl=16,sp=16,va=16, + pa=8,pb=8,pc=8,mk=8,mb=8,mc=8,tm0=8,tm1=8,s=8, } local Interrupts_7801 = lookupify{ 'f0','ft','f1','f2','fs' @@ -140,6 +141,15 @@ local opcode_reg_reg_list = { e = lookupify{'mov'}, h = lookupify{'mov'}, l = lookupify{'mov'}, + pa = lookupify{'mov'}, + pb = lookupify{'mov'}, + pc = lookupify{'mov'}, + mk = lookupify{'mov'}, + mb = lookupify{'mov'}, + mc = lookupify{'mov'}, + tm0 = lookupify{'mov'}, + tm1 = lookupify{'mov'}, + s = lookupify{'mov'}, }, b = { a = lookupify{'mov'}, diff --git a/samples/scv_hello.l65 b/samples/scv_hello.l65 index 725e08b..51c6b4d 100644 --- a/samples/scv_hello.l65 +++ b/samples/scv_hello.l65 @@ -6,29 +6,29 @@ section{"rom", org=0x8000} di lxi sp,0xFFD2 ei - calt 0x8C + calt 0x8C - lxi hl,vdc_data - lxi de,0x3400 - mvi c,0x03 - block + lxi hl,vdc_data + lxi de,0x3400 + mvi c,0x03 + block lxi hl,message lxi de,0x3044 - lxi bc,0x01ff + lxi bc,0x01ff @loop_0 block dcr b - jr loop_0 + jr loop_0 - -- beep + -- beep lxi hl,0x3600 calf 0xfb0 @loop_1 nop - jr loop_1 + jr loop_1 section{"vdc_data", org=0x8030} dc.b 0xC0,0x00,0x00,0xF2 @@ -37,4 +37,4 @@ section{"message", org=0x8040} dc.b "\t\t\t\t Hello world! \t\t\t\t" dc.b 0x00 -writebin(filename .. '.bin') \ No newline at end of file +writebin(filename .. '.bin') diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 507573b..ad68f98 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -168,5 +168,14 @@ section{"rom", org=0x8000} out 0x00 out 0x5a out 0xbf + mov a,pa + mov a,pb + mov a,pc + mov a,mk + mov a,mb + mov a,mc + mov a,tm0 + mov a,tm1 + mov a,s writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 09624df..ce5bd43 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -412,12 +412,32 @@ for k,v in pairs(opinout) do end end + +local op4car8={ + movapa=M.op(0xc0,10), + movapb=M.op(0xc1,10), + movapc=M.op(0xc2,10), + movamk=M.op(0xc3,10), + movamb=M.op(0xc4,10), + movamc=M.op(0xc5,10), + movatm0=M.op(0xc6,10), + movatm1=M.op(0xc7,10), + movas=M.op(0xc8,10), +} M.op4car8 = op4car8 +for k,v in pairs(op4car8) do + M[k] = function() + table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x4c, v.opc } }) + end +end + return M --[[ [todo] 16 bits instructions: 0x4cxx + + 0x4dxx 0x60xx 0x64xx From db038e29e552e7e7bfdc5827a45ce627c9ed5ef6 Mon Sep 17 00:00:00 2001 From: mooz Date: Thu, 15 Nov 2018 19:44:13 +0100 Subject: [PATCH 25/41] Added 0x4dxx MOV instructions. --- l7801.lua | 33 +++++++++++++++------------------ samples/scv_test.l65 | 9 +++++++++ uPD7801.lua | 22 ++++++++++++++++++---- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/l7801.lua b/l7801.lua index cce6ffe..2035d75 100644 --- a/l7801.lua +++ b/l7801.lua @@ -151,24 +151,21 @@ local opcode_reg_reg_list = { tm1 = lookupify{'mov'}, s = lookupify{'mov'}, }, - b = { - a = lookupify{'mov'}, - }, - c = { - a = lookupify{'mov'}, - }, - d = { - a = lookupify{'mov'}, - }, - e = { - a = lookupify{'mov'}, - }, - h = { - a = lookupify{'mov'}, - }, - l = { - a = lookupify{'mov'}, - }, + b = { a = lookupify{'mov'} }, + c = { a = lookupify{'mov'} }, + d = { a = lookupify{'mov'} }, + e = { a = lookupify{'mov'} }, + h = { a = lookupify{'mov'} }, + l = { a = lookupify{'mov'} }, + pa = { a = lookupify{'mov'} }, + pb = { a = lookupify{'mov'} }, + pc = { a = lookupify{'mov'} }, + mk = { a = lookupify{'mov'} }, + mb = { a = lookupify{'mov'} }, + mc = { a = lookupify{'mov'} }, + tm0 = { a = lookupify{'mov'} }, + tm1 = { a = lookupify{'mov'} }, + s = { a = lookupify{'mov'} }, v = {}, } diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index ad68f98..561dd05 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -177,5 +177,14 @@ section{"rom", org=0x8000} mov a,tm0 mov a,tm1 mov a,s + mov pa,a + mov pb,a + mov pc,a + mov mk,a + mov mb,a + mov mc,a + mov tm0,a + mov tm1,a + mov s,a writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index ce5bd43..8d33894 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -430,15 +430,29 @@ for k,v in pairs(op4car8) do end end +local op4dr8a={ + movpaa=M.op(0xc0,10), + movpba=M.op(0xc1,10), + movpca=M.op(0xc2,10), + movmka=M.op(0xc3,10), + movmba=M.op(0xc4,10), + movmca=M.op(0xc5,10), + movtm0a=M.op(0xc6,10), + movtm1a=M.op(0xc7,10), + movsa=M.op(0xc8,10), +} M.op4dr8a = op4dr8a +for k,v in pairs(op4dr8a) do + M[k] = function() + table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x4d, v.opc } }) + end +end + + return M --[[ [todo] 16 bits instructions: - 0x4cxx - - - 0x4dxx 0x60xx 0x64xx 0x70xx From a2e44ae24af5e7e404fd729a2c53e9fb062fd7e2 Mon Sep 17 00:00:00 2001 From: mooz Date: Thu, 15 Nov 2018 21:46:34 +0100 Subject: [PATCH 26/41] Added ANA, XRA, ORA, ADDNC, GTA, SUBNB, LTA, ADD, ADC, SUB, NEA, SBB, EQA, ONA, OFFA instructions. --- l7801.lua | 34 ++++--- samples/scv_test.l65 | 226 ++++++++++++++++++++++++++++++++++++++++++- uPD7801.lua | 37 ++++++- 3 files changed, 281 insertions(+), 16 deletions(-) diff --git a/l7801.lua b/l7801.lua index 2035d75..d6585ad 100644 --- a/l7801.lua +++ b/l7801.lua @@ -49,6 +49,8 @@ local Keywords_7801 = { 'skit','sknit','skz','sknc','sknz','sll','slr','softi', 'staw','stax','staxd','staxi','stc','stm','sui','suinb', 'table','xri', + 'ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa', + 'ona','offa' } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -97,7 +99,7 @@ local opcode_reg = lookupify{ 'dcr','dcx','inr','inx','pop','push','rll','rlr','sll','slr', } local opcode_reg_reg = lookupify{ - 'mov' + 'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa','ona','offa' } local opcode_regb = lookupify{ 'aci','adi','adinc','ani','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri', @@ -135,12 +137,14 @@ local opcode_reg_list = { local opcode_reg_reg_list = { a = { - b = lookupify{'mov'}, - c = lookupify{'mov'}, - d = lookupify{'mov'}, - e = lookupify{'mov'}, - h = lookupify{'mov'}, - l = lookupify{'mov'}, + a = lookupify{'ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa','ona','offa'}, + b = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa','ona','offa'}, + c = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa','ona','offa'}, + d = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa','ona','offa'}, + e = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa','ona','offa'}, + h = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa','ona','offa'}, + l = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa','ona','offa'}, + v = lookupify{'ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa','ona','offa'}, pa = lookupify{'mov'}, pb = lookupify{'mov'}, pc = lookupify{'mov'}, @@ -151,12 +155,13 @@ local opcode_reg_reg_list = { tm1 = lookupify{'mov'}, s = lookupify{'mov'}, }, - b = { a = lookupify{'mov'} }, - c = { a = lookupify{'mov'} }, - d = { a = lookupify{'mov'} }, - e = { a = lookupify{'mov'} }, - h = { a = lookupify{'mov'} }, - l = { a = lookupify{'mov'} }, + v = { a = lookupify{'ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa'} }, + b = { a = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa'} }, + c = { a = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa'} }, + d = { a = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa'} }, + e = { a = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa'} }, + h = { a = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa'} }, + l = { a = lookupify{'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa'} }, pa = { a = lookupify{'mov'} }, pb = { a = lookupify{'mov'} }, pc = { a = lookupify{'mov'} }, @@ -166,8 +171,9 @@ local opcode_reg_reg_list = { tm0 = { a = lookupify{'mov'} }, tm1 = { a = lookupify{'mov'} }, s = { a = lookupify{'mov'} }, - v = {}, } +local op60names = {} +local register_names = {'v','a','b','c','d','e','h','l'} local addressing_map = { imp = opcode_implied, diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 561dd05..700135f 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -186,5 +186,229 @@ section{"rom", org=0x8000} mov tm0,a mov tm1,a mov s,a - + ana v,a + ana a,a + ana b,a + ana c,a + ana d,a + ana e,a + ana h,a + ana l,a + xra v,a + xra a,a + xra b,a + xra c,a + xra d,a + xra e,a + xra h,a + xra l,a + ora v,a + ora a,a + ora b,a + ora c,a + ora d,a + ora e,a + ora h,a + ora l,a + addnc v,a + addnc a,a + addnc b,a + addnc c,a + addnc d,a + addnc e,a + addnc h,a + addnc l,a + gta v,a + gta a,a + gta b,a + gta c,a + gta d,a + gta e,a + gta h,a + gta l,a + subnb v,a + subnb a,a + subnb b,a + subnb c,a + subnb d,a + subnb e,a + subnb h,a + subnb l,a + lta v,a + lta a,a + lta b,a + lta c,a + lta d,a + lta e,a + lta h,a + lta l,a + add v,a + add a,a + add b,a + add c,a + add d,a + add e,a + add h,a + add l,a + adc v,a + adc a,a + adc b,a + adc c,a + adc d,a + adc e,a + adc h,a + adc l,a + sub v,a + sub a,a + sub b,a + sub c,a + sub d,a + sub e,a + sub h,a + sub l,a + nea v,a + nea a,a + nea b,a + nea c,a + nea d,a + nea e,a + nea h,a + nea l,a + sbb v,a + sbb a,a + sbb b,a + sbb c,a + sbb d,a + sbb e,a + sbb h,a + sbb l,a + eqa v,a + eqa a,a + eqa b,a + eqa c,a + eqa d,a + eqa e,a + eqa h,a + eqa l,a + ana a,v + ana a,a + ana a,b + ana a,c + ana a,d + ana a,e + ana a,h + ana a,l + xra a,v + xra a,a + xra a,b + xra a,c + xra a,d + xra a,e + xra a,h + xra a,l + ora a,v + ora a,a + ora a,b + ora a,c + ora a,d + ora a,e + ora a,h + ora a,l + addnc a,v + addnc a,a + addnc a,b + addnc a,c + addnc a,d + addnc a,e + addnc a,h + addnc a,l + gta a,v + gta a,a + gta a,b + gta a,c + gta a,d + gta a,e + gta a,h + gta a,l + subnb a,v + subnb a,a + subnb a,b + subnb a,c + subnb a,d + subnb a,e + subnb a,h + subnb a,l + lta a,v + lta a,a + lta a,b + lta a,c + lta a,d + lta a,e + lta a,h + lta a,l + add a,v + add a,a + add a,b + add a,c + add a,d + add a,e + add a,h + add a,l + ona a,v + ona a,a + ona a,b + ona a,c + ona a,d + ona a,e + ona a,h + ona a,l + adc a,v + adc a,a + adc a,b + adc a,c + adc a,d + adc a,e + adc a,h + adc a,l + offa a,v + offa a,a + offa a,b + offa a,c + offa a,d + offa a,e + offa a,h + offa a,l + sub a,v + sub a,a + sub a,b + sub a,c + sub a,d + sub a,e + sub a,h + sub a,l + nea a,v + nea a,a + nea a,b + nea a,c + nea a,d + nea a,e + nea a,h + nea a,l + sbb a,v + sbb a,a + sbb a,b + sbb a,c + sbb a,d + sbb a,e + sbb a,h + sbb a,l + eqa a,v + eqa a,a + eqa a,b + eqa a,c + eqa a,d + eqa a,e + eqa a,h + eqa a,l + writebin(filename .. '.bin') \ No newline at end of file diff --git a/uPD7801.lua b/uPD7801.lua index 8d33894..7a6cf69 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -447,13 +447,48 @@ for k,v in pairs(op4dr8a) do end end +local op60names = {'ana','xra','ora','addnc','gta','subnb','lta','add','','adc','','sub','nea','sbb','eqa'} +local register_names = {'v','a','b','c','d','e','h','l'} +local k = 0x08 +for i,o in ipairs(op60names) do + if o == '' then + k = k + #register_names + else + for j,r in ipairs(register_names) do + local l = k + M[o .. r .. 'a'] = function() + table.insert(M.section_current.instructions, { size=2, cycles=8, bin={ 0x60, l } }) + end + k = k + 1 + end + end +end + +k = 0x88 +op60names[9] = 'ona' +op60names[11] = 'offa' +for i,o in ipairs(op60names) do + if o == '' then + k = k + #register_names + else + for j,r in ipairs(register_names) do + local l = k + local name = o .. 'a' .. r + if not M[name] then + M[name] = function() + table.insert(M.section_current.instructions, { size=2, cycles=8, bin={ 0x60, l } }) + end + end + k = k + 1 + end + end +end return M --[[ [todo] 16 bits instructions: - 0x60xx 0x64xx 0x70xx 0x74xx From 08086d222e8acdb89ba2c3a89fafb7b127068ac9 Mon Sep 17 00:00:00 2001 From: mooz Date: Fri, 16 Nov 2018 23:31:48 +0100 Subject: [PATCH 27/41] Added 0x64xx instructions. --- l7801.lua | 24 +- samples/scv_test.l65 | 630 +++++++++++++++++++++++++++---------------- uPD7801.lua | 48 +++- 3 files changed, 467 insertions(+), 235 deletions(-) diff --git a/l7801.lua b/l7801.lua index d6585ad..2122de0 100644 --- a/l7801.lua +++ b/l7801.lua @@ -37,6 +37,7 @@ local Keywords_control = { local Keywords_data = { 'dc', } + local Keywords_7801 = { 'aci','adi','adinc','ani','bit0','bit1','bit2','bit3', 'bit4','bit5','bit6','bit7','block','calb','calf','call', @@ -50,7 +51,7 @@ local Keywords_7801 = { 'staw','stax','staxd','staxi','stc','stm','sui','suinb', 'table','xri', 'ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa', - 'ona','offa' + 'ona','offa', } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -119,13 +120,14 @@ local opcode_timer = lookupify{ } local opcode_reg_list = { a = lookupify{'aci','adi','adinc','ani','dcr','inr','eqi','gti','lti','mvi','nei','offi','oni','ori','rll','rlr','sbi','sll','slr','sui','suinb','xri'}, - b = lookupify{'dcr','inr','mvi'}, - c = lookupify{'dcr','inr','mvi','rll','rlr','sll','slr'}, - d = lookupify{'mvi'}, - e = lookupify{'mvi'}, - h = lookupify{'mvi'}, - l = lookupify{'mvi'}, - v = lookupify{'inrw','ldaw','dcrw','eqiw','mvi','mviw','staw', + b = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi','dcr','inr','mvi'}, + c = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi','dcr','inr','mvi','rll','rlr','sll','slr'}, + d = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi','mvi'}, + e = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi','mvi'}, + h = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi','mvi'}, + l = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi','mvi'}, + v = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi', + 'inrw','ldaw','dcrw','eqiw','mvi','mviw','staw', 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', }, bc = lookupify{'ldax','lxi','mvix','pop','push','stax'}, @@ -133,6 +135,10 @@ local opcode_reg_list = { hl = lookupify{'dcx','inx','ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, sp = lookupify{'dcx','inx','lxi'}, va = lookupify{'pop','push'}, + pa = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi'}, + pb = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi'}, + pc = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi'}, + mk = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi'}, } local opcode_reg_reg_list = { @@ -1583,7 +1589,7 @@ local function ParseLua(src, src_name) if not Registers_7801[register_name] then return false, GenerateError(register_name .. " is not a valid register") end - if not opcode_reg_list[register_name] and opcode_reg_list[register_name][op] then + if (not opcode_reg_list[register_name]) and (not opcode_reg_list[register_name][op]) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end if opcode_regw[op] or opcode_regb[op] then diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 700135f..2dcebbe 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -186,229 +186,409 @@ section{"rom", org=0x8000} mov tm0,a mov tm1,a mov s,a - ana v,a - ana a,a - ana b,a - ana c,a - ana d,a - ana e,a - ana h,a - ana l,a - xra v,a - xra a,a - xra b,a - xra c,a - xra d,a - xra e,a - xra h,a - xra l,a - ora v,a - ora a,a - ora b,a - ora c,a - ora d,a - ora e,a - ora h,a - ora l,a - addnc v,a - addnc a,a - addnc b,a - addnc c,a - addnc d,a - addnc e,a - addnc h,a - addnc l,a - gta v,a - gta a,a - gta b,a - gta c,a - gta d,a - gta e,a - gta h,a - gta l,a - subnb v,a - subnb a,a - subnb b,a - subnb c,a - subnb d,a - subnb e,a - subnb h,a - subnb l,a - lta v,a - lta a,a - lta b,a - lta c,a - lta d,a - lta e,a - lta h,a - lta l,a - add v,a - add a,a - add b,a - add c,a - add d,a - add e,a - add h,a - add l,a - adc v,a - adc a,a - adc b,a - adc c,a - adc d,a - adc e,a - adc h,a - adc l,a - sub v,a - sub a,a - sub b,a - sub c,a - sub d,a - sub e,a - sub h,a - sub l,a - nea v,a - nea a,a - nea b,a - nea c,a - nea d,a - nea e,a - nea h,a - nea l,a - sbb v,a - sbb a,a - sbb b,a - sbb c,a - sbb d,a - sbb e,a - sbb h,a - sbb l,a - eqa v,a - eqa a,a - eqa b,a - eqa c,a - eqa d,a - eqa e,a - eqa h,a - eqa l,a - ana a,v - ana a,a - ana a,b - ana a,c - ana a,d - ana a,e - ana a,h - ana a,l - xra a,v - xra a,a - xra a,b - xra a,c - xra a,d - xra a,e - xra a,h - xra a,l - ora a,v - ora a,a - ora a,b - ora a,c - ora a,d - ora a,e - ora a,h - ora a,l - addnc a,v - addnc a,a - addnc a,b - addnc a,c - addnc a,d - addnc a,e - addnc a,h - addnc a,l - gta a,v - gta a,a - gta a,b - gta a,c - gta a,d - gta a,e - gta a,h - gta a,l - subnb a,v - subnb a,a - subnb a,b - subnb a,c - subnb a,d - subnb a,e - subnb a,h - subnb a,l - lta a,v - lta a,a - lta a,b - lta a,c - lta a,d - lta a,e - lta a,h - lta a,l - add a,v - add a,a - add a,b - add a,c - add a,d - add a,e - add a,h - add a,l - ona a,v - ona a,a - ona a,b - ona a,c - ona a,d - ona a,e - ona a,h - ona a,l - adc a,v - adc a,a - adc a,b - adc a,c - adc a,d - adc a,e - adc a,h - adc a,l - offa a,v - offa a,a - offa a,b - offa a,c - offa a,d - offa a,e - offa a,h - offa a,l - sub a,v - sub a,a - sub a,b - sub a,c - sub a,d - sub a,e - sub a,h - sub a,l - nea a,v - nea a,a - nea a,b - nea a,c - nea a,d - nea a,e - nea a,h - nea a,l - sbb a,v - sbb a,a - sbb a,b - sbb a,c - sbb a,d - sbb a,e - sbb a,h - sbb a,l - eqa a,v - eqa a,a - eqa a,b - eqa a,c - eqa a,d - eqa a,e - eqa a,h - eqa a,l + ana v,a + ana a,a + ana b,a + ana c,a + ana d,a + ana e,a + ana h,a + ana l,a + xra v,a + xra a,a + xra b,a + xra c,a + xra d,a + xra e,a + xra h,a + xra l,a + ora v,a + ora a,a + ora b,a + ora c,a + ora d,a + ora e,a + ora h,a + ora l,a + addnc v,a + addnc a,a + addnc b,a + addnc c,a + addnc d,a + addnc e,a + addnc h,a + addnc l,a + gta v,a + gta a,a + gta b,a + gta c,a + gta d,a + gta e,a + gta h,a + gta l,a + subnb v,a + subnb a,a + subnb b,a + subnb c,a + subnb d,a + subnb e,a + subnb h,a + subnb l,a + lta v,a + lta a,a + lta b,a + lta c,a + lta d,a + lta e,a + lta h,a + lta l,a + add v,a + add a,a + add b,a + add c,a + add d,a + add e,a + add h,a + add l,a + adc v,a + adc a,a + adc b,a + adc c,a + adc d,a + adc e,a + adc h,a + adc l,a + sub v,a + sub a,a + sub b,a + sub c,a + sub d,a + sub e,a + sub h,a + sub l,a + nea v,a + nea a,a + nea b,a + nea c,a + nea d,a + nea e,a + nea h,a + nea l,a + sbb v,a + sbb a,a + sbb b,a + sbb c,a + sbb d,a + sbb e,a + sbb h,a + sbb l,a + eqa v,a + eqa a,a + eqa b,a + eqa c,a + eqa d,a + eqa e,a + eqa h,a + eqa l,a + ana a,v + ana a,a + ana a,b + ana a,c + ana a,d + ana a,e + ana a,h + ana a,l + xra a,v + xra a,a + xra a,b + xra a,c + xra a,d + xra a,e + xra a,h + xra a,l + ora a,v + ora a,a + ora a,b + ora a,c + ora a,d + ora a,e + ora a,h + ora a,l + addnc a,v + addnc a,a + addnc a,b + addnc a,c + addnc a,d + addnc a,e + addnc a,h + addnc a,l + gta a,v + gta a,a + gta a,b + gta a,c + gta a,d + gta a,e + gta a,h + gta a,l + subnb a,v + subnb a,a + subnb a,b + subnb a,c + subnb a,d + subnb a,e + subnb a,h + subnb a,l + lta a,v + lta a,a + lta a,b + lta a,c + lta a,d + lta a,e + lta a,h + lta a,l + add a,v + add a,a + add a,b + add a,c + add a,d + add a,e + add a,h + add a,l + ona a,v + ona a,a + ona a,b + ona a,c + ona a,d + ona a,e + ona a,h + ona a,l + adc a,v + adc a,a + adc a,b + adc a,c + adc a,d + adc a,e + adc a,h + adc a,l + offa a,v + offa a,a + offa a,b + offa a,c + offa a,d + offa a,e + offa a,h + offa a,l + sub a,v + sub a,a + sub a,b + sub a,c + sub a,d + sub a,e + sub a,h + sub a,l + nea a,v + nea a,a + nea a,b + nea a,c + nea a,d + nea a,e + nea a,h + nea a,l + sbb a,v + sbb a,a + sbb a,b + sbb a,c + sbb a,d + sbb a,e + sbb a,h + sbb a,l + eqa a,v + eqa a,a + eqa a,b + eqa a,c + eqa a,d + eqa a,e + eqa a,h + eqa a,l + ani v,0x00 + ani a,0x01 + ani b,0x02 + ani c,0x03 + ani d,0x04 + ani e,0x05 + ani h,0x06 + ani l,0x07 + xri v,0x08 + xri a,0x09 + xri b,0x0a + xri c,0x0b + xri d,0x0c + xri e,0x0d + xri h,0x0e + xri l,0x0f + ori v,0x10 + ori a,0x11 + ori b,0x12 + ori c,0x13 + ori d,0x14 + ori e,0x15 + ori h,0x16 + ori l,0x17 + adinc v,0x18 + adinc a,0x19 + adinc b,0x1a + adinc c,0x1b + adinc d,0x1c + adinc e,0x1d + adinc h,0x1e + adinc l,0x1f + gti v,0x20 + gti a,0x21 + gti b,0x22 + gti c,0x23 + gti d,0x24 + gti e,0x25 + gti h,0x26 + gti l,0x27 + suinb v,0x28 + suinb a,0x29 + suinb b,0x2a + suinb c,0x2b + suinb d,0x2c + suinb e,0x2d + suinb h,0x2e + suinb l,0x2f + lti v,0x30 + lti a,0x31 + lti b,0x32 + lti c,0x33 + lti d,0x34 + lti e,0x35 + lti h,0x36 + lti l,0x37 + adi v,0x38 + adi a,0x39 + adi b,0x3a + adi c,0x3b + adi d,0x3c + adi e,0x3d + adi h,0x3e + adi l,0x4f + oni v,0x40 + oni a,0x41 + oni b,0x42 + oni c,0x43 + oni d,0x44 + oni e,0x45 + oni h,0x46 + oni l,0x47 + aci v,0x48 + aci a,0x49 + aci b,0x4a + aci c,0x4b + aci d,0x4c + aci e,0x4d + aci h,0x4e + aci l,0x4f + offi v,0x50 + offi a,0x51 + offi b,0x52 + offi c,0x53 + offi d,0x54 + offi e,0x55 + offi h,0x56 + offi l,0x57 + sui v,0x58 + sui a,0x59 + sui b,0x5a + sui c,0x5b + sui d,0x5c + sui e,0x5d + sui h,0x5e + sui l,0x5f + nei v,0x60 + nei a,0x61 + nei b,0x62 + nei c,0x63 + nei d,0x64 + nei e,0x65 + nei h,0x66 + nei l,0x67 + sbi v,0x68 + sbi a,0x69 + sbi b,0x6a + sbi c,0x6b + sbi d,0x6c + sbi e,0x6d + sbi h,0x6e + sbi l,0x6f + eqi v,0x70 + eqi a,0x71 + eqi b,0x72 + eqi c,0x73 + eqi d,0x74 + eqi e,0x75 + eqi h,0x76 + eqi l,0x77 + ani pa,0x78 + ani pb,0x79 + ani pc,0x7a + ani mk,0x7b + xri pa,0x7c + xri pb,0x7d + xri pc,0x7e + xri mk,0x7f + ori pa,0x80 + ori pb,0x81 + ori pc,0x82 + ori mk,0x83 + adinc pa,0x84 + adinc pb,0x85 + adinc pc,0x86 + adinc mk,0x87 + gti pa,0x88 + gti pb,0x89 + gti pc,0x8a + gti mk,0x8b + suinb pa,0x8c + suinb pb,0x8d + suinb pc,0x8e + suinb mk,0x8f + lti pa,0x90 + lti pb,0x91 + lti pc,0x92 + lti mk,0x93 + adi pa,0x94 + adi pb,0x95 + adi pc,0x96 + adi mk,0x97 + oni pa,0x98 + oni pb,0x99 + oni pc,0x9a + oni mk,0x9b + aci pa,0x9c + aci pb,0x9d + aci pc,0x9e + aci mk,0x9f + offi pa,0xa0 + offi pb,0xa1 + offi pc,0xa2 + offi mk,0xa3 + sui pa,0xa4 + sui pb,0xa5 + sui pc,0xa6 + sui mk,0xa7 + nei pa,0xa8 + nei pb,0xa9 + nei pc,0xaa + nei mk,0xab + sbi pa,0xac + sbi pb,0xad + sbi pc,0xae + sbi mk,0xaf + eqi pa,0xb0 + eqi pb,0xb1 + eqi pc,0xb2 + eqi mk,0xb3 -writebin(filename .. '.bin') \ No newline at end of file +writebin(filename .. '.bin') diff --git a/uPD7801.lua b/uPD7801.lua index 7a6cf69..b3974bc 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -484,12 +484,58 @@ for i,o in ipairs(op60names) do end end +k = 0x08 +local op64names = { 'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi' } +for i,o in ipairs(op64names) do + for j,r in ipairs(register_names) do + local name = o .. r + if not M[name] then + local l = k + M[name] = function(late,early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local op = { cycles=11 } + op.size = function() late,early = M.size_op(late,early) return 3 end + op.bin = function() local l65dbg=l65dbg + local x = 0x00 + l; + local y = 0x00 + M.op_eval_byte(late,early) + return { 0x64, x, y } + end + table.insert(M.section_current.instructions, op) + end + end + k = k + 1 + end +end + +k = 0x88 +local ex_register_names = {'pa','pb','pc','mk'} +for i,o in ipairs(op64names) do + for j,r in ipairs(ex_register_names) do + local name = o .. r + if not M[name] then + local l = k + M[name] = function(late,early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local op = { cycles=11 } + op.size = function() late,early = M.size_op(late,early) return 3 end + op.bin = function() local l65dbg=l65dbg + local x = 0x00 + l; + local y = 0x00 + M.op_eval_byte(late,early) + return { 0x64, x, y } + end + table.insert(M.section_current.instructions, op) + end + end + k = k + 1 + end + k = k + 4 +end + return M --[[ [todo] 16 bits instructions: - 0x64xx 0x70xx 0x74xx ]]-- From b9fc343548c5249e4339e7b409dc596e736d1520 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 17 Nov 2018 18:58:07 +0100 Subject: [PATCH 28/41] Added 0x74xx instructions. --- l7801.lua | 3 +++ samples/scv_test.l65 | 17 ++++++++++++++++- uPD7801.lua | 28 +++++++++++++++++++++++++++- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/l7801.lua b/l7801.lua index 2122de0..8041d08 100644 --- a/l7801.lua +++ b/l7801.lua @@ -52,6 +52,7 @@ local Keywords_7801 = { 'table','xri', 'ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa', 'ona','offa', + 'anaw','xraw','oraw','addncw','gtaw','subnbw','ltaw','addw','onaw','adcw','offaw','subw','neaw','sbbw','eqaw', } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -89,6 +90,7 @@ local opcode_immediate = lookupify{ local opcode_wa = lookupify{ 'inrw','ldaw','dcrw','staw', 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', + 'anaw','xraw','oraw','addncw','gtaw','subnbw','ltaw','addw','onaw','adcw','offaw','subw','neaw','sbbw','eqaw', } local opcode_wab = lookupify{ 'mviw','eqiw' @@ -129,6 +131,7 @@ local opcode_reg_list = { v = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi', 'inrw','ldaw','dcrw','eqiw','mvi','mviw','staw', 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', + 'anaw','xraw','oraw','addncw','gtaw','subnbw','ltaw','addw','onaw','adcw','offaw','subw','neaw','sbbw','eqaw', }, bc = lookupify{'ldax','lxi','mvix','pop','push','stax'}, de = lookupify{'ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 2dcebbe..fd3670b 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -590,5 +590,20 @@ section{"rom", org=0x8000} eqi pb,0xb1 eqi pc,0xb2 eqi mk,0xb3 - + anaw (v,0xf0) + xraw (v,0xe1) + oraw (v,0xd2) + addncw (v,0xc3) + gtaw (v,0xb4) + subnbw (v,0xa5) + ltaw (v,0x96) + addw (v,0x87) + onaw (v,0x78) + adcw (v,0x69) + offaw (v,0x5a) + subw (v,0x4b) + neaw (v,0x3c) + sbbw (v,0x2d) + eqaw (v,0x1e) + writebin(filename .. '.bin') diff --git a/uPD7801.lua b/uPD7801.lua index b3974bc..4544486 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -531,11 +531,37 @@ for i,o in ipairs(op64names) do k = k + 4 end +local op74wa = { + anaw=M.op(0x88,14), + xraw=M.op(0x90,14), + oraw=M.op(0x98,14), + addncw=M.op(0xa0,14), + gtaw=M.op(0xa8,14), + subnbw=M.op(0xb0,14), + ltaw=M.op(0xb8,14), + addw=M.op(0xc0,14), + onaw=M.op(0xc8,14), + adcw=M.op(0xd0,14), + offaw=M.op(0xd8,14), + subw=M.op(0xe0,14), + neaw=M.op(0xe8,14), + sbbw=M.op(0xf0,14), + eqaw=M.op(0xf8,14), +} M.op74wa = op74wa +for k,v in pairs(op74wa) do + M[k .. 'wa'] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 2 end + local bin = function() local l65dbg=l65dbg return { 0x74, v.opc, M.op_eval_byte(late,early) } end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + + return M --[[ [todo] 16 bits instructions: 0x70xx - 0x74xx ]]-- From bac144896a58dcbcb3e216ee6da52e00fe0c4cf5 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 17 Nov 2018 21:49:41 +0100 Subject: [PATCH 29/41] Added SSPD, LSPD, SBCD, LBCD, SDED, LDED, SHLD and LHLD instructions. --- l7801.lua | 21 ++++++- samples/scv_test.l65 | 10 ++- uPD7801.lua | 146 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+), 3 deletions(-) diff --git a/l7801.lua b/l7801.lua index 8041d08..44b53ac 100644 --- a/l7801.lua +++ b/l7801.lua @@ -53,6 +53,7 @@ local Keywords_7801 = { 'ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa', 'ona','offa', 'anaw','xraw','oraw','addncw','gtaw','subnbw','ltaw','addw','onaw','adcw','offaw','subw','neaw','sbbw','eqaw', + 'sspd','lspd','sbcd','lbcd','sded','lded','shld','lhld', } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -120,6 +121,9 @@ local opcode_regw = lookupify{ local opcode_timer = lookupify{ 'skit','sknit', } +local opcode_ind = lookupify{ + 'sspd','lspd','sbcd','lbcd','sded','lded','shld','lhld', +} local opcode_reg_list = { a = lookupify{'aci','adi','adinc','ani','dcr','inr','eqi','gti','lti','mvi','nei','offi','oni','ori','rll','rlr','sbi','sll','slr','sui','suinb','xri'}, b = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi','dcr','inr','mvi'}, @@ -1512,14 +1516,27 @@ local function ParseLua(src, src_name) end stat = emit_call{name=op .. 'imm', args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break end + if opcode_ind[op] then + if not tok:ConsumeSymbol('(', tokenList) then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) if not st then return false, expr end + local paren_open_whites,paren_close_whites,mod_st,mod_expr = {},{} + 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 + if not tok:ConsumeSymbol(')', tokenList) then return false, expr end + stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + end if (opcode_wa[op] or opcode_wab[op] or opcode_reg_ind[op] or opcode_reg_ind_ex[op]) and tok:ConsumeSymbol('(', tokenList) then local paren_open_whites,paren_close_whites = {},{} for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_open_whites, v) end - + local register_name = tok:Get(tokenList).Data - if not Registers_7801[register_name] then + if (not Registers_7801[register_name]) then return false, GenerateError(register_name .. " is not a valid register") end + if not (opcode_reg_list[register_name] and opcode_reg_list[register_name][op]) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index fd3670b..48aa0cf 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -605,5 +605,13 @@ section{"rom", org=0x8000} neaw (v,0x3c) sbbw (v,0x2d) eqaw (v,0x1e) - + sspd (0x8000) + lspd (0x8001) + sbcd (0x8010) + lbcd (0x8011) + sded (0x8100) + lded (0x8101) + shld (0x8110) + lhld (0x8111) + writebin(filename .. '.bin') diff --git a/uPD7801.lua b/uPD7801.lua index 4544486..f345c9e 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -557,6 +557,28 @@ for k,v in pairs(op74wa) do end end +local op70w = { + sspd=M.op(0x0e,20), + lspd=M.op(0x0f,20), + sbcd=M.op(0x1e,20), + lbcd=M.op(0x1f,20), + sded=M.op(0x2e,20), + lded=M.op(0x2f,20), + shld=M.op(0x3e,20), + lhld=M.op(0x3f,20), +} M.op70w = op70w +for k,v in pairs(op70w) do + M[k] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 3 end + local bin = function() local l65dbg=l65dbg + local x = M.op_eval_word(late,early) + return { 0x70, v.opc, x&0xff, x>>8 } + end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + return M @@ -564,4 +586,128 @@ return M 16 bits instructions: 0x70xx + + 17 + case 0x68: my_stprintf_s(buffer, buffer_len, _T("mov v,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x69: my_stprintf_s(buffer, buffer_len, _T("mov a,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x6a: my_stprintf_s(buffer, buffer_len, _T("mov b,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x6b: my_stprintf_s(buffer, buffer_len, _T("mov c,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x6c: my_stprintf_s(buffer, buffer_len, _T("mov d,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x6d: my_stprintf_s(buffer, buffer_len, _T("mov e,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x6e: my_stprintf_s(buffer, buffer_len, _T("mov h,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x6f: my_stprintf_s(buffer, buffer_len, _T("mov l,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x78: my_stprintf_s(buffer, buffer_len, _T("mov %s,v"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x79: my_stprintf_s(buffer, buffer_len, _T("mov %s,a"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x7a: my_stprintf_s(buffer, buffer_len, _T("mov %s,b"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x7b: my_stprintf_s(buffer, buffer_len, _T("mov %s,c"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x7c: my_stprintf_s(buffer, buffer_len, _T("mov %s,d"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x7d: my_stprintf_s(buffer, buffer_len, _T("mov %s,e"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x7e: my_stprintf_s(buffer, buffer_len, _T("mov %s,h"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + case 0x7f: my_stprintf_s(buffer, buffer_len, _T("mov %s,l"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + + case 0x89: my_stprintf_s(buffer, buffer_len, _T("anax b")); break; + case 0x8a: my_stprintf_s(buffer, buffer_len, _T("anax d")); break; + case 0x8b: my_stprintf_s(buffer, buffer_len, _T("anax h")); break; + case 0x8c: my_stprintf_s(buffer, buffer_len, _T("anax d+")); break; + case 0x8d: my_stprintf_s(buffer, buffer_len, _T("anax h+")); break; + case 0x8e: my_stprintf_s(buffer, buffer_len, _T("anax d-")); break; + case 0x8f: my_stprintf_s(buffer, buffer_len, _T("anax h-")); break; + case 0x91: my_stprintf_s(buffer, buffer_len, _T("xrax b")); break; + case 0x92: my_stprintf_s(buffer, buffer_len, _T("xrax d")); break; + case 0x93: my_stprintf_s(buffer, buffer_len, _T("xrax h")); break; + case 0x94: my_stprintf_s(buffer, buffer_len, _T("xrax d+")); break; + case 0x95: my_stprintf_s(buffer, buffer_len, _T("xrax h+")); break; + case 0x96: my_stprintf_s(buffer, buffer_len, _T("xrax d-")); break; + case 0x97: my_stprintf_s(buffer, buffer_len, _T("xrax h-")); break; + case 0x99: my_stprintf_s(buffer, buffer_len, _T("orax b")); break; + case 0x9a: my_stprintf_s(buffer, buffer_len, _T("orax d")); break; + case 0x9b: my_stprintf_s(buffer, buffer_len, _T("orax h")); break; + case 0x9c: my_stprintf_s(buffer, buffer_len, _T("orax d+")); break; + case 0x9d: my_stprintf_s(buffer, buffer_len, _T("orax h+")); break; + case 0x9e: my_stprintf_s(buffer, buffer_len, _T("orax d-")); break; + case 0x9f: my_stprintf_s(buffer, buffer_len, _T("orax h-")); break; + case 0xa1: my_stprintf_s(buffer, buffer_len, _T("addncx b")); break; + case 0xa2: my_stprintf_s(buffer, buffer_len, _T("addncx d")); break; + case 0xa3: my_stprintf_s(buffer, buffer_len, _T("addncx h")); break; + case 0xa4: my_stprintf_s(buffer, buffer_len, _T("addncx d+")); break; + case 0xa5: my_stprintf_s(buffer, buffer_len, _T("addncx h+")); break; + case 0xa6: my_stprintf_s(buffer, buffer_len, _T("addncx d-")); break; + case 0xa7: my_stprintf_s(buffer, buffer_len, _T("addncx h-")); break; + case 0xa9: my_stprintf_s(buffer, buffer_len, _T("gtax b")); break; + case 0xaa: my_stprintf_s(buffer, buffer_len, _T("gtax d")); break; + case 0xab: my_stprintf_s(buffer, buffer_len, _T("gtax h")); break; + case 0xac: my_stprintf_s(buffer, buffer_len, _T("gtax d+")); break; + case 0xad: my_stprintf_s(buffer, buffer_len, _T("gtax h+")); break; + case 0xae: my_stprintf_s(buffer, buffer_len, _T("gtax d-")); break; + case 0xaf: my_stprintf_s(buffer, buffer_len, _T("gtax h-")); break; + case 0xb1: my_stprintf_s(buffer, buffer_len, _T("subnbx b")); break; + case 0xb2: my_stprintf_s(buffer, buffer_len, _T("subnbx d")); break; + case 0xb3: my_stprintf_s(buffer, buffer_len, _T("subnbx h")); break; + case 0xb4: my_stprintf_s(buffer, buffer_len, _T("subnbx d+")); break; + case 0xb5: my_stprintf_s(buffer, buffer_len, _T("subnbx h+")); break; + case 0xb6: my_stprintf_s(buffer, buffer_len, _T("subnbx d-")); break; + case 0xb7: my_stprintf_s(buffer, buffer_len, _T("subnbx h-")); break; + case 0xb9: my_stprintf_s(buffer, buffer_len, _T("ltax b")); break; + case 0xba: my_stprintf_s(buffer, buffer_len, _T("ltax d")); break; + case 0xbb: my_stprintf_s(buffer, buffer_len, _T("ltax h")); break; + case 0xbc: my_stprintf_s(buffer, buffer_len, _T("ltax d+")); break; + case 0xbd: my_stprintf_s(buffer, buffer_len, _T("ltax h+")); break; + case 0xbe: my_stprintf_s(buffer, buffer_len, _T("ltax d-")); break; + case 0xbf: my_stprintf_s(buffer, buffer_len, _T("ltax h-")); break; + case 0xc1: my_stprintf_s(buffer, buffer_len, _T("addx b")); break; + case 0xc2: my_stprintf_s(buffer, buffer_len, _T("addx d")); break; + case 0xc3: my_stprintf_s(buffer, buffer_len, _T("addx h")); break; + case 0xc4: my_stprintf_s(buffer, buffer_len, _T("addx d+")); break; + case 0xc5: my_stprintf_s(buffer, buffer_len, _T("addx h+")); break; + case 0xc6: my_stprintf_s(buffer, buffer_len, _T("addx d-")); break; + case 0xc7: my_stprintf_s(buffer, buffer_len, _T("addx h-")); break; + case 0xc9: my_stprintf_s(buffer, buffer_len, _T("onax b")); break; + case 0xca: my_stprintf_s(buffer, buffer_len, _T("onax d")); break; + case 0xcb: my_stprintf_s(buffer, buffer_len, _T("onax h")); break; + case 0xcc: my_stprintf_s(buffer, buffer_len, _T("onax d+")); break; + case 0xcd: my_stprintf_s(buffer, buffer_len, _T("onax h+")); break; + case 0xce: my_stprintf_s(buffer, buffer_len, _T("onax d-")); break; + case 0xcf: my_stprintf_s(buffer, buffer_len, _T("onax h-")); break; + case 0xd1: my_stprintf_s(buffer, buffer_len, _T("adcx b")); break; + case 0xd2: my_stprintf_s(buffer, buffer_len, _T("adcx d")); break; + case 0xd3: my_stprintf_s(buffer, buffer_len, _T("adcx h")); break; + case 0xd4: my_stprintf_s(buffer, buffer_len, _T("adcx d+")); break; + case 0xd5: my_stprintf_s(buffer, buffer_len, _T("adcx h+")); break; + case 0xd6: my_stprintf_s(buffer, buffer_len, _T("adcx d-")); break; + case 0xd7: my_stprintf_s(buffer, buffer_len, _T("adcx h-")); break; + case 0xd9: my_stprintf_s(buffer, buffer_len, _T("offax b")); break; + case 0xda: my_stprintf_s(buffer, buffer_len, _T("offax d")); break; + case 0xdb: my_stprintf_s(buffer, buffer_len, _T("offax h")); break; + case 0xdc: my_stprintf_s(buffer, buffer_len, _T("offax d+")); break; + case 0xdd: my_stprintf_s(buffer, buffer_len, _T("offax h+")); break; + case 0xde: my_stprintf_s(buffer, buffer_len, _T("offax d-")); break; + case 0xdf: my_stprintf_s(buffer, buffer_len, _T("offax h-")); break; + case 0xe1: my_stprintf_s(buffer, buffer_len, _T("subx b")); break; + case 0xe2: my_stprintf_s(buffer, buffer_len, _T("subx d")); break; + case 0xe3: my_stprintf_s(buffer, buffer_len, _T("subx h")); break; + case 0xe4: my_stprintf_s(buffer, buffer_len, _T("subx d+")); break; + case 0xe5: my_stprintf_s(buffer, buffer_len, _T("subx h+")); break; + case 0xe6: my_stprintf_s(buffer, buffer_len, _T("subx d-")); break; + case 0xe7: my_stprintf_s(buffer, buffer_len, _T("subx h-")); break; + case 0xe9: my_stprintf_s(buffer, buffer_len, _T("neax b")); break; + case 0xea: my_stprintf_s(buffer, buffer_len, _T("neax d")); break; + case 0xeb: my_stprintf_s(buffer, buffer_len, _T("neax h")); break; + case 0xec: my_stprintf_s(buffer, buffer_len, _T("neax d+")); break; + case 0xed: my_stprintf_s(buffer, buffer_len, _T("neax h+")); break; + case 0xee: my_stprintf_s(buffer, buffer_len, _T("neax d-")); break; + case 0xef: my_stprintf_s(buffer, buffer_len, _T("neax h-")); break; + case 0xf1: my_stprintf_s(buffer, buffer_len, _T("sbbx b")); break; + case 0xf2: my_stprintf_s(buffer, buffer_len, _T("sbbx d")); break; + case 0xf3: my_stprintf_s(buffer, buffer_len, _T("sbbx h")); break; + case 0xf4: my_stprintf_s(buffer, buffer_len, _T("sbbx d+")); break; + case 0xf5: my_stprintf_s(buffer, buffer_len, _T("sbbx h+")); break; + case 0xf6: my_stprintf_s(buffer, buffer_len, _T("sbbx d-")); break; + case 0xf7: my_stprintf_s(buffer, buffer_len, _T("sbbx h-")); break; + case 0xf9: my_stprintf_s(buffer, buffer_len, _T("eqax b")); break; + case 0xfa: my_stprintf_s(buffer, buffer_len, _T("eqax d")); break; + case 0xfb: my_stprintf_s(buffer, buffer_len, _T("eqax h")); break; + case 0xfc: my_stprintf_s(buffer, buffer_len, _T("eqax d+")); break; + case 0xfd: my_stprintf_s(buffer, buffer_len, _T("eqax h+")); break; + case 0xfe: my_stprintf_s(buffer, buffer_len, _T("eqax d-")); break; + case 0xff: my_stprintf_s(buffer, buffer_len, _T("eqax h-")); break; ]]-- From b47f3ebb990bc57730b72ebe185e856d7e64bba3 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 17 Nov 2018 23:17:09 +0100 Subject: [PATCH 30/41] Added MOV (hhll),R8 instructions. --- l7801.lua | 53 ++++++++++++++++++++++++++++++++++++++++---- samples/scv_test.l65 | 10 ++++++++- uPD7801.lua | 39 ++++++++++++++++++++++---------- 3 files changed, 85 insertions(+), 17 deletions(-) diff --git a/l7801.lua b/l7801.lua index 44b53ac..92f6667 100644 --- a/l7801.lua +++ b/l7801.lua @@ -102,8 +102,11 @@ local opcode_relative = lookupify{ local opcode_reg = lookupify{ 'dcr','dcx','inr','inx','pop','push','rll','rlr','sll','slr', } +local opcode_mov = lookupify{ + 'mov' +} local opcode_reg_reg = lookupify{ - 'mov','ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa','ona','offa' + 'ana','xra','ora','addnc','gta','subnb','lta','add','adc','sub','nea','sbb','eqa','ona','offa' } local opcode_regb = lookupify{ 'aci','adi','adinc','ani','eqi','gti','lti','mvi','nei','offi','oni','ori','sbi','sui','suinb','xri', @@ -185,7 +188,7 @@ local opcode_reg_reg_list = { tm1 = { a = lookupify{'mov'} }, s = { a = lookupify{'mov'} }, } -local op60names = {} +local registers_8 = lookupify {'v','a','b','c','d','e','h','l'} local register_names = {'v','a','b','c','d','e','h','l'} local addressing_map = { @@ -1522,11 +1525,53 @@ local function ParseLua(src, src_name) end inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) local st, expr = ParseExpr(scope) if not st then return false, expr end - local paren_open_whites,paren_close_whites,mod_st,mod_expr = {},{} + local paren_open_whites,paren_close_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 if not tok:ConsumeSymbol(')', tokenList) then return false, expr end - stat = emit_call{name=op, args={expr, mod_expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + stat = emit_call{name=op, args={expr}, inverse_encapsulate=inverse_encapsulate, paren_open_white=paren_open_whites} break + end + if opcode_mov[op] then + tok:Save() + local r0_name = tok:Get(tokenList).Data + if not Registers_7801[r0_name] then + tok:Restore() + if not tok:ConsumeSymbol('(', tokenList) then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) if not st then return false, expr end + local paren_open_whites,paren_close_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 + + if not tok:ConsumeSymbol(')', tokenList) then return false, expr end + + for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + + if not tok:ConsumeSymbol(',', tokenList) then return false, expr end + + r0_name = tok:Get(tokenList).Data + if not registers_8[r0_name] then + return false, GenerateError(r0_name .. " is not a valid register") + end + stat = emit_call{name=op .. "ind" .. r0_name, args={expr}, inverse_encapsulate=inverse_encapsulates, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break + else + tok:Commit() + end + + if not tok:ConsumeSymbol(',', tokenList) then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + local r1_name = tok:Get(tokenList).Data + if not Registers_7801[r1_name] then + return false, GenerateError(r0_name .. " is not a valid register") + end + if not (opcode_reg_reg_list[r0_name] and opcode_reg_reg_list[r0_name][r1_name] and opcode_reg_reg_list[r0_name][r1_name][op]) then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + stat = emit_call{name=op .. r0_name .. r1_name} break end if (opcode_wa[op] or opcode_wab[op] or opcode_reg_ind[op] or opcode_reg_ind_ex[op]) and tok:ConsumeSymbol('(', tokenList) then local paren_open_whites,paren_close_whites = {},{} diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 48aa0cf..51c80e3 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -613,5 +613,13 @@ section{"rom", org=0x8000} lded (0x8101) shld (0x8110) lhld (0x8111) - + mov (0xab00),v + mov (0xbc01),a + mov (0xde02),b + mov (0xfa03),c + mov (0xeb04),d + mov (0xdc05),e + mov (0xcd06),h + mov (0xbe07),l + writebin(filename .. '.bin') diff --git a/uPD7801.lua b/uPD7801.lua index f345c9e..7f751af 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -557,7 +557,7 @@ for k,v in pairs(op74wa) do end end -local op70w = { +local op70ind = { sspd=M.op(0x0e,20), lspd=M.op(0x0f,20), sbcd=M.op(0x1e,20), @@ -566,11 +566,11 @@ local op70w = { lded=M.op(0x2f,20), shld=M.op(0x3e,20), lhld=M.op(0x3f,20), -} M.op70w = op70w -for k,v in pairs(op70w) do +} M.op70ind = op70ind +for k,v in pairs(op70ind) do M[k] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = M.size_op(late,early) return 3 end + local size = function() late,early = M.size_op(late,early) return 4 end local bin = function() local l65dbg=l65dbg local x = M.op_eval_word(late,early) return { 0x70, v.opc, x&0xff, x>>8 } @@ -579,6 +579,27 @@ for k,v in pairs(op70w) do end end +local op70indr8 = { + movindv=M.op(0x78,17), + movinda=M.op(0x79,17), + movindb=M.op(0x7a,17), + movindc=M.op(0x7b,17), + movindd=M.op(0x7c,17), + movinde=M.op(0x7d,17), + movindh=M.op(0x7e,17), + movindl=M.op(0x7f,17), +} M.op70indr8 = op70indr8 +for k,v in pairs(op70indr8) do + M[k] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 4 end + local bin = function() local l65dbg=l65dbg + local x = M.op_eval_word(late,early) + return { 0x70, v.opc, x&0xff, x>>8 } + end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end return M @@ -596,14 +617,8 @@ return M case 0x6d: my_stprintf_s(buffer, buffer_len, _T("mov e,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; case 0x6e: my_stprintf_s(buffer, buffer_len, _T("mov h,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; case 0x6f: my_stprintf_s(buffer, buffer_len, _T("mov l,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x78: my_stprintf_s(buffer, buffer_len, _T("mov %s,v"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x79: my_stprintf_s(buffer, buffer_len, _T("mov %s,a"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x7a: my_stprintf_s(buffer, buffer_len, _T("mov %s,b"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x7b: my_stprintf_s(buffer, buffer_len, _T("mov %s,c"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x7c: my_stprintf_s(buffer, buffer_len, _T("mov %s,d"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x7d: my_stprintf_s(buffer, buffer_len, _T("mov %s,e"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x7e: my_stprintf_s(buffer, buffer_len, _T("mov %s,h"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x7f: my_stprintf_s(buffer, buffer_len, _T("mov %s,l"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; + + case 0x89: my_stprintf_s(buffer, buffer_len, _T("anax b")); break; case 0x8a: my_stprintf_s(buffer, buffer_len, _T("anax d")); break; From ec56b7b504df2ee07f77a52a1fc52900ed205103 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 17 Nov 2018 23:40:10 +0100 Subject: [PATCH 31/41] Added MOV r8,(hhll) instructions. --- l7801.lua | 67 ++++++++++++++++++++++++-------------------- samples/scv_test.l65 | 8 ++++++ uPD7801.lua | 34 ++++++++++++++-------- 3 files changed, 66 insertions(+), 43 deletions(-) diff --git a/l7801.lua b/l7801.lua index 92f6667..823f3ed 100644 --- a/l7801.lua +++ b/l7801.lua @@ -1533,45 +1533,50 @@ local function ParseLua(src, src_name) end if opcode_mov[op] then tok:Save() - local r0_name = tok:Get(tokenList).Data - if not Registers_7801[r0_name] then - tok:Restore() - if not tok:ConsumeSymbol('(', tokenList) then + local r0_name, r1_name = tok:Get(tokenList).Data, '' + if Registers_7801[r0_name] then + tok:Commit() + if not tok:ConsumeSymbol(',', tokenList) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) - local st, expr = ParseExpr(scope) if not st then return false, expr end - local paren_open_whites,paren_close_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 - - if not tok:ConsumeSymbol(')', tokenList) then return false, expr end - - for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end - for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end - - if not tok:ConsumeSymbol(',', tokenList) then return false, expr end - - r0_name = tok:Get(tokenList).Data - if not registers_8[r0_name] then - return false, GenerateError(r0_name .. " is not a valid register") + tok:Save() + r1_name = tok:Get(tokenList).Data + if Registers_7801[r1_name] then + tok:Commit() + if not (opcode_reg_reg_list[r0_name] and opcode_reg_reg_list[r0_name][r1_name] and opcode_reg_reg_list[r0_name][r1_name][op]) then + return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") + end + stat = emit_call{name=op .. r0_name .. r1_name} break + else + r1_name = '' end - stat = emit_call{name=op .. "ind" .. r0_name, args={expr}, inverse_encapsulate=inverse_encapsulates, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break else - tok:Commit() + r0_name = '' end - - if not tok:ConsumeSymbol(',', tokenList) then + tok:Restore() + + if not tok:ConsumeSymbol('(', tokenList) then return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") end - local r1_name = tok:Get(tokenList).Data - if not Registers_7801[r1_name] then - return false, GenerateError(r0_name .. " is not a valid register") + inverse_encapsulate = tok:ConsumeSymbol('!', tokenList) + local st, expr = ParseExpr(scope) if not st then return false, expr end + local paren_open_whites,paren_close_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 + + if not tok:ConsumeSymbol(')', tokenList) then return false, expr end + + for _,v in ipairs(tokenList[#tokenList-1].LeadingWhite) do table.insert(paren_close_whites, v) end + for _,v in ipairs(tokenList[#tokenList].LeadingWhite) do table.insert(paren_close_whites, v) end + + if r0_name == '' then + if not tok:ConsumeSymbol(',', tokenList) then return false, expr end + r1_name = tok:Get(tokenList).Data + if not registers_8[r1_name] then + return false, GenerateError(r1_name .. " is not a valid register") + end end - if not (opcode_reg_reg_list[r0_name] and opcode_reg_reg_list[r0_name][r1_name] and opcode_reg_reg_list[r0_name][r1_name][op]) then - return false, GenerateError("Opcode " .. op .. " doesn't support this addressing mode") - end - stat = emit_call{name=op .. r0_name .. r1_name} break + stat = emit_call{name=op .. r0_name .. "ind" .. r1_name, args={expr}, inverse_encapsulate=inverse_encapsulates, paren_open_white=paren_open_whites, paren_close_white=paren_close_whites} break end if (opcode_wa[op] or opcode_wab[op] or opcode_reg_ind[op] or opcode_reg_ind_ex[op]) and tok:ConsumeSymbol('(', tokenList) then local paren_open_whites,paren_close_whites = {},{} diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 51c80e3..435b27a 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -621,5 +621,13 @@ section{"rom", org=0x8000} mov (0xdc05),e mov (0xcd06),h mov (0xbe07),l + mov v,(0x000f) + mov a,(0x00f0) + mov b,(0x00ff) + mov c,(0x0f00) + mov d,(0x0f0f) + mov e,(0x0ff0) + mov h,(0x0fff) + mov l,(0xf000) writebin(filename .. '.bin') diff --git a/uPD7801.lua b/uPD7801.lua index 7f751af..4e50490 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -601,6 +601,28 @@ for k,v in pairs(op70indr8) do end end +local op70r8ind = { + movvind=M.op(0x68,17), + movaind=M.op(0x69,17), + movbind=M.op(0x6a,17), + movcind=M.op(0x6b,17), + movdind=M.op(0x6c,17), + moveind=M.op(0x6d,17), + movhind=M.op(0x6e,17), + movlind=M.op(0x6f,17), +} M.op70r8ind = op70r8ind +for k,v in pairs(op70r8ind) do + M[k] = function(late, early) + local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local size = function() late,early = M.size_op(late,early) return 4 end + local bin = function() local l65dbg=l65dbg + local x = M.op_eval_word(late,early) + return { 0x70, v.opc, x&0xff, x>>8 } + end + table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) + end +end + return M --[[ [todo] @@ -608,18 +630,6 @@ return M 16 bits instructions: 0x70xx - 17 - case 0x68: my_stprintf_s(buffer, buffer_len, _T("mov v,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x69: my_stprintf_s(buffer, buffer_len, _T("mov a,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x6a: my_stprintf_s(buffer, buffer_len, _T("mov b,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x6b: my_stprintf_s(buffer, buffer_len, _T("mov c,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x6c: my_stprintf_s(buffer, buffer_len, _T("mov d,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x6d: my_stprintf_s(buffer, buffer_len, _T("mov e,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x6e: my_stprintf_s(buffer, buffer_len, _T("mov h,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - case 0x6f: my_stprintf_s(buffer, buffer_len, _T("mov l,%s"), get_value_or_symbol(d_debugger->first_symbol, _T("%04xh"), getw())); break; - - - case 0x89: my_stprintf_s(buffer, buffer_len, _T("anax b")); break; case 0x8a: my_stprintf_s(buffer, buffer_len, _T("anax d")); break; case 0x8b: my_stprintf_s(buffer, buffer_len, _T("anax h")); break; From c42546e483e386973d9be39fb500d42df69c9738 Mon Sep 17 00:00:00 2001 From: mooz Date: Sat, 17 Nov 2018 23:43:03 +0100 Subject: [PATCH 32/41] Fixed opcode size. --- uPD7801.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uPD7801.lua b/uPD7801.lua index 4e50490..b19bdc5 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -551,7 +551,7 @@ local op74wa = { for k,v in pairs(op74wa) do M[k .. 'wa'] = function(late, early) local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } - local size = function() late,early = M.size_op(late,early) return 2 end + local size = function() late,early = M.size_op(late,early) return 3 end local bin = function() local l65dbg=l65dbg return { 0x74, v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end @@ -629,7 +629,7 @@ return M 16 bits instructions: 0x70xx - + 11 case 0x89: my_stprintf_s(buffer, buffer_len, _T("anax b")); break; case 0x8a: my_stprintf_s(buffer, buffer_len, _T("anax d")); break; case 0x8b: my_stprintf_s(buffer, buffer_len, _T("anax h")); break; From 345f9d522d73452c429b168c182344868f42508c Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 18 Nov 2018 00:10:32 +0100 Subject: [PATCH 33/41] Added the last opcodes of 0x70xx. --- l7801.lua | 25 +++++++-- samples/scv_test.l65 | 107 ++++++++++++++++++++++++++++++++++++- uPD7801.lua | 124 +++++-------------------------------------- 3 files changed, 140 insertions(+), 116 deletions(-) diff --git a/l7801.lua b/l7801.lua index 823f3ed..a7f086e 100644 --- a/l7801.lua +++ b/l7801.lua @@ -54,6 +54,9 @@ local Keywords_7801 = { 'ona','offa', 'anaw','xraw','oraw','addncw','gtaw','subnbw','ltaw','addw','onaw','adcw','offaw','subw','neaw','sbbw','eqaw', 'sspd','lspd','sbcd','lbcd','sded','lded','shld','lhld', + 'anax','xrax','orax','addncx','gtax','subnbx','ltax','addx','onax','adcx','offax','subx','neax','sbbx','eqax', + 'anaxi','xraxi','oraxi','addncxi','gtaxi','subnbxi','ltaxi','addxi','onaxi','adcxi','offaxi','subxi','neaxi','sbbxi','eqaxi', + 'anaxd','xraxd','oraxd','addncxd','gtaxd','subnbxd','ltaxd','addxd','onaxd','adcxd','offaxd','subxd','neaxd','sbbxd','eqaxd', } local Registers_7801 = { a=8,b=8,c=8,d=8,e=8,h=8,l=8,v=8, @@ -114,6 +117,9 @@ local opcode_regb = lookupify{ local opcode_reg_ind = lookupify{ 'ldax','ldaxd','ldaxi', 'stax','staxd','staxi', + 'anax','xrax','orax','addncx','gtax','subnbx','ltax','addx','onax','adcx','offax','subx','neax','sbbx','eqax', + 'anaxi','xraxi','oraxi','addncxi','gtaxi','subnbxi','ltaxi','addxi','onaxi','adcxi','offaxi','subxi','neaxi','sbbxi','eqaxi', + 'anaxd','xraxd','oraxd','addncxd','gtaxd','subnbxd','ltaxd','addxd','onaxd','adcxd','offaxd','subxd','neaxd','sbbxd','eqaxd', } local opcode_reg_ind_ex = lookupify{ 'mvix' @@ -140,9 +146,22 @@ local opcode_reg_list = { 'bit0','bit1','bit2','bit3','bit4','bit5','bit6','bit7', 'anaw','xraw','oraw','addncw','gtaw','subnbw','ltaw','addw','onaw','adcw','offaw','subw','neaw','sbbw','eqaw', }, - bc = lookupify{'ldax','lxi','mvix','pop','push','stax'}, - de = lookupify{'ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, - hl = lookupify{'dcx','inx','ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi'}, + bc = lookupify{ + 'ldax','lxi','mvix','pop','push','stax', + 'anax','xrax','orax','addncx','gtax','subnbx','ltax','addx','onax','adcx','offax','subx','neax','sbbx','eqax', + }, + de = lookupify{ + 'ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi', + 'anax','xrax','orax','addncx','gtax','subnbx','ltax','addx','onax','adcx','offax','subx','neax','sbbx','eqax', + 'anaxi','xraxi','oraxi','addncxi','gtaxi','subnbxi','ltaxi','addxi','onaxi','adcxi','offaxi','subxi','neaxi','sbbxi','eqaxi', + 'anaxd','xraxd','oraxd','addncxd','gtaxd','subnbxd','ltaxd','addxd','onaxd','adcxd','offaxd','subxd','neaxd','sbbxd','eqaxd', + }, + hl = lookupify{ + 'dcx','inx','ldax','ldaxd','ldaxi','lxi','mvix','pop','push','stax','staxd','staxi', + 'anax','xrax','orax','addncx','gtax','subnbx','ltax','addx','onax','adcx','offax','subx','neax','sbbx','eqax', + 'anaxi','xraxi','oraxi','addncxi','gtaxi','subnbxi','ltaxi','addxi','onaxi','adcxi','offaxi','subxi','neaxi','sbbxi','eqaxi', + 'anaxd','xraxd','oraxd','addncxd','gtaxd','subnbxd','ltaxd','addxd','onaxd','adcxd','offaxd','subxd','neaxd','sbbxd','eqaxd', + }, sp = lookupify{'dcx','inx','lxi'}, va = lookupify{'pop','push'}, pa = lookupify{'ani','xri','ori','adinc','gti','suinb','lti','adi','oni','aci','offi','sui','nei','sbi','eqi'}, diff --git a/samples/scv_test.l65 b/samples/scv_test.l65 index 435b27a..dab312e 100644 --- a/samples/scv_test.l65 +++ b/samples/scv_test.l65 @@ -629,5 +629,110 @@ section{"rom", org=0x8000} mov e,(0x0ff0) mov h,(0x0fff) mov l,(0xf000) - + anax (bc) + xrax (bc) + orax (bc) + addncx (bc) + gtax (bc) + subnbx (bc) + ltax (bc) + addx (bc) + onax (bc) + adcx (bc) + offax (bc) + subx (bc) + neax (bc) + sbbx (bc) + eqax (bc) + anax (de) + xrax (de) + orax (de) + addncx (de) + gtax (de) + subnbx (de) + ltax (de) + addx (de) + onax (de) + adcx (de) + offax (de) + subx (de) + neax (de) + sbbx (de) + eqax (de) + anax (hl) + xrax (hl) + orax (hl) + addncx (hl) + gtax (hl) + subnbx (hl) + ltax (hl) + addx (hl) + onax (hl) + adcx (hl) + offax (hl) + subx (hl) + neax (hl) + sbbx (hl) + eqax (hl) + anaxi (de) + xraxi (de) + oraxi (de) + addncxi (de) + gtaxi (de) + subnbxi (de) + ltaxi (de) + addxi (de) + onaxi (de) + adcxi (de) + offaxi (de) + subxi (de) + neaxi (de) + sbbxi (de) + eqaxi (de) + anaxi (hl) + xraxi (hl) + oraxi (hl) + addncxi (hl) + gtaxi (hl) + subnbxi (hl) + ltaxi (hl) + addxi (hl) + onaxi (hl) + adcxi (hl) + offaxi (hl) + subxi (hl) + neaxi (hl) + sbbxi (hl) + eqaxi (hl) + anaxd (de) + xraxd (de) + oraxd (de) + addncxd (de) + gtaxd (de) + subnbxd (de) + ltaxd (de) + addxd (de) + onaxd (de) + adcxd (de) + offaxd (de) + subxd (de) + neaxd (de) + sbbxd (de) + eqaxd (de) + anaxd (hl) + xraxd (hl) + oraxd (hl) + addncxd (hl) + gtaxd (hl) + subnbxd (hl) + ltaxd (hl) + addxd (hl) + onaxd (hl) + adcxd (hl) + offaxd (hl) + subxd (hl) + neaxd (hl) + sbbxd (hl) + eqaxd (hl) + writebin(filename .. '.bin') diff --git a/uPD7801.lua b/uPD7801.lua index b19bdc5..e02c77d 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -623,116 +623,16 @@ for k,v in pairs(op70r8ind) do end end -return M +k = 0x89 +local op70names = {'anax','xrax','orax','addncx','gtax','subnbx','ltax','addx','onax','adcx','offax','subx','neax','sbbx','eqax'} +local op70suffixes = {'bc','de','hl','ide','ihl','dde','dhl'} +for i,o in ipairs(op70names) do + for j,s in ipairs(op70suffixes) do + local l = 0x00 + k + (j-1) + (8 * (i-1)) + M[o .. s] = function() + table.insert(M.section_current.instructions, { size=2, cycles=11, bin={ 0x70, l } }) + end + end +end ---[[ [todo] - -16 bits instructions: - 0x70xx - 11 - case 0x89: my_stprintf_s(buffer, buffer_len, _T("anax b")); break; - case 0x8a: my_stprintf_s(buffer, buffer_len, _T("anax d")); break; - case 0x8b: my_stprintf_s(buffer, buffer_len, _T("anax h")); break; - case 0x8c: my_stprintf_s(buffer, buffer_len, _T("anax d+")); break; - case 0x8d: my_stprintf_s(buffer, buffer_len, _T("anax h+")); break; - case 0x8e: my_stprintf_s(buffer, buffer_len, _T("anax d-")); break; - case 0x8f: my_stprintf_s(buffer, buffer_len, _T("anax h-")); break; - case 0x91: my_stprintf_s(buffer, buffer_len, _T("xrax b")); break; - case 0x92: my_stprintf_s(buffer, buffer_len, _T("xrax d")); break; - case 0x93: my_stprintf_s(buffer, buffer_len, _T("xrax h")); break; - case 0x94: my_stprintf_s(buffer, buffer_len, _T("xrax d+")); break; - case 0x95: my_stprintf_s(buffer, buffer_len, _T("xrax h+")); break; - case 0x96: my_stprintf_s(buffer, buffer_len, _T("xrax d-")); break; - case 0x97: my_stprintf_s(buffer, buffer_len, _T("xrax h-")); break; - case 0x99: my_stprintf_s(buffer, buffer_len, _T("orax b")); break; - case 0x9a: my_stprintf_s(buffer, buffer_len, _T("orax d")); break; - case 0x9b: my_stprintf_s(buffer, buffer_len, _T("orax h")); break; - case 0x9c: my_stprintf_s(buffer, buffer_len, _T("orax d+")); break; - case 0x9d: my_stprintf_s(buffer, buffer_len, _T("orax h+")); break; - case 0x9e: my_stprintf_s(buffer, buffer_len, _T("orax d-")); break; - case 0x9f: my_stprintf_s(buffer, buffer_len, _T("orax h-")); break; - case 0xa1: my_stprintf_s(buffer, buffer_len, _T("addncx b")); break; - case 0xa2: my_stprintf_s(buffer, buffer_len, _T("addncx d")); break; - case 0xa3: my_stprintf_s(buffer, buffer_len, _T("addncx h")); break; - case 0xa4: my_stprintf_s(buffer, buffer_len, _T("addncx d+")); break; - case 0xa5: my_stprintf_s(buffer, buffer_len, _T("addncx h+")); break; - case 0xa6: my_stprintf_s(buffer, buffer_len, _T("addncx d-")); break; - case 0xa7: my_stprintf_s(buffer, buffer_len, _T("addncx h-")); break; - case 0xa9: my_stprintf_s(buffer, buffer_len, _T("gtax b")); break; - case 0xaa: my_stprintf_s(buffer, buffer_len, _T("gtax d")); break; - case 0xab: my_stprintf_s(buffer, buffer_len, _T("gtax h")); break; - case 0xac: my_stprintf_s(buffer, buffer_len, _T("gtax d+")); break; - case 0xad: my_stprintf_s(buffer, buffer_len, _T("gtax h+")); break; - case 0xae: my_stprintf_s(buffer, buffer_len, _T("gtax d-")); break; - case 0xaf: my_stprintf_s(buffer, buffer_len, _T("gtax h-")); break; - case 0xb1: my_stprintf_s(buffer, buffer_len, _T("subnbx b")); break; - case 0xb2: my_stprintf_s(buffer, buffer_len, _T("subnbx d")); break; - case 0xb3: my_stprintf_s(buffer, buffer_len, _T("subnbx h")); break; - case 0xb4: my_stprintf_s(buffer, buffer_len, _T("subnbx d+")); break; - case 0xb5: my_stprintf_s(buffer, buffer_len, _T("subnbx h+")); break; - case 0xb6: my_stprintf_s(buffer, buffer_len, _T("subnbx d-")); break; - case 0xb7: my_stprintf_s(buffer, buffer_len, _T("subnbx h-")); break; - case 0xb9: my_stprintf_s(buffer, buffer_len, _T("ltax b")); break; - case 0xba: my_stprintf_s(buffer, buffer_len, _T("ltax d")); break; - case 0xbb: my_stprintf_s(buffer, buffer_len, _T("ltax h")); break; - case 0xbc: my_stprintf_s(buffer, buffer_len, _T("ltax d+")); break; - case 0xbd: my_stprintf_s(buffer, buffer_len, _T("ltax h+")); break; - case 0xbe: my_stprintf_s(buffer, buffer_len, _T("ltax d-")); break; - case 0xbf: my_stprintf_s(buffer, buffer_len, _T("ltax h-")); break; - case 0xc1: my_stprintf_s(buffer, buffer_len, _T("addx b")); break; - case 0xc2: my_stprintf_s(buffer, buffer_len, _T("addx d")); break; - case 0xc3: my_stprintf_s(buffer, buffer_len, _T("addx h")); break; - case 0xc4: my_stprintf_s(buffer, buffer_len, _T("addx d+")); break; - case 0xc5: my_stprintf_s(buffer, buffer_len, _T("addx h+")); break; - case 0xc6: my_stprintf_s(buffer, buffer_len, _T("addx d-")); break; - case 0xc7: my_stprintf_s(buffer, buffer_len, _T("addx h-")); break; - case 0xc9: my_stprintf_s(buffer, buffer_len, _T("onax b")); break; - case 0xca: my_stprintf_s(buffer, buffer_len, _T("onax d")); break; - case 0xcb: my_stprintf_s(buffer, buffer_len, _T("onax h")); break; - case 0xcc: my_stprintf_s(buffer, buffer_len, _T("onax d+")); break; - case 0xcd: my_stprintf_s(buffer, buffer_len, _T("onax h+")); break; - case 0xce: my_stprintf_s(buffer, buffer_len, _T("onax d-")); break; - case 0xcf: my_stprintf_s(buffer, buffer_len, _T("onax h-")); break; - case 0xd1: my_stprintf_s(buffer, buffer_len, _T("adcx b")); break; - case 0xd2: my_stprintf_s(buffer, buffer_len, _T("adcx d")); break; - case 0xd3: my_stprintf_s(buffer, buffer_len, _T("adcx h")); break; - case 0xd4: my_stprintf_s(buffer, buffer_len, _T("adcx d+")); break; - case 0xd5: my_stprintf_s(buffer, buffer_len, _T("adcx h+")); break; - case 0xd6: my_stprintf_s(buffer, buffer_len, _T("adcx d-")); break; - case 0xd7: my_stprintf_s(buffer, buffer_len, _T("adcx h-")); break; - case 0xd9: my_stprintf_s(buffer, buffer_len, _T("offax b")); break; - case 0xda: my_stprintf_s(buffer, buffer_len, _T("offax d")); break; - case 0xdb: my_stprintf_s(buffer, buffer_len, _T("offax h")); break; - case 0xdc: my_stprintf_s(buffer, buffer_len, _T("offax d+")); break; - case 0xdd: my_stprintf_s(buffer, buffer_len, _T("offax h+")); break; - case 0xde: my_stprintf_s(buffer, buffer_len, _T("offax d-")); break; - case 0xdf: my_stprintf_s(buffer, buffer_len, _T("offax h-")); break; - case 0xe1: my_stprintf_s(buffer, buffer_len, _T("subx b")); break; - case 0xe2: my_stprintf_s(buffer, buffer_len, _T("subx d")); break; - case 0xe3: my_stprintf_s(buffer, buffer_len, _T("subx h")); break; - case 0xe4: my_stprintf_s(buffer, buffer_len, _T("subx d+")); break; - case 0xe5: my_stprintf_s(buffer, buffer_len, _T("subx h+")); break; - case 0xe6: my_stprintf_s(buffer, buffer_len, _T("subx d-")); break; - case 0xe7: my_stprintf_s(buffer, buffer_len, _T("subx h-")); break; - case 0xe9: my_stprintf_s(buffer, buffer_len, _T("neax b")); break; - case 0xea: my_stprintf_s(buffer, buffer_len, _T("neax d")); break; - case 0xeb: my_stprintf_s(buffer, buffer_len, _T("neax h")); break; - case 0xec: my_stprintf_s(buffer, buffer_len, _T("neax d+")); break; - case 0xed: my_stprintf_s(buffer, buffer_len, _T("neax h+")); break; - case 0xee: my_stprintf_s(buffer, buffer_len, _T("neax d-")); break; - case 0xef: my_stprintf_s(buffer, buffer_len, _T("neax h-")); break; - case 0xf1: my_stprintf_s(buffer, buffer_len, _T("sbbx b")); break; - case 0xf2: my_stprintf_s(buffer, buffer_len, _T("sbbx d")); break; - case 0xf3: my_stprintf_s(buffer, buffer_len, _T("sbbx h")); break; - case 0xf4: my_stprintf_s(buffer, buffer_len, _T("sbbx d+")); break; - case 0xf5: my_stprintf_s(buffer, buffer_len, _T("sbbx h+")); break; - case 0xf6: my_stprintf_s(buffer, buffer_len, _T("sbbx d-")); break; - case 0xf7: my_stprintf_s(buffer, buffer_len, _T("sbbx h-")); break; - case 0xf9: my_stprintf_s(buffer, buffer_len, _T("eqax b")); break; - case 0xfa: my_stprintf_s(buffer, buffer_len, _T("eqax d")); break; - case 0xfb: my_stprintf_s(buffer, buffer_len, _T("eqax h")); break; - case 0xfc: my_stprintf_s(buffer, buffer_len, _T("eqax d+")); break; - case 0xfd: my_stprintf_s(buffer, buffer_len, _T("eqax h+")); break; - case 0xfe: my_stprintf_s(buffer, buffer_len, _T("eqax d-")); break; - case 0xff: my_stprintf_s(buffer, buffer_len, _T("eqax h-")); break; -]]-- +return M From ae9951418344772189a7a3f9840028731cdc4c17 Mon Sep 17 00:00:00 2001 From: mooz Date: Sun, 18 Nov 2018 22:13:04 +0100 Subject: [PATCH 34/41] Added standalone version of the uPD7801 compiler. --- CMakeLists.txt | 34 +++++++ l7801.c | 222 +++++++++++++++++++++++++++++++++++++++++++ scv.l65 => scv.l7801 | 0 3 files changed, 256 insertions(+) create mode 100644 l7801.c rename scv.l65 => scv.l7801 (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c9469f..9aa4d46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,3 +117,37 @@ endif() target_link_libraries(embed ${LINKLIBS}) target_link_libraries(${PROJECT_NAME} ${LINKLIBS}) + +set(L7801_SOURCES + ${L65_SOURCE_DIR}/lfs.c + ${L65_SOURCE_DIR}/lpeg.c + ${L65_SOURCE_DIR}/l7801.c + ) +set(L7801_HEADERS + ${L65_HEADERS} + ) + +set(L7801_FILES ${L65_SOURCE_DIR}/scv.l7801) + +set(L7801_SCRIPTS + ${L65_SOURCE_DIR}/asm.lua + ${L65_SOURCE_DIR}/uPD7801.lua + ${L65_SOURCE_DIR}/dkjson.lua + ${L65_SOURCE_DIR}/l7801.lua + ${L65_BINARY_DIR}/l65cfg.lua + ${L65_SOURCE_DIR}/re.lua + ${L7801_FILES} + ) + +add_custom_command( + OUTPUT ${L65_BINARY_DIR}/scripts_7801.h + COMMAND embed -o ${L65_BINARY_DIR}/scripts_7801.h ${L7801_SCRIPTS} + DEPENDS embed ${L7801_SCRIPTS} +) +add_custom_target(prereq_7801 DEPENDS ${L65_BINARY_DIR}/scripts_7801.h) +add_executable(l7801 ${L7801_SOURCES} ${L7801_HEADERS} ${L7801_FILES}) +add_dependencies(l7801 prereq_7801) +set_property(TARGET l7801 PROPERTY C_STANDARD 99) +target_include_directories(l7801 PRIVATE "${L7801_SOURCE_DIR}" "${L65_BINARY_DIR}") +target_link_libraries(l7801 ${LINKLIBS}) + diff --git a/l7801.c b/l7801.c new file mode 100644 index 0000000..a403714 --- /dev/null +++ b/l7801.c @@ -0,0 +1,222 @@ +#include +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_NO_FAILURE_STRINGS +#include "stb_image.h" + +#define LUA_IMPLEMENTATION +#include "lua.h" +#include "scripts_7801.h" + +extern int luaopen_lpeg(lua_State *L); +extern int luaopen_lfs(lua_State *L); + +// l7801 lib +static int r_s32be(uint8_t **b) { uint8_t *p = *b; int v = ((int)(p[0]))<<24 | ((int)(p[1]))<<16 | ((int)p[2])<<8 | p[3]; *b += 4; return v; } +typedef struct { int len, nam; } chunk_s; +static chunk_s r_chunk(uint8_t **b) { int len = r_s32be(b), nam = r_s32be(b); chunk_s c = { len, nam }; return c; } +static int open_image(lua_State *L) +{ + const char *filename = luaL_checkstring(L, 1); + FILE *file = fopen(filename, "rb"); + if (!file) + { + lua_pushnil(L); + lua_pushfstring(L, "failed to open file %s", filename); + return 2; + } + fseek(file, 0, SEEK_END); + size_t sz = ftell(file); + fseek(file, 0, SEEK_SET); + uint8_t *png = malloc(sz); + fread(png, sz, 1, file); + fclose(file); + static uint8_t png_sig[8] = { 137,80,78,71,13,10,26,10 }; + if (memcmp(png, png_sig, 8) != 0) + { + free(png); + lua_pushnil(L); + lua_pushfstring(L, "file %s is not a PNG", filename); + return 2; + } + uint8_t *b = png + 8; + int w, h; + uint8_t *d = 0; long d_sz = 0; +#define CHUNK_NAM(a,b,c,d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + for (;;) + { + chunk_s chunk = r_chunk(&b); + switch (chunk.nam) + { + case CHUNK_NAM('I','H','D','R'): { + w = r_s32be(&b); h = r_s32be(&b); + if (b[0] != 8 || b[1] != 3) + { + free(png); + lua_pushnil(L); + lua_pushfstring(L, "PNG file %s must be 8b indexed", filename); + return 2; + } + b += 9; + } break; + case CHUNK_NAM('I','D','A','T'): { + d = realloc(d, d_sz + chunk.len); + memcpy(d + d_sz, b, chunk.len); + d_sz += chunk.len; + b += chunk.len+4; + } break; + case CHUNK_NAM('I','E','N','D'): { + free(png); + if (!d) + { + lua_pushnil(L); + lua_pushfstring(L, "invalid PNG file %s", filename); + return 2; + } + int px_sz; + uint8_t *px_raw = (uint8_t*)stbi_zlib_decode_malloc_guesssize_headerflag((void*)d, d_sz, (w+1) * h, &px_sz, 1); + free(d); + uint8_t *px = calloc(w,h); + uint8_t *px0 = px, *px_raw0 = px_raw; + for (int y = 0; y < h; ++y) + { + int filter = *px_raw++; + #define prev (x==0 ? 0 : px[x-1]) + #define up (px[x-w]) + #define prevup (x==0 ? 0 : px[x-w-1]) + switch (filter) + { + case 0: memcpy(px, px_raw, w); break; + case 1: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + prev; } break; + case 2: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + up; } break; + case 3: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + ((prev+up)>>1); } break; + case 4: for (int x = 0; x < w; ++x) { px[x] = px_raw[x] + stbi__paeth(prev,up,prevup); } break; + } + #undef prev + #undef up + #undef prevup + px += w; + px_raw += w; + } + STBI_FREE(px_raw0); + + lua_createtable(L, w*h, 3); + lua_pushstring(L, filename); + lua_setfield(L, -2, "filename"); + lua_pushinteger(L, w); + lua_setfield(L, -2, "width"); + lua_pushinteger(L, h); + lua_setfield(L, -2, "height"); + for (int i = 0; i < w*h; ++i) + { + lua_pushinteger(L, px0[i]); + lua_rawseti(L, -2, i+1); + } + free(px0); + return 1; + } + default: + b += chunk.len+4; + } + } +#undef CHUNK_NAM + if (d) free(d); + free(png); + lua_pushnil(L); + lua_pushfstring(L, "invalid PNG file %s", filename); + return 2; +} +static const struct luaL_Reg l7801lib[] = { + {"image", open_image}, + {NULL, NULL}, +}; +static int luaopen_l7801(lua_State *L) +{ + luaL_newlib(L, l7801lib); + return 1; +} + +#define SRC_LUA(name) { #name, 0, script_ ## name ## _lua, sizeof(script_ ## name ## _lua) } +#define SRC_L7801(name) { #name, 1, script_ ## name ## _l7801, sizeof(script_ ## name ## _l7801) } +static struct script { const char *name; int t; const char *data; size_t sz; } embedded[] = { + SRC_LUA(dkjson), + SRC_LUA(l65cfg), + SRC_LUA(re), + SRC_L7801(scv), +}; +#undef SRC_LUA +#undef SRC_L7801 + +static int getembedded(lua_State *L) +{ + const char *name = lua_tostring(L, 1); + for (struct script *s = embedded, *e = s + sizeof(embedded) / sizeof(embedded[0]); s != e; ++s) + { + if (!strcmp(s->name, name)) + { + lua_pushlstring(L, s->data, s->sz); + lua_pushboolean(L, s->t); + return 2; + } + } + return 0; +} + +static int msghandler(lua_State *L) +{ + const char *msg = lua_tostring(L, 1); + if (msg == NULL) + { + if (luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING) + return 1; + msg = lua_pushfstring(L, "(error object is a %s value)", luaL_typename(L, 1)); + } + luaL_traceback(L, L, msg, 1); + return 1; +} + +int main(int argc, char *argv[]) +{ + lua_State *L = luaL_newstate(); + luaL_openlibs(L); + luaL_requiref(L, "lpeg", luaopen_lpeg, 1); lua_pop(L, 1); + luaL_requiref(L, "lfs", luaopen_lfs, 1); lua_pop(L, 1); + luaL_requiref(L, "l7801", luaopen_l7801, 1); lua_pop(L, 1); + + // preload embedded lua scripts + luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); + luaL_loadbufferx(L, script_asm_lua, sizeof(script_asm_lua), "asm.lua", "b"); + lua_setfield(L, -2, "asm"); + luaL_loadbufferx(L, script_uPD7801_lua, sizeof(script_uPD7801_lua), "uPD7801.lua", "b"); + lua_setfield(L, -2, "uPD7801"); + lua_pop(L, 1); + + // error handler + lua_pushcfunction(L, msghandler); + // l65.lua script + luaL_loadbufferx(L, script_l7801_lua, sizeof(script_l7801_lua), "l7801.lua", "b"); + // arg[] table + lua_createtable(L, argc-1, 2); + lua_pushcfunction(L, getembedded); // pass embedded script lookup function as arg[-1] + lua_rawseti(L, -2, -1); + for (int i = 0; i < argc; i++) lua_pushstring(L, argv[i]), lua_rawseti(L, -2, i); + lua_pushvalue(L, -1); + lua_setglobal(L, "arg"); + // ... arguments + { int i; for (i = 1; i < argc; ++i) lua_rawgeti(L, -i, i); lua_remove(L, -i); } + // call l7801 + int status = lua_pcall(L, argc-1, 0, -argc-1); + if (status != LUA_OK) + { + const char *msg = lua_tostring(L, -1); + fprintf(stderr, "%s\n", msg); + lua_pop(L, 1); + } + lua_pop(L, 1); // remove msghandler + lua_close(L); + return status; +} + diff --git a/scv.l65 b/scv.l7801 similarity index 100% rename from scv.l65 rename to scv.l7801 From 7bfb04cf8689c8fb81a638e5491d8ab5b57429d1 Mon Sep 17 00:00:00 2001 From: mooz Date: Mon, 19 Nov 2018 18:39:09 +0100 Subject: [PATCH 35/41] Added appveyor configuration file. --- appveyor.yaml | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 appveyor.yaml diff --git a/appveyor.yaml b/appveyor.yaml new file mode 100644 index 0000000..5975721 --- /dev/null +++ b/appveyor.yaml @@ -0,0 +1,41 @@ +version: '0.1.{build}' + +os: Visual Studio 2013 +platform: x64 +configuration: Release + +before_build: + - mkdir install + - mkdir build + - cd build + - cmake -G "Visual Studio 12 2013 Win64" -DCMAKE_INSTALL_PREFIX=../install + +build_script: + - FOR /F "tokens=*" %%i in ('git describe') do SET COMMITNOW=%%i + - if defined APPVEYOR_REPO_TAG_NAME (set L65_RELEASE=true) else (set L65_SNAPSHOT=true) + - if defined L65_RELEASE set L65_VERSION=%APPVEYOR_REPO_TAG_NAME:~1% + - if defined L65_RELEASE echo Building l65 %L65_VERSION%... (from %COMMITNOW%) + - if defined L65_SNAPSHOT set L65_VERSION=%APPVEYOR_BUILD_VERSION% + - if defined L65_SNAPSHOT echo Building l65 snapshot %L65_VERSION%... (from %COMMITNOW%) + - cmake --build . --config Release + - cmake --build . --config Release --target install + +after_build: + - cd ../install + - 7z a ../l65.zip * -tzip + +artifacts: + - path: l65.zip + name: l65-${L65_VERSION}.zip + +deploy: + - provider: GitHub + release: l65-${L65_VERSION} + description: 'l65 msvc12 win64 build' + auth_token: + secure: xRIravp3mvMiAgogn6KGuK1yrolmSJUsum/wPXwu82bh97O7YkuQ3B178ac+WHml + artifact: /l65.*\.zip/ + draft: true + on: + appveyor_repo_tag: true + push_release: true From d6254b2ca3215b60a577ceba7ed700e0fd438243 Mon Sep 17 00:00:00 2001 From: mooz Date: Mon, 19 Nov 2018 18:53:02 +0100 Subject: [PATCH 36/41] Fixed extension. --- appveyor.yaml => appveyor.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appveyor.yaml => appveyor.yml (100%) diff --git a/appveyor.yaml b/appveyor.yml similarity index 100% rename from appveyor.yaml rename to appveyor.yml From 18faa0ba34f6fbd779ff0c6cb1473cd2fb8d41c8 Mon Sep 17 00:00:00 2001 From: mooz Date: Mon, 19 Nov 2018 19:00:37 +0100 Subject: [PATCH 37/41] Fixed cmake invokation in appveyor configuration file. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5975721..d9a746b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ before_build: - mkdir install - mkdir build - cd build - - cmake -G "Visual Studio 12 2013 Win64" -DCMAKE_INSTALL_PREFIX=../install + - cmake -G "Visual Studio 12 2013 Win64" -DCMAKE_INSTALL_PREFIX=../install .. build_script: - FOR /F "tokens=*" %%i in ('git describe') do SET COMMITNOW=%%i From 8f5e37dd820951cdf822e7867f6914da86d5c003 Mon Sep 17 00:00:00 2001 From: mooz Date: Mon, 19 Nov 2018 19:18:44 +0100 Subject: [PATCH 38/41] Added install configuration. --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9aa4d46..df1762b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,3 +151,8 @@ set_property(TARGET l7801 PROPERTY C_STANDARD 99) target_include_directories(l7801 PRIVATE "${L7801_SOURCE_DIR}" "${L65_BINARY_DIR}") target_link_libraries(l7801 ${LINKLIBS}) + +install(TARGETS l65 l7801 + RUNTIME DESTINATION bin) +install(DIRECTORY samples DESTINATION doc) +install(FILES README.md DESTINATION doc) From fa59803eeba977f7fab93a27f145d4464dea669e Mon Sep 17 00:00:00 2001 From: mooz Date: Mon, 19 Nov 2018 23:15:46 +0100 Subject: [PATCH 39/41] Fixed JR instruction. --- CMakeLists.txt | 2 +- l7801.c | 4 ++-- scv.l7801 => scv.l65 | 0 uPD7801.lua | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename scv.l7801 => scv.l65 (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index df1762b..8be35fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,7 @@ set(L7801_HEADERS ${L65_HEADERS} ) -set(L7801_FILES ${L65_SOURCE_DIR}/scv.l7801) +set(L7801_FILES ${L65_SOURCE_DIR}/scv.l65) set(L7801_SCRIPTS ${L65_SOURCE_DIR}/asm.lua diff --git a/l7801.c b/l7801.c index a403714..18c6442 100644 --- a/l7801.c +++ b/l7801.c @@ -140,12 +140,12 @@ static int luaopen_l7801(lua_State *L) } #define SRC_LUA(name) { #name, 0, script_ ## name ## _lua, sizeof(script_ ## name ## _lua) } -#define SRC_L7801(name) { #name, 1, script_ ## name ## _l7801, sizeof(script_ ## name ## _l7801) } +#define SRC_L65(name) { #name, 1, script_ ## name ## _l65, sizeof(script_ ## name ## _l65) } static struct script { const char *name; int t; const char *data; size_t sz; } embedded[] = { SRC_LUA(dkjson), SRC_LUA(l65cfg), SRC_LUA(re), - SRC_L7801(scv), + SRC_L65(scv), }; #undef SRC_LUA #undef SRC_L7801 diff --git a/scv.l7801 b/scv.l65 similarity index 100% rename from scv.l7801 rename to scv.l65 diff --git a/uPD7801.lua b/uPD7801.lua index e02c77d..7f85bfd 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -245,7 +245,7 @@ M.jr = function(label) if x < -32 or x > 0x32 then error("branch target out of range for " .. l .. ": " .. x) elseif x >= 0 then x = 0xc0 + x - return + return x else return x & 0xff end From f2ab52c0ae40932a9aac81b9a8f0e0638e194a3f Mon Sep 17 00:00:00 2001 From: mooz Date: Mon, 19 Nov 2018 23:16:33 +0100 Subject: [PATCH 40/41] Added Plogue uPD1771C Tester by David Viens (@plgDavid). --- samples/scv_plogue_tester.l65 | 498 ++++++++++++++++++++++++++++++++++ 1 file changed, 498 insertions(+) create mode 100644 samples/scv_plogue_tester.l65 diff --git a/samples/scv_plogue_tester.l65 b/samples/scv_plogue_tester.l65 new file mode 100644 index 0000000..1135397 --- /dev/null +++ b/samples/scv_plogue_tester.l65 @@ -0,0 +1,498 @@ +---------------------------------------------------------------- +-- Plogue uPD1771C Tester +-- BY David Viens january 2010 chipsounds R&D +-- (from Hello World! Program Ver 1.1 by) Programmed By Enri +-- haxored to emit 7801 instructions using +-- Macro Assembler AS V1.42's 7810 mode +-- http://john.ccac.rwth-aachen.de:8000/as +-- Converted to l65 +---------------------------------------------------------------- + +require 'scv' +location(0x8000, 0x9fff) +section{"rom", org=0x8000} + dc.b 'H' -- Headder + +-- 0FF8X seems reserved, but not FF9X +local PARAMS = 0xFF90 +local ACTIVE_PARAM = 0xFF9A +local PLAYING = 0xFF9B + +------------------------- +-- Clear Text All Area -- +------------------------- + calt 0x8c -- bios function!!! + +------------- +-- Set VDC -- +------------- + lxi hl,VDC_DATA + lxi de,0x3400 + mvi c,0x03 + block + +--------------------- +-- Set INITIAL RAM -- +--------------------- + lxi hl,INITIAL_RAM + lxi de,PARAMS + mvi c,0x0F + block + +-------------------------------------------------------------- +----------------- END INITIALISATION POUTINE ----------------- +-------------------------------------------------------------- + +------------------------- +-- Print Screen Format -- +------------------------- + lxi hl,DISPLAY_DATA + lxi de,0x3040 -- Text RAM Address + lxi bc,0x0180 +@LOOP0 + block + dcr b + jr LOOP0 + +-------------------------------------------------------------- +------------------------- MAIN LOOP ------------------------- +-------------------------------------------------------------- +@LOOPN + -- reposition pointer to current param + lxi hl,PARAMS + mov b,(ACTIVE_PARAM) + dcx hl +@POSITIONLOOP + inx hl + dcr b + jmp POSITIONLOOP + + + lxi de,0x3090 + -- SLEEP before note + mvi c,0x10 -- wait 1 second of vblanks + call SLEEPFUNC + + + mvi a,0xFD -- we want to store that into PA so that portB can be later scanned i guess like the vic/c64 kb + mov pa,a + mov a,pb -- see which are closed upon return + + oni a,2 + jr RIGHT_DOWN + jr RIGHT_END +@RIGHT_DOWN + ldax (hl) + adi a,1 + stax (hl) + + -- if playing replay patter + mov a,(PLAYING) + eqi a,1 + jmp ALL_DONE + -- fake not already playing + mvi a,0 + mov (PLAYING),a -- ON + call PLAY_PATTERN + jmp ALL_DONE + +@RIGHT_END + + oni a,1 + jr DOWN_DOWN + jr DOWN_END +@DOWN_DOWN + mov a,(ACTIVE_PARAM) + adi a,1 + mov (ACTIVE_PARAM),a + jmp ALL_DONE +@DOWN_END + + mvi a,0xFE + mov pa,a -- fill port with voltages + mov a,pb -- see which are closed upon return + + oni a,1 + jr LEFT_DOWN + jr LEFT_END +@LEFT_DOWN + ldax (hl) + sui a,1 + stax (hl) + + -- if playing replay patter + mov a,(PLAYING) + eqi a,1 + jmp ALL_DONE + -- fake not already playing + mvi a,0 + mov (PLAYING),a -- OFF + call PLAY_PATTERN + jmp ALL_DONE +@LEFT_END + + oni a,2 + jr UP_DOWN + jr UP_END +@UP_DOWN + mov a,(ACTIVE_PARAM) + sui a,1 + mov (ACTIVE_PARAM),a + jmp ALL_DONE +@UP_END + + oni a,4 + jr BUTTON_DOWN + jr BUTTON_UP +@BUTTON_DOWN + call PLAY_PATTERN + jmp ALL_DONE +@BUTTON_UP + call STOP_PATTERN + jr BUTTON_END +@BUTTON_END + +@ALL_DONE + + -- check bounds on active param + mov a,(ACTIVE_PARAM) + lti a,0x0A + jr ACT_GREATER + jr ACT_DONE +@ACT_GREATER + mvi a,0x00 + mov (ACTIVE_PARAM),a + jr ACT_DONE +@ACT_DONE + + -- print where we at! + call DISPLAY_LOOP + + jmp LOOPN + +------------------------------------------------------------------------- +-- Display init data +------------------------------------------------------------------------- +@VDC_DATA + dc.b 0xC0,0x00,0x00,0xF1 -- 0F1 -> black + +------------------------------------------------------------------------- +-- lame sleep (with C param) +------------------------------------------------------------------------- +section{"SLEEPFUNC", org=0x8100} +-- sleep the amount of time depending on C + push bc +@SLOOP + mvi b,0xff +@SLEEP0 + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + dcr b + jr SLEEP0 + dcr c + jr SLOOP + pop bc + ret + +------------------------------------------------------------------------- +-- wait on VBLANK +------------------------------------------------------------------------- +section{"WVBLANK", org=0x8200} + skit f2 -- wait until acknowledged + jr WVBLANK + ret + +------------------------------------------------------------------------- +-- wait on D1771g (wait until INT1=1) +------------------------------------------------------------------------- +section{"WD1771G", org=0x8220} + skit f1 + jr WD1771G + ret + +------------------------------------------------------------------------- +-- Print ONE UINT8_T on screen as HEX (two screen chars printed) +-- +-- A should contain the hex value to print (A returns unchanged) +-- D should contain the screen value to dump the high part (D returns unchanged) +-- V is thrashed (used as temporary val) +------------------------------------------------------------------------- +section{"PRINT_HEX", org=0x8240} + mvi v,0 -- trick to do V=A + add v,a -- trick to do V=A + + ani a,0xF0 -- a = a & 0x0f; + clc -- clear carry so not to fuck up the following right shifts + rlr a -- + rlr a -- + rlr a -- + rlr a -- ok we got the HEX value for the up 4bits + + gti a,0x09 + jr HIGH_GREATER + jr HIGH_LOWER +@HIGH_GREATER + adi a,0x30 -- a+='0' (ascii) + jr HIGH_DONE +@HIGH_LOWER + adi a,0x37 -- a+=('A'-10) (ascii) + jr HIGH_DONE +@HIGH_DONE + + staxi (de) -- + + mvi a,0 -- trick to do A=V + add a,v -- trick to do A=V + ani a,0x0F -- a = a & 0x0f + + gti a,0x09 + jr LOW_GREATER + jr LOW_LOWER +@LOW_GREATER + adi a,0x30 -- a+='0' (ascii) + jr LOW_DONE +@LOW_LOWER + adi a,0x37 -- a+=('A'-10) (ascii) + jr LOW_DONE +@LOW_DONE + + staxd (de) -- + mvi a,0 -- trick to do A=V + add a,v -- trick to do A=V + ret + +------------------------------------------------------------------------- +-- Prints all current param values +------------------------------------------------------------------------- +section{"DISPLAY_LOOP", org=0x8280} + mvi b,0x0B + lxi de,0x3090 + lxi hl,PARAMS +@DLOOP + + -- if b==ACTIVE_PARAM show arrow + -- else show space + mvi a,0x0B + mov c,(ACTIVE_PARAM) + sub a,c + + eqa a,b + jr NOCURSOR + mvi a,0x1C + stax (de) + jr CURSDONE +@NOCURSOR + mvi a,0x20 + stax (de) +@CURSDONE + -- print all ram + ldaxi (hl) + -- increase D pos to display in hex + inx de + inx de + inx de + call PRINT_HEX + dcx de + dcx de + dcx de + + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + inx de + + dcr b + jmp DLOOP + ret + +------------------------------------------------------------------------- +-- Stop current pattern +------------------------------------------------------------------------- +section{"STOP_PATTERN", org=0x82d0} + -- if (!playing) return; + mov a,(PLAYING) + eqi a,1 + jr STOP_DONE + + mvi a,0 + mov (PLAYING),a -- OFF + + di + lxi hl,0x3600 -- SOUND REGISTER in H + call WVBLANK -- cwait on intf2 + skit f1 + nop + + mvix (hl),0x00 -- note OFF + + ei + +@STOP_DONE + ret + +------------------------------------------------------------------------- +-- Plays current pattern +-- Start with beep please +------------------------------------------------------------------------- +section{"PLAY_PATTERN", org=0x82f0} + mov a,(PLAYING) + eqi a,0 + jmp PLAY_DONE + + -- setting variable true! + mvi a,1 + mov (PLAYING),a -- ON + + lxi de,PARAMS + lxi hl,0x3600 -- SOUND REGISTER in H + + + ldaxi (de) + eqi a,1 + jmp PLAY_TONE + jmp PLAY_NOISE + +@PLAY_TONE + ------------------------ Tone Start ------------------------ + di + call WVBLANK + skit f1 + nop + -- instrument params start + mvi a,2 -- tone! + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WVBLANK -- cwait on intf2 + -- instrument params end + ei + jmp PLAY_DONE + +@PLAY_NOISE + ------------------------ Tone Start ------------------------ + di + call WVBLANK -- cwait on intf2 + skit f1 + nop + -- instrument params start + mvi a,1 -- NOISE + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WD1771G -- cwait on intf1 + ldaxi (de) + stax (hl) + call WVBLANK -- cwait on intf2 + -- instrument params end + ei + jmp PLAY_DONE + +@PLAY_DONE + ret + +------------------------------------------------------------------------- +-- Message Data1 +-- this version has left+audio changes working +------------------------------------------------------------------------- +@DISPLAY_DATA + dc.b " Plogue uPD1771C Tester " + dc.b " v0.0018 " + dc.b " Param[0]: ( ) " + dc.b " Param[1]: ( ) " + dc.b " Param[2]: ( ) " + dc.b " Param[3]: ( ) " + dc.b " Param[4]: ( ) " + dc.b " Param[5]: ( ) " + dc.b " Param[6]: ( ) " + dc.b " Param[7]: ( ) " + dc.b " Param[8]: ( ) " + dc.b " Param[9]: ( ) " + + -- go to [FF90;FF9F] +@INITIAL_RAM + -- params + dc.b 0x02 + dc.b 0x80 + dc.b 0xFF + dc.b 0x1F + + dc.b 0xAB + dc.b 0xFE + dc.b 0xCD + dc.b 0xDC + dc.b 0x45 + dc.b 0x01 + + dc.b 0x00 -- FF9A curent param + dc.b 0x00 -- FF9B BOOL note on + dc.b 0x83 -- misc + dc.b 0x39 -- misc + dc.b 0x44 -- misc + dc.b 0x36 -- misc + +writebin(filename..'.bin', genbin(0xff)) From 52a5777949f2e83e062b6f556c60492e762ef97b Mon Sep 17 00:00:00 2001 From: mooz Date: Wed, 21 Nov 2018 21:21:07 +0100 Subject: [PATCH 41/41] =?UTF-8?q?Use=20l7801=20extension=20for=20=C2=B5PD7?= =?UTF-8?q?801=20compiler.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 1 + CMakeLists.txt | 2 +- l7801.c | 4 +- l7801.lua | 114 +++++++++--------- samples/{scv_hello.l65 => scv_hello.l7801} | 0 ...gue_tester.l65 => scv_plogue_tester.l7801} | 0 samples/{scv_test.l65 => scv_test.l7801} | 0 scv.l65 => scv.l7801 | 0 uPD7801.lua | 68 +++++------ 9 files changed, 95 insertions(+), 94 deletions(-) rename samples/{scv_hello.l65 => scv_hello.l7801} (100%) rename samples/{scv_plogue_tester.l65 => scv_plogue_tester.l7801} (100%) rename samples/{scv_test.l65 => scv_test.l7801} (100%) rename scv.l65 => scv.l7801 (100%) diff --git a/.travis.yml b/.travis.yml index e67f384..ad3969b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ script: - cmake . -DCMAKE_BUILD_TYPE=Release - make - cd samples; for f in *.l65; do echo $f; ../l65 $f || break; done; cd .. + - cd samples; for f in *.l7801; do echo $f; ../l7801 $f || break; done; cd .. - cp l65 l65-$TRAVIS_TAG-$TRAVIS_OS_NAME deploy: provider: releases diff --git a/CMakeLists.txt b/CMakeLists.txt index 8be35fe..df1762b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,7 +127,7 @@ set(L7801_HEADERS ${L65_HEADERS} ) -set(L7801_FILES ${L65_SOURCE_DIR}/scv.l65) +set(L7801_FILES ${L65_SOURCE_DIR}/scv.l7801) set(L7801_SCRIPTS ${L65_SOURCE_DIR}/asm.lua diff --git a/l7801.c b/l7801.c index 18c6442..a403714 100644 --- a/l7801.c +++ b/l7801.c @@ -140,12 +140,12 @@ static int luaopen_l7801(lua_State *L) } #define SRC_LUA(name) { #name, 0, script_ ## name ## _lua, sizeof(script_ ## name ## _lua) } -#define SRC_L65(name) { #name, 1, script_ ## name ## _l65, sizeof(script_ ## name ## _l65) } +#define SRC_L7801(name) { #name, 1, script_ ## name ## _l7801, sizeof(script_ ## name ## _l7801) } static struct script { const char *name; int t; const char *data; size_t sz; } embedded[] = { SRC_LUA(dkjson), SRC_LUA(l65cfg), SRC_LUA(re), - SRC_L65(scv), + SRC_L7801(scv), }; #undef SRC_LUA #undef SRC_L7801 diff --git a/l7801.lua b/l7801.lua index a7f086e..491c667 100644 --- a/l7801.lua +++ b/l7801.lua @@ -2131,7 +2131,7 @@ local function ParseLua(src, src_name) end -local function Format65(ast) +local function Format7801(ast) local function splitLines(str) if str:match("\n") then local lines = {} @@ -2538,34 +2538,34 @@ local function Format65(ast) end local dirsep = package.config:sub(1,1) -local dirl65 = (string.match(arg[0], "(.*[\\/]).*") or ''):gsub('/',dirsep) -local searchl65 = '' -if #dirl65 > 0 then - searchl65 = string.format(";%s?;%s?.l65", dirl65, dirl65) - package.path = package.path .. string.format(";%s?.lua", dirl65) +local dirl7801 = (string.match(arg[0], "(.*[\\/]).*") or ''):gsub('/',dirsep) +local searchl7801 = '' +if #dirl7801 > 0 then + searchl7801 = string.format(";%s?;%s?.l7801", dirl7801, dirl7801) + package.path = package.path .. string.format(";%s?.lua", dirl7801) end -l65_def = { +l7801_def = { parse = ParseLua, - format = Format65, + format = Format7801, searcher_index = 2, - search_path = string.format(".%s?;.%s?.l65%s", dirsep, dirsep, searchl65), + search_path = string.format(".%s?;.%s?.l7801%s", dirsep, dirsep, searchl7801), load_org = load, loadfile_org = loadfile, dofile_org = dofile, } -if not l65 then l65 = l65_def else for k,v in pairs(l65_def) do l65[k]=v end end -l65.report = function(success, ...) +if not l7801 then l7801 = l7801_def else for k,v in pairs(l7801_def) do l7801[k]=v end end +l7801.report = function(success, ...) if success then return success,... end local message=... io.stderr:write(tostring(message)..'\n') os.exit(-1) end -l65.msghandler = function(msg) +l7801.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 + msg = msg:gsub('%[string "(.-%.l7801)"%]', '%1') -- [string "xxx.l7801"] -> xxx.l7801 local trace_cur = debug.traceback(nil, 2) - trace_cur = trace_cur:gsub('%[string "(.-%.l65)"%]', '%1') -- [string "xxx.l65"] -> xxx.l65 + trace_cur = trace_cur:gsub('%[string "(.-%.l7801)"%]', '%1') -- [string "xxx.l7801"] -> xxx.l7801 trace_cur = trace_cur:gsub('stack traceback:', '') local i=2 @@ -2574,7 +2574,7 @@ l65.msghandler = function(msg) while true do local n,v = debug.getlocal(i, j) if not n then break end - if n == 'l65dbg' then + if n == 'l7801dbg' then o(string.format("%s\n", msg)) if trace_cur:find("in local 'late'") then local lines = {} @@ -2585,7 +2585,7 @@ l65.msghandler = function(msg) o(table.concat(lines,'\n')) end local trace = v.trace:match(".-\n(.*)\n.-'xpcall'") - trace = trace:gsub('%[string "(.-%.l65)"%]', '%1') + trace = trace:gsub('%[string "(.-%.l7801)"%]', '%1') trace = trace:gsub('stack traceback:', '') o(trace .. '\n') os.exit(-2) @@ -2601,32 +2601,32 @@ l65.msghandler = function(msg) end do local getembedded = type(arg[-1]) == 'function' and arg[-1] - l65.load_embedded = function(name) + l7801.load_embedded = function(name) if not getembedded then return end - local src,isl65 = getembedded(name) + local src,isl7801 = getembedded(name) if not src then return end - if isl65 then - name = name .. '.l65' - local st, ast = l65.report(l65.parse(src, name)) - src = l65.format(ast) + if isl7801 then + name = name .. '.l7801' + local st, ast = l7801.report(l7801.parse(src, name)) + src = l7801.format(ast) else name = name .. '.lua' end - local bc = assert(l65.load_org(src, name)) + local bc = assert(l7801.load_org(src, name)) return bc, name end end -l65.searcher = function(name) - local filename,err = package.searchpath(name, l65.search_path, '.', '.') +l7801.searcher = function(name) + local filename,err = package.searchpath(name, l7801.search_path, '.', '.') if not filename then return err end local file = assert(io.open(filename, 'rb')) local src = file:read('*a') file:close() - local st, ast = l65.report(l65.parse(src, filename)) - local bc = assert(l65.load_org(l65.format(ast), filename)) + local st, ast = l7801.report(l7801.parse(src, filename)) + local bc = assert(l7801.load_org(l7801.format(ast), filename)) return bc, filename end -l65.load = function(chunk, chunkname, mode, ...) +l7801.load = function(chunk, chunkname, mode, ...) local chunk_t,s = type(chunk) if chunk_t == 'string' then s = chunk elseif chunk_t == 'function' then @@ -2635,12 +2635,12 @@ l65.load = function(chunk, chunkname, mode, ...) else return nil, string.format("invalid type for chunk %s: %s", chunkname or "=(load)", chunk_t) end if s:sub(1,4) == "\x1bLua" then -- a binary file - return l65.load_org(s, chunkname, mode, ...) + return l7801.load_org(s, chunkname, mode, ...) end - local st, ast = l65.report(l65.parse(s, chunkname or "=(load)")) - return l65.load_org(l65.format(ast), chunkname, 't', ...) + local st, ast = l7801.report(l7801.parse(s, chunkname or "=(load)")) + return l7801.load_org(l7801.format(ast), chunkname, 't', ...) end -l65.loadfile = function(filename, mode, ...) +l7801.loadfile = function(filename, mode, ...) local s if not filename then s = io.read('*a') else @@ -2649,34 +2649,34 @@ l65.loadfile = function(filename, mode, ...) s = file:read('*a') file:close() end - return l65.load(s, filename, mode, ...) + return l7801.load(s, filename, mode, ...) end -l65.dofile = function(filename) - local f = l65.report(l65.loadfile(filename)) +l7801.dofile = function(filename) + local f = l7801.report(l7801.loadfile(filename)) return f() end -l65.installhooks = function() - if package.searchers[l65.searcher_index] ~= l65.searcher then - table.insert(package.searchers, l65.searcher_index, l65.searcher) +l7801.installhooks = function() + if package.searchers[l7801.searcher_index] ~= l7801.searcher then + table.insert(package.searchers, l7801.searcher_index, l7801.searcher) end - if not l65.hooks_installed then l65.hooks_installed = true - load = l65.load - loadfile = l65.loadfile - dofile = l65.dofile + if not l7801.hooks_installed then l7801.hooks_installed = true + load = l7801.load + loadfile = l7801.loadfile + dofile = l7801.dofile end end -l65.uninstallhooks = function() +l7801.uninstallhooks = function() for k,v in ipairs(package.searchers) do - if v == l65.searcher then table.remove(package.searchers, k) break end + if v == l7801.searcher then table.remove(package.searchers, k) break end end - if l65.hooks_installed then l65.hooks_installed = nil - load = l65.load_org - loadfile = l65.loadfile_org - dofile = l65.dofile_org + if l7801.hooks_installed then l7801.hooks_installed = nil + load = l7801.load_org + loadfile = l7801.loadfile_org + dofile = l7801.dofile_org end end -table.insert(package.searchers, l65.searcher_index, l65.load_embedded) -l65.installhooks() +table.insert(package.searchers, l7801.searcher_index, l7801.load_embedded) +l7801.installhooks() function getopt(optstring, ...) local opts = { } @@ -2712,16 +2712,16 @@ function getopt(optstring, ...) end) end -local cfg=require"l65cfg" l65.cfg=cfg +local cfg=require"l65cfg" l7801.cfg=cfg local version = function() - print(string.format("l65 %s", cfg.version)) + print(string.format("l7801 %s", cfg.version)) end local usage = function(f) if not f then f = io.stdout end f:write(string.format([[ Usage: %s [options] file [args] Options: - -d Dump the Lua code after l65 parsing into file + -d Dump the Lua code after l7801 parsing into file -h Display this information -v Display the release version ]], arg[0])) @@ -2740,12 +2740,12 @@ for opt,arg,i in getopt("d:hv", ...) do if opt == false then inf=arg optix=i+1 break end end if not inf then return invalid_usage() end -if dump then l65.format = function(ast) - local s=Format65(ast) l65.format = Format65 +if dump then l7801.format = function(ast) + local s=Format7801(ast) l7801.format = Format7801 local f = assert(io.open(dump, 'wb')) f:write(s) f:close() return s end end local fn='' for i=#inf,1,-1 do local c=inf:sub(i,i) if c==dirsep or c=='/' then break end fn=c..fn if c=='.' then fn='' end end filename=fn -local f = l65.report(l65.loadfile(inf)) -return xpcall(f, l65.msghandler, select(optix, ...)) +local f = l7801.report(l7801.loadfile(inf)) +return xpcall(f, l7801.msghandler, select(optix, ...)) diff --git a/samples/scv_hello.l65 b/samples/scv_hello.l7801 similarity index 100% rename from samples/scv_hello.l65 rename to samples/scv_hello.l7801 diff --git a/samples/scv_plogue_tester.l65 b/samples/scv_plogue_tester.l7801 similarity index 100% rename from samples/scv_plogue_tester.l65 rename to samples/scv_plogue_tester.l7801 diff --git a/samples/scv_test.l65 b/samples/scv_test.l7801 similarity index 100% rename from samples/scv_test.l65 rename to samples/scv_test.l7801 diff --git a/scv.l65 b/scv.l7801 similarity index 100% rename from scv.l65 rename to scv.l7801 diff --git a/uPD7801.lua b/uPD7801.lua index 7f85bfd..4aee978 100644 --- a/uPD7801.lua +++ b/uPD7801.lua @@ -111,9 +111,9 @@ local opregxx ={ } M.opregxx = opregxx for k,v in pairs(opregxx) do M[k] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + local bin = function() local l7801dbg=l7801dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end @@ -138,9 +138,9 @@ local opaxx ={ } M.opaxx = opaxx for k,v in pairs(opaxx) do M[k .. 'a'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + local bin = function() local l7801dbg=l7801dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end @@ -165,9 +165,9 @@ local opw = { } M.opw = opw for k,v in pairs(opw) do M[k .. 'imm'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 3 end - local bin = function() local l65dbg=l65dbg + local bin = function() local l7801dbg=l7801dbg local x = M.op_eval_word(late,early) return { v.opc, x&0xff, x>>8 } end @@ -183,9 +183,9 @@ local opr16w = { } M.opr16w = opr16w for k,v in pairs(opr16w) do M[k] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 3 end - local bin = function() local l65dbg=l65dbg + local bin = function() local l7801dbg=l7801dbg local x = M.op_eval_word(late,early) return { v.opc, x&0xff, x>>8 } end @@ -195,11 +195,11 @@ end M['calt' .. 'imm'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local op = { cycles=19 } op.size = function() late,early = M.size_op(late,early) return 1 end op.bin = function() - local l65dbg=l65dbg + local l7801dbg=l7801dbg local x = M.op_eval_byte(late,early) if (x%2 == 1) then error("offset should be even : " .. x) end if x < 0x80 or x > 0xfe then error("offset out of range : " .. x) end @@ -210,10 +210,10 @@ M['calt' .. 'imm'] = function(late, early) end M['calf' .. 'imm'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local op = { cycles=16 } op.size = function() late,early = M.size_op(late,early) return 2 end - op.bin = function() local l65dbg=l65dbg + op.bin = function() local l7801dbg=l7801dbg local x = 0 + M.op_eval_word(late,early) if x < 0x0800 or x > 0xffff then error("subroutine address out of range [0x0800-0xffff]: " .. x) end x = x - 0x0800; @@ -223,7 +223,7 @@ M['calf' .. 'imm'] = function(late, early) end M.jr = function(label) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local parent,offset = M.label_current local section,rorg = M.section_current,M.location_current.rorg local op = { cycles=13 } @@ -233,7 +233,7 @@ M.jr = function(label) return 1 end op.bin = function() - local l65dbg=l65dbg + local l7801dbg=l7801dbg local x,l = label,label if type(x) == 'function' then x=x() end if type(x) == 'string' then @@ -254,7 +254,7 @@ M.jr = function(label) end M.jre = function(label) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local parent,offset = M.label_current local section,rorg = M.section_current,M.location_current.rorg local op = { cycles=17 } @@ -264,7 +264,7 @@ M.jre = function(label) return 2 end op.bin = function() - local l65dbg=l65dbg + local l7801dbg=l7801dbg local x,l = label,label if type(x) == 'function' then x=x() end if type(x) == 'string' then @@ -296,9 +296,9 @@ local opwa = { } M.opwa = opwa for k,v in pairs(opwa) do M[k .. 'wa'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 2 end - local bin = function() local l65dbg=l65dbg return { v.opc, M.op_eval_byte(late,early) } end + local bin = function() local l7801dbg=l7801dbg return { v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end @@ -309,14 +309,14 @@ local opwaxx = { } M.opwaxx = opwaxx for k,v in pairs(opwaxx) do M[k .. 'waxx'] = function(late_offset, late_data, early_offset, early_data) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late_offset,early_offset = M.size_op(late_offset,early_offset) late_data,early_data = M.size_op(late_data,early_data) return 3 end local bin = function() - local l65dbg=l65dbg + local l7801dbg=l7801dbg return { v.opc, M.op_eval_byte(late_offset,early_offset), M.op_eval_byte(late_data,early_data) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) @@ -401,10 +401,10 @@ local opinout={ } M.opinout = op4inout for k,v in pairs(opinout) do M[k .. 'imm'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local op = { cycles=v.cycles } op.size = function() late,early = M.size_op(late,early) return 2 end - op.bin = function() local l65dbg=l65dbg + op.bin = function() local l7801dbg=l7801dbg local x = 0x00 + M.op_eval_byte(late,early) return { v.opc, 0x00, x } end @@ -492,10 +492,10 @@ for i,o in ipairs(op64names) do if not M[name] then local l = k M[name] = function(late,early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local op = { cycles=11 } op.size = function() late,early = M.size_op(late,early) return 3 end - op.bin = function() local l65dbg=l65dbg + op.bin = function() local l7801dbg=l7801dbg local x = 0x00 + l; local y = 0x00 + M.op_eval_byte(late,early) return { 0x64, x, y } @@ -515,10 +515,10 @@ for i,o in ipairs(op64names) do if not M[name] then local l = k M[name] = function(late,early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local op = { cycles=11 } op.size = function() late,early = M.size_op(late,early) return 3 end - op.bin = function() local l65dbg=l65dbg + op.bin = function() local l7801dbg=l7801dbg local x = 0x00 + l; local y = 0x00 + M.op_eval_byte(late,early) return { 0x64, x, y } @@ -550,9 +550,9 @@ local op74wa = { } M.op74wa = op74wa for k,v in pairs(op74wa) do M[k .. 'wa'] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 3 end - local bin = function() local l65dbg=l65dbg return { 0x74, v.opc, M.op_eval_byte(late,early) } end + local bin = function() local l7801dbg=l7801dbg return { 0x74, v.opc, M.op_eval_byte(late,early) } end table.insert(M.section_current.instructions, { size=size, cycles=v.cycles, bin=bin }) end end @@ -569,9 +569,9 @@ local op70ind = { } M.op70ind = op70ind for k,v in pairs(op70ind) do M[k] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 4 end - local bin = function() local l65dbg=l65dbg + local bin = function() local l7801dbg=l7801dbg local x = M.op_eval_word(late,early) return { 0x70, v.opc, x&0xff, x>>8 } end @@ -591,9 +591,9 @@ local op70indr8 = { } M.op70indr8 = op70indr8 for k,v in pairs(op70indr8) do M[k] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 4 end - local bin = function() local l65dbg=l65dbg + local bin = function() local l7801dbg=l7801dbg local x = M.op_eval_word(late,early) return { 0x70, v.opc, x&0xff, x>>8 } end @@ -613,9 +613,9 @@ local op70r8ind = { } M.op70r8ind = op70r8ind for k,v in pairs(op70r8ind) do M[k] = function(late, early) - local l65dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } + local l7801dbg = { info=debug.getinfo(2, 'Sl'), trace=debug.traceback(nil, 1) } local size = function() late,early = M.size_op(late,early) return 4 end - local bin = function() local l65dbg=l65dbg + local bin = function() local l7801dbg=l7801dbg local x = M.op_eval_word(late,early) return { 0x70, v.opc, x&0xff, x>>8 } end