Merge pull request #1 from BlockoS/master

Added support for µPD7801
This commit is contained in:
g012 2018-11-21 21:25:29 +01:00 committed by GitHub
commit 5105f8bd8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 5895 additions and 892 deletions

View File

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

982
6502.lua

File diff suppressed because it is too large Load Diff

View File

@ -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
@ -116,3 +117,42 @@ 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})
install(TARGETS l65 l7801
RUNTIME DESTINATION bin)
install(DIRECTORY samples DESTINATION doc)
install(FILES README.md DESTINATION doc)

41
appveyor.yml Normal file
View File

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

826
asm.lua Normal file
View File

@ -0,0 +1,826 @@
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<<i) == 0 then lsb=lsb+1 else break end end
return waste, cross, lsb
end
local position_section = function(section, constrain)
local location = section.location
local chunks,rorg = location.chunks,location.rorg
table.sort(chunks, function(a,b) if a.size==b.size then return a.id<b.id end return a.size<b.size end)
for chunk_ix,chunk in ipairs(chunks) do if chunk.size >= 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.id<b.id end return a.size>b.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<b end return x<y end)
for _,v in ipairs(sym_rev) do
local k,vorg=symbols[v],v
local u=v:match'.*()_' if u then -- change _ to . in local labels
local parent=v:sub(1,u-1) if symbols[parent] then v = parent..'.'..v:sub(u+1) end
end
local e = entry(k,v,vorg) if e then
if type(e) == 'table' then for _,ev in ipairs(e) do ins(s, ev) end
else ins(s, e) end
end
end
return s
end
M.getsym_as = {
lua = function() -- .lua
local fmt,rep = string.format,string.rep
local s = M.getsym(function(a,l) return fmt("%s = 0x%04x", l, a) end)
return table.concat(s, '\n')
end,
dasm = function() -- .sym
local fmt,rep = string.format,string.rep
local s = M.getsym(function(a,l) return fmt("%s%s %04x", l, rep(' ',24-#l), a) end)
table.insert(s, 1, '--- Symbol List')
s[#s+1] = '--- End of Symbol List.'
return table.concat(s, '\n')
end,
}
-- write a symbol file for debuggers, using specified format (defaults to DASM)
M.writesym = function(filename, format)
assert(filename)
local s = M.getsym_as[format or 'dasm'](filename)
if s then
local f = assert(io.open(filename, "wb"), "failed to open " .. filename .. " for writing")
f:write(s) f:close()
end
end
stats.__tostring = function()
local s,ins={},table.insert
ins(s, " Free Used Size Area")
for _,location in ipairs(locations) do
local name = (location.name or ''):sub(1,14)
name = string.rep(' ', 14-#name) .. name
local fmt = "%s %5d %5d %5d [%04X-%04X]"
if location.finish then
local size = location.finish-location.start+1
ins(s, string.format(fmt, name,
location.unused, size-location.unused, size, location.start, location.finish))
else
ins(s, string.format(fmt, name,
location.unused, location.used, location.stops_at-location.start+1, location.start, location.stops_at))
end
end
if #locations > 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
return M

View File

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

222
l7801.c Normal file
View File

@ -0,0 +1,222 @@
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#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;
}

2751
l7801.lua Normal file

File diff suppressed because it is too large Load Diff

4
main.c
View File

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

40
samples/scv_hello.l7801 Normal file
View File

@ -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,0x3044
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 "\t\t\t\t Hello world! \t\t\t\t"
dc.b 0x00
writebin(filename .. '.bin')

View File

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

738
samples/scv_test.l7801 Normal file
View File

@ -0,0 +1,738 @@
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
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
@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
ldax (bc)
ldax (de)
ldax (hl)
stax (bc)
stax (de)
stax (hl)
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)
dcx bc
dcx de
dcx hl
inx bc
inx de
inx hl
mvix (bc),0xf9
mvix (de),0xe8
mvix (hl),0xd7
mviw (v,0x9a),0x3f
eqiw (v,0xc5),0x1b
ldaxd (de)
ldaxi (de)
ldaxd (hl)
ldaxi (hl)
staxd (de)
staxi (de)
staxd (hl)
staxi (hl)
push bc
push de
push hl
pop hl
pop de
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
in 0x00
in 0xa7
in 0xbf
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
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
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
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)
sspd (0x8000)
lspd (0x8001)
sbcd (0x8010)
lbcd (0x8011)
sded (0x8100)
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
mov v,(0x000f)
mov a,(0x00f0)
mov b,(0x00ff)
mov c,(0x0f00)
mov d,(0x0f0f)
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')

3
scv.l7801 Normal file
View File

@ -0,0 +1,3 @@
cpu = require 'uPD7801'
setmetatable(_ENV, cpu)

638
uPD7801.lua Normal file
View File

@ -0,0 +1,638 @@
M = require "asm"
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 M.word_normalize(M.op_eval(late, early)) end
M.op_eval_word = op_eval_word
local opimp={
block=M.op(0x31,13),
calb=M.op(0x63,13),
daa=M.op(0x61,4),
ex=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 .. 'imp' ] = 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 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 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),
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()
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),
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),
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)
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 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
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 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 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
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),
} M.opw = opw
for k,v in pairs(opw) do
M[k .. 'imm'] = function(late, early)
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 l7801dbg=l7801dbg
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.opr16w = opr16w
for k,v in pairs(opr16w) do
M[k] = function(late, early)
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 l7801dbg=l7801dbg
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
M['calt' .. 'imm'] = function(late, early)
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 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
x = (x>>1) + 0x40
return x
end
table.insert(M.section_current.instructions, op)
end
M['calf' .. 'imm'] = function(late, early)
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 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;
return { 0x78 | ((x>>8) & 0x07), x&0xff }
end
table.insert(M.section_current.instructions, op)
end
M.jr = function(label)
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 }
op.size = function()
offset = section.size
label = M.size_dc(label)
return 1
end
op.bin = function()
local l7801dbg=l7801dbg
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-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
x = 0xc0 + x
return x
else
return x & 0xff
end
end
table.insert(M.section_current.instructions, op)
end
M.jre = function(label)
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 }
op.size = function()
offset = section.size
label = M.size_dc(label)
return 2
end
op.bin = function()
local l7801dbg=l7801dbg
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 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 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 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
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 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 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 })
end
end
local op48imp = {
ei=M.op(0x20,8),
di=M.op(0x24,8),
clc=M.op(0x2a,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),
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
M[k .. 'imp'] = function()
table.insert(M.section_current.instructions, { size=2, cycles=v.cycles, bin={ 0x48, v.opc } })
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),
pushhl=M.op(0x3e,17),
pushva=M.op(0x0e,17),
popbc=M.op(0x1f,15),
popde=M.op(0x2f,15),
pophl=M.op(0x3f,15),
popva=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
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
-- 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 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 l7801dbg=l7801dbg
local x = 0x00 + M.op_eval_byte(late,early)
return { v.opc, 0x00, x }
end
table.insert(M.section_current.instructions, op)
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
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
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
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 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 l7801dbg=l7801dbg
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 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 l7801dbg=l7801dbg
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
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 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 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
local op70ind = {
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.op70ind = op70ind
for k,v in pairs(op70ind) do
M[k] = function(late, early)
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 l7801dbg=l7801dbg
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
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 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 l7801dbg=l7801dbg
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
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 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 l7801dbg=l7801dbg
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
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
return M