mirror of
https://github.com/g012/l65.git
synced 2025-03-08 12:31:35 +00:00
[NES] Added UNROM-512 mapper and sample
This commit is contained in:
parent
5f71b92bcd
commit
31cccce3e1
2
.gitignore
vendored
2
.gitignore
vendored
@ -7,4 +7,4 @@
|
||||
*.nes.deb
|
||||
*.sym
|
||||
*.mlb
|
||||
*.nl
|
||||
*.nl
|
@ -71,6 +71,7 @@ Table of Contents
|
||||
* [Windows](#windows)
|
||||
* [Linux](#linux)
|
||||
* [Vim files installation](#vim-files-installation)
|
||||
* [Visual Studio Code extension](#vscode-extension)
|
||||
* [TODO List](#todo-list)
|
||||
* [Credits](#credits)
|
||||
* [License](#license)
|
||||
@ -656,6 +657,10 @@ make
|
||||
|
||||
Note that the syntax file includes some highlighting for features only activated via pragmas: `dna`, `xsr`, `rtx` and `far`. If you do not want to use these keywords, remove them from the syntax file.
|
||||
|
||||
## Visual Studio Code extension
|
||||
|
||||
Install the "l65" extension from the marketplace or check [l65-vscode](https://github.com/g012/l65-vscode) repository.
|
||||
|
||||
## TODO List
|
||||
|
||||
* [k65](http://devkk.net/wiki/index.php?title=K65) style syntax
|
||||
|
7
asm.lua
7
asm.lua
@ -101,7 +101,8 @@ M.link = function()
|
||||
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
|
||||
local s, f = rorg(cstart) // 0x100, rorg(cfinish) // 0x100
|
||||
if s==f or math.ceil(s)==math.floor(s) and s+1==f and cfinish-cstart==0x100 then
|
||||
if constraint.type == 'crosspage' then return end
|
||||
else
|
||||
if constraint.type == 'samepage' then return end
|
||||
@ -259,7 +260,7 @@ M.link = function()
|
||||
return waste, cross, lsb
|
||||
end)
|
||||
if not position then
|
||||
error("unable to find space for section " .. section.label)
|
||||
error("unable to find space for related section '" .. section.label .. "' of size " .. section.size)
|
||||
end
|
||||
for section,offset in pairs(related) do
|
||||
section.org = position + (section.location.start - location_start) + offset
|
||||
@ -273,7 +274,7 @@ M.link = function()
|
||||
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)
|
||||
error("unable to find space for section '" .. section.label .. "' of size " .. section.size)
|
||||
end
|
||||
end
|
||||
|
||||
|
54
nes.l65
54
nes.l65
@ -405,7 +405,7 @@ mappers.UxROM = function(t)
|
||||
until off + sz >= t.chrsize
|
||||
chrrom = chrrom0
|
||||
function switchprgrom(bankix)
|
||||
if bankix then assert(bankix < bc-1) lda #bankix end
|
||||
if bankix then assert(bankix < bc, "mappers.switchprgrom: bank out of range: " .. bankix .. ", expected 0-" .. (bc-1)) lda #bankix end
|
||||
-- lda to reverse map [n..0] to [0..n]
|
||||
tax lda bankbytes,x sta bankbytes,x
|
||||
end
|
||||
@ -415,6 +415,58 @@ mappers.UxROM = function(t)
|
||||
end
|
||||
mappers[2] = mappers.UxROM
|
||||
|
||||
--[[
|
||||
https://www.nesdev.org/wiki/UNROM_512
|
||||
]]
|
||||
mappers.UNROM512 = function(t)
|
||||
if not t then t = {} end
|
||||
t.mapperid = 30
|
||||
if not t.prgsize then t.prgsize = 32 * 16384 end
|
||||
assert(t.prgsize >= 0x8000 and t.prgsize <= 0x80000, "prgsize must be at least 32kB and at most 512kB")
|
||||
assert(n0ne(t.chrsize), "chrsize must be 0")
|
||||
if n0ne(t.chrramsize) and n0ne(t.chrbramsize) then t.chrramsize = 4 * 8192 end
|
||||
local csize = val0(t.chrramsize) + val0(t.chrbramsize)
|
||||
assert(csize == 0x2000 or csize == 0x4000 or csize == 0x8000, "combined chrram size must be 8, 16 or 32kB")
|
||||
hdrrom = location{0x7ff0, 0x7fff, name='header'}
|
||||
header(t)
|
||||
local bc = t.prgsize//0x4000
|
||||
for bi=0,bc-2 do
|
||||
local o,ix = 0x8000 + bi*0x4000, bc-1-bi
|
||||
_ENV['prgrom'..ix] = location{o, o+0x3fff, rorg=0x8000, name='prgrom'..ix}
|
||||
end
|
||||
local prglast = 0x8000 + (bc-1)*0x4000
|
||||
prgrom0 = location{prglast, prglast+0x3fff, rorg=0xc000, name='prgrom0'}
|
||||
prgrom = prgrom0
|
||||
section{"vectors", org=prglast+0x3ffa} dc.w nmi, main, irq
|
||||
section{ "bankbytes", align=256 } -- for handling bus conflicts
|
||||
for m=0,1 do
|
||||
for c=0,3 do
|
||||
for p=0x1f,0,-1 do byte(m<<7 | c<<5 | p) end
|
||||
end
|
||||
end
|
||||
function clearchrram(page_count, offset)
|
||||
ppu_addr(CHAR0 + (offset or 0)) tay ldx#(page_count or 32) @_clear sta PPUDATA iny bne _clear dex bne _clear
|
||||
end
|
||||
function loadchrram(var, page_count, offset)
|
||||
ppu_addr(CHAR0 + (offset or 0)) ldx#(page_count or 32) ldy#0 @_load lda (var),y sta PPUDATA iny bne _load inc var+1 dex bne _load
|
||||
end
|
||||
function switch(prgbankix, chrbankix, mirror)
|
||||
if prgbankix then assert(prgbankix < bc, "mappers.switch: PRG bank out of range: " .. prgbankix .. ", expected 0-" .. (bc-1)) end
|
||||
if chrbankix then assert(chrbankix < 4, "mappers.switch: CHR bank out of range: " .. chrbankix .. ", expected 0-3") end
|
||||
if mirror then assert(mirror == 0 or mirror == 1, "mappers.switch: mirror out of range: " .. mirror .. ", expected 0-1") end
|
||||
if prgbankix or chrbankix or mirror then
|
||||
local r = (mirror or 0)<<7 | (chrbankix or 0)<<5 | (prgbankix or 1)
|
||||
lda #r
|
||||
end
|
||||
-- lda to reverse prg map [n..0] to [0..n]
|
||||
tax lda bankbytes,x sta bankbytes,x
|
||||
end
|
||||
mappers.init = function()
|
||||
switch(1)
|
||||
end
|
||||
end
|
||||
mappers[30] = mappers.UxROM
|
||||
|
||||
--[[
|
||||
https://wiki.nesdev.com/w/index.php/CNROM
|
||||
Has bus conflicts.
|
||||
|
75
samples/nes_chrram.l65
Normal file
75
samples/nes_chrram.l65
Normal file
@ -0,0 +1,75 @@
|
||||
require'nes'
|
||||
mappers.UNROM512()
|
||||
|
||||
location(prgrom1)
|
||||
|
||||
local font_size = 27 * 16
|
||||
@@font
|
||||
dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 -- <SPC>
|
||||
dc.b 0x38,0x38,0x2c,0x64,0x7e,0x46,0xce,0x00,0x38,0x38,0x2c,0x64,0x7e,0x46,0xce,0x00 -- A
|
||||
dc.b 0xfc,0x62,0x66,0x7c,0x62,0x66,0xfc,0x00,0xfc,0x62,0x66,0x7c,0x62,0x66,0xfc,0x00 -- B
|
||||
dc.b 0x7c,0xe6,0xc2,0xc0,0xc0,0xe6,0x7c,0x00,0x7c,0xe6,0xc2,0xc0,0xc0,0xe6,0x7c,0x00 -- C
|
||||
dc.b 0xfc,0x4e,0x46,0x46,0x46,0xce,0xfc,0x00,0xfc,0x4e,0x46,0x46,0x46,0xce,0xfc,0x00 -- D
|
||||
dc.b 0xfe,0x66,0x60,0x7c,0x60,0x66,0xfe,0x00,0xfe,0x66,0x60,0x7c,0x60,0x66,0xfe,0x00 -- E
|
||||
dc.b 0xfe,0x66,0x60,0x7c,0x60,0x60,0xf0,0x00,0xfe,0x66,0x60,0x7c,0x60,0x60,0xf0,0x00 -- F
|
||||
dc.b 0x7c,0xe6,0xc0,0xce,0xc6,0xe6,0x7c,0x00,0x7c,0xe6,0xc0,0xce,0xc6,0xe6,0x7c,0x00 -- G
|
||||
dc.b 0xee,0x66,0x66,0x7e,0x66,0x66,0xee,0x00,0xee,0x66,0x66,0x7e,0x66,0x66,0xee,0x00 -- H
|
||||
dc.b 0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00 -- I
|
||||
dc.b 0x0e,0x06,0x06,0xc6,0xc6,0xce,0x7c,0x00,0x0e,0x06,0x06,0xc6,0xc6,0xce,0x7c,0x00 -- J
|
||||
dc.b 0xce,0xdc,0xf8,0xf0,0xf8,0xdc,0xce,0x00,0xce,0xdc,0xf8,0xf0,0xf8,0xdc,0xce,0x00 -- K
|
||||
dc.b 0xc0,0xc0,0xc0,0xc0,0xc6,0xc6,0xfe,0x00,0xc0,0xc0,0xc0,0xc0,0xc6,0xc6,0xfe,0x00 -- L
|
||||
dc.b 0xc6,0xee,0xfe,0xd6,0xc6,0xc6,0xc6,0x00,0xc6,0xee,0xfe,0xd6,0xc6,0xc6,0xc6,0x00 -- M
|
||||
dc.b 0xc6,0xe6,0xf6,0xde,0xce,0xc6,0xc6,0x00,0xc6,0xe6,0xf6,0xde,0xce,0xc6,0xc6,0x00 -- N
|
||||
dc.b 0x7c,0xee,0xc6,0xc6,0xc6,0xee,0x7c,0x00,0x7c,0xee,0xc6,0xc6,0xc6,0xee,0x7c,0x00 -- O
|
||||
dc.b 0xfc,0xc6,0xc6,0xc6,0xfc,0xc0,0xc0,0x00,0xfc,0xc6,0xc6,0xc6,0xfc,0xc0,0xc0,0x00 -- P
|
||||
dc.b 0x7c,0xce,0xc6,0xc6,0xde,0xec,0x7e,0x00,0x7c,0xce,0xc6,0xc6,0xde,0xec,0x7e,0x00 -- Q
|
||||
dc.b 0xfc,0x66,0x66,0x7c,0x58,0x6c,0xe6,0x00,0xfc,0x66,0x66,0x7c,0x58,0x6c,0xe6,0x00 -- R
|
||||
dc.b 0x7c,0xc6,0xc0,0x7c,0x06,0xc6,0x7c,0x00,0x7c,0xc6,0xc0,0x7c,0x06,0xc6,0x7c,0x00 -- S
|
||||
dc.b 0xfe,0x92,0x10,0x10,0x10,0x10,0x38,0x00,0xfe,0x92,0x10,0x10,0x10,0x10,0x38,0x00 -- T
|
||||
dc.b 0xe6,0xe6,0xc2,0xc2,0xc2,0xe6,0x7c,0x00,0xe6,0xe6,0xc2,0xc2,0xc2,0xe6,0x7c,0x00 -- U
|
||||
dc.b 0xc6,0xc6,0xc6,0x6c,0x6c,0x38,0x38,0x00,0xc6,0xc6,0xc6,0x6c,0x6c,0x38,0x38,0x00 -- V
|
||||
dc.b 0xc6,0xc6,0xd6,0xfe,0xee,0xc6,0x82,0x00,0xc6,0xc6,0xd6,0xfe,0xee,0xc6,0x82,0x00 -- W
|
||||
dc.b 0x86,0xcc,0x78,0x30,0x78,0xcc,0x86,0x00,0x86,0xcc,0x78,0x30,0x78,0xcc,0x86,0x00 -- X
|
||||
dc.b 0xc6,0xc6,0x6c,0x38,0x18,0x18,0x38,0x00,0xc6,0xc6,0x6c,0x38,0x18,0x18,0x38,0x00 -- Y
|
||||
dc.b 0x7e,0xce,0x98,0x30,0x62,0xe6,0xfc,0x00,0x7e,0xce,0x98,0x30,0x62,0xe6,0xfc,0x00 -- Z
|
||||
|
||||
-- RAM
|
||||
chr = 0
|
||||
|
||||
location(prgrom)
|
||||
@@nmi rti
|
||||
@@irq rti
|
||||
|
||||
charset(" abcdefghijklmnopqrstuvwxyz")
|
||||
local hello = "hello world"
|
||||
@@text byte(hello)
|
||||
|
||||
@@main
|
||||
init()
|
||||
clearchrram()
|
||||
-- load font in CHR RAM
|
||||
ppu_addr(CHAR0)
|
||||
lda #font&0xff sta chr lda #font>>8 sta chr+1
|
||||
ldy #0 @_loadfnt1 lda (chr),y sta PPUDATA iny bne _loadfnt1
|
||||
inc chr+1
|
||||
@_loadfnt2 lda (chr),y sta PPUDATA iny cpy #font_size-256 bne _loadfnt2
|
||||
-- load BG palette in PPU RAM
|
||||
ppu_addr(BGPAL)
|
||||
for _,v in ipairs{ 0x1f, 0x00, 0x10, 0x20 } do lda #v sta PPUDATA end
|
||||
-- load screen text in PPU RAM 0x21CA
|
||||
ppu_addr(0x21ca)
|
||||
ldy #0 @_loadtxt lda text,y sta PPUDATA iny cpy ##hello bne _loadtxt
|
||||
-- reset scroll position
|
||||
ppu_addr(0) sta BGSCROL sta BGSCROL
|
||||
-- show BG
|
||||
vblank_waitbegin()
|
||||
lda #0x0a sta PPUMASK
|
||||
-- idle
|
||||
@_loop jmp _loop
|
||||
|
||||
writebin(filename..'.nes')
|
||||
writesym(filename..'.mlb', 'mesen')
|
||||
writesym(filename..'.nes', 'fceux')
|
||||
print(stats)
|
||||
|
||||
|
@ -1,113 +1,113 @@
|
||||
require'vcs'
|
||||
mappers['4K']()
|
||||
|
||||
local HEADER_LEN = 92
|
||||
local PICTURE_LEN = 64
|
||||
local STEP_COUNT = 32
|
||||
|
||||
-- FLUSH text as playfield
|
||||
local logo_img = assert(l65.image("flush.png")) -- analyse the image twice, so load it separately
|
||||
@@logo_col samepage byte(0x00, 0xd4, 0x72, linecol(logo_img)) end
|
||||
local pfs = playfield(logo_img)
|
||||
for i=1,#pfs do
|
||||
local pf = pfs[i]
|
||||
section("logo_pf"..(i-1)) samepage byte(0, pf[1], pf[#pf], pf) end
|
||||
end
|
||||
local LOGO_HEIGHT = #pfs[1]
|
||||
|
||||
-- background
|
||||
local bg = linecol("flushbg.png")
|
||||
@@logo_bg_all
|
||||
samepage
|
||||
@logo_bg_pre for i=1,8 do dc.b bg[1] end
|
||||
@logo_bg
|
||||
for i=1,13 do dc.b bg[1] end
|
||||
byte(bg)
|
||||
for i=1,13 do dc.b bg[#bg] end
|
||||
@logo_bg_post for i=1,8 do dc.b bg[#bg] end
|
||||
end
|
||||
|
||||
-- generate offset tables into logo_pf*
|
||||
do
|
||||
local DISP_HEIGHT = PICTURE_LEN
|
||||
local transfo,bgshift = {},{}
|
||||
for x=0,STEP_COUNT-1 do
|
||||
local theta = x/(STEP_COUNT-1) * math.pi/2 - math.pi/4
|
||||
local s,c = math.sin(theta),math.cos(theta)
|
||||
local ra,rb,rc,rd = -c, s-c, s+c, c
|
||||
for y=0,DISP_HEIGHT-1 do
|
||||
local r = DISP_HEIGHT / LOGO_HEIGHT
|
||||
local yn = r * (2 * y/(DISP_HEIGHT-1) - 1)
|
||||
local function f()
|
||||
local y = (s-yn) / c
|
||||
return math.min(math.floor((y+1)/2*LOGO_HEIGHT), LOGO_HEIGHT-1) + 3
|
||||
end
|
||||
local v
|
||||
if rd < rc then v = yn>rc and 0 or yn>rb and f(yn) or yn>ra and 2 or 0
|
||||
else v = yn>rd and 0 or yn>rc and 1 or yn>rb and f(yn) or 0 end
|
||||
transfo[x*DISP_HEIGHT+DISP_HEIGHT-y] = v
|
||||
end
|
||||
bgshift[#bgshift+1] = math.floor(math.sin(math.pi+theta)*LOGO_HEIGHT/4)
|
||||
end
|
||||
@@logo_transfo byte(transfo)
|
||||
@@logo_bgshift byte(bgshift)
|
||||
end
|
||||
|
||||
-- rotation anim
|
||||
do
|
||||
local PERIOD = 128
|
||||
local f = \x((math.sin(x*2*math.pi/PERIOD)+1)/2 * (STEP_COUNT-1))
|
||||
local rotation = {}
|
||||
for x=1,PERIOD do
|
||||
rotation[#rotation+1] = math.floor(math.min(f(x-1), (STEP_COUNT-1)))
|
||||
end
|
||||
@@logo_rotation byte(rotation)
|
||||
end
|
||||
|
||||
local bg_ptr = 0x80
|
||||
local trans_ptr = 0x82
|
||||
local time = 0x84
|
||||
local tmp = 0x85
|
||||
|
||||
local on_vblank = function()
|
||||
inc time asl time lsr time
|
||||
ldy time lda logo_rotation,y sta tmp
|
||||
|
||||
ldy tmp lda logo_bgshift,y sta bg_ptr
|
||||
lda#logo_bg&0xff clc adc bg_ptr sta bg_ptr lda#logo_bg>>8 sta bg_ptr+1
|
||||
|
||||
setptr(logo_transfo, trans_ptr)
|
||||
lda tmp asl asl asl asl asl asl clc adc trans_ptr sta trans_ptr
|
||||
lda trans_ptr+1 adc#0 sta trans_ptr+1
|
||||
lda tmp lsr lsr clc adc trans_ptr+1 sta trans_ptr+1
|
||||
|
||||
ldy#PICTURE_LEN-1 lda (bg_ptr),y sta COLUBK
|
||||
end
|
||||
|
||||
local kernel = function()
|
||||
ldy#HEADER_LEN @_header sta WSYNC dey bne _header
|
||||
samepage @_line
|
||||
lda (trans_ptr),y tax
|
||||
lda (bg_ptr),y
|
||||
sta WSYNC sta COLUBK
|
||||
lda logo_col,x sta COLUPF
|
||||
lda logo_pf0,x sta PF0
|
||||
lda logo_pf1,x sta PF1
|
||||
lda logo_pf2,x sta PF2
|
||||
lda logo_pf3,x sta PF0
|
||||
lda logo_pf4,x sta PF1
|
||||
lda logo_pf5,x sta PF2
|
||||
iny cpy#PICTURE_LEN bne _line
|
||||
end
|
||||
lda#0 sta WSYNC sta PF0 sta PF1 sta PF2
|
||||
end
|
||||
|
||||
@@main
|
||||
init()
|
||||
@_frame
|
||||
overscan() vblank(on_vblank) screen(kernel) jmp _frame
|
||||
|
||||
;
|
||||
writebin(filename..'.bin')
|
||||
writesym(filename..'.sym')
|
||||
print(stats)
|
||||
require'vcs'
|
||||
mappers['4K']()
|
||||
|
||||
local HEADER_LEN = 92
|
||||
local PICTURE_LEN = 64
|
||||
local STEP_COUNT = 32
|
||||
|
||||
-- FLUSH text as playfield
|
||||
local logo_img = assert(l65.image("flush.png")) -- analyse the image twice, so load it separately
|
||||
@@logo_col samepage byte(0x00, 0xd4, 0x72, linecol(logo_img)) end
|
||||
local pfs = playfield(logo_img)
|
||||
for i=1,#pfs do
|
||||
local pf = pfs[i]
|
||||
section("logo_pf"..(i-1)) samepage byte(0, pf[1], pf[#pf], pf) end
|
||||
end
|
||||
local LOGO_HEIGHT = #pfs[1]
|
||||
|
||||
-- background
|
||||
local bg = linecol("flushbg.png")
|
||||
@@logo_bg_all
|
||||
samepage
|
||||
@logo_bg_pre for i=1,8 do dc.b bg[1] end
|
||||
@logo_bg
|
||||
for i=1,13 do dc.b bg[1] end
|
||||
byte(bg)
|
||||
for i=1,13 do dc.b bg[#bg] end
|
||||
@logo_bg_post for i=1,8 do dc.b bg[#bg] end
|
||||
end
|
||||
|
||||
-- generate offset tables into logo_pf*
|
||||
do
|
||||
local DISP_HEIGHT = PICTURE_LEN
|
||||
local transfo,bgshift = {},{}
|
||||
for x=0,STEP_COUNT-1 do
|
||||
local theta = x/(STEP_COUNT-1) * math.pi/2 - math.pi/4
|
||||
local s,c = math.sin(theta),math.cos(theta)
|
||||
local ra,rb,rc,rd = -c, s-c, s+c, c
|
||||
for y=0,DISP_HEIGHT-1 do
|
||||
local r = DISP_HEIGHT / LOGO_HEIGHT
|
||||
local yn = r * (2 * y/(DISP_HEIGHT-1) - 1)
|
||||
local function f()
|
||||
local y = (s-yn) / c
|
||||
return math.min(math.floor((y+1)/2*LOGO_HEIGHT), LOGO_HEIGHT-1) + 3
|
||||
end
|
||||
local v
|
||||
if rd < rc then v = yn>rc and 0 or yn>rb and f(yn) or yn>ra and 2 or 0
|
||||
else v = yn>rd and 0 or yn>rc and 1 or yn>rb and f(yn) or 0 end
|
||||
transfo[x*DISP_HEIGHT+DISP_HEIGHT-y] = v
|
||||
end
|
||||
bgshift[#bgshift+1] = math.floor(math.sin(math.pi+theta)*LOGO_HEIGHT/4)
|
||||
end
|
||||
@@logo_transfo byte(transfo)
|
||||
@@logo_bgshift byte(bgshift)
|
||||
end
|
||||
|
||||
-- rotation anim
|
||||
do
|
||||
local PERIOD = 128
|
||||
local f = \x((math.sin(x*2*math.pi/PERIOD)+1)/2 * (STEP_COUNT-1))
|
||||
local rotation = {}
|
||||
for x=1,PERIOD do
|
||||
rotation[#rotation+1] = math.floor(math.min(f(x-1), (STEP_COUNT-1)))
|
||||
end
|
||||
@@logo_rotation byte(rotation)
|
||||
end
|
||||
|
||||
local bg_ptr = 0x80
|
||||
local trans_ptr = 0x82
|
||||
local time = 0x84
|
||||
local tmp = 0x85
|
||||
|
||||
local on_vblank = function()
|
||||
inc time asl time lsr time
|
||||
ldy time lda logo_rotation,y sta tmp
|
||||
|
||||
ldy tmp lda logo_bgshift,y sta bg_ptr
|
||||
lda#logo_bg&0xff clc adc bg_ptr sta bg_ptr lda#logo_bg>>8 sta bg_ptr+1
|
||||
|
||||
setptr(logo_transfo, trans_ptr)
|
||||
lda tmp asl asl asl asl asl asl clc adc trans_ptr sta trans_ptr
|
||||
lda trans_ptr+1 adc#0 sta trans_ptr+1
|
||||
lda tmp lsr lsr clc adc trans_ptr+1 sta trans_ptr+1
|
||||
|
||||
ldy#PICTURE_LEN-1 lda (bg_ptr),y sta COLUBK
|
||||
end
|
||||
|
||||
local kernel = function()
|
||||
ldy#HEADER_LEN @_header sta WSYNC dey bne _header
|
||||
samepage @_line
|
||||
lda (trans_ptr),y tax
|
||||
lda (bg_ptr),y
|
||||
sta WSYNC sta COLUBK
|
||||
lda logo_col,x sta COLUPF
|
||||
lda logo_pf0,x sta PF0
|
||||
lda logo_pf1,x sta PF1
|
||||
lda logo_pf2,x sta PF2
|
||||
lda logo_pf3,x sta PF0
|
||||
lda logo_pf4,x sta PF1
|
||||
lda logo_pf5,x sta PF2
|
||||
iny cpy#PICTURE_LEN bne _line
|
||||
end
|
||||
lda#0 sta WSYNC sta PF0 sta PF1 sta PF2
|
||||
end
|
||||
|
||||
@@main
|
||||
init()
|
||||
@_frame
|
||||
overscan() vblank(on_vblank) screen(kernel) jmp _frame
|
||||
|
||||
;
|
||||
writebin(filename..'.bin')
|
||||
writesym(filename..'.sym')
|
||||
print(stats)
|
||||
|
@ -1,413 +1,413 @@
|
||||
require'vcs'
|
||||
mappers['2K']()
|
||||
|
||||
local AUDC0s = 0x90
|
||||
local AUDC1s, AUDF0s, AUDF1s, AUDV0s, AUDV1s = AUDC0s+1, AUDC0s+2, AUDC0s+3, AUDC0s+4, AUDC0s+5
|
||||
local vubars = 0xA0
|
||||
local tmp = 0xB0
|
||||
|
||||
local zic_filename = ... or 'Ishtar.ttt'
|
||||
local zic = ttt(zic_filename)
|
||||
print(string.format('Using file %s (ttt version %d)\n Name: %s\n Author: %s\n%s', zic_filename, zic.version, zic.name, zic.author, zic.comment))
|
||||
|
||||
-- debug printing of zic data
|
||||
--[[
|
||||
local printbytetable = function(v)
|
||||
local s = ' '
|
||||
for kk,vv in ipairs(v) do
|
||||
s = s .. string.format('%02x, ', vv)
|
||||
if #s >= 34 then print(s) s = ' ' end
|
||||
end
|
||||
if #s > 0 then print(s) end
|
||||
end
|
||||
for k,v in pairs(zic) do
|
||||
if type(v) ~= 'table' then
|
||||
print(k,v)
|
||||
elseif type(v[1]) == 'number' then
|
||||
print(k) printbytetable(v)
|
||||
elseif type(v[1]) == 'table' then
|
||||
for ek, e in ipairs(v) do
|
||||
print(k, ek, e.name) printbytetable(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
@@tt_InsCtrlTable byte(zic.insctrltable)
|
||||
@@tt_InsADIndexes byte(zic.insadindexes)
|
||||
@@tt_InsSustainIndexes byte(zic.inssustainindexes)
|
||||
@@tt_InsReleaseIndexes byte(zic.insreleaseindexes)
|
||||
@@tt_InsFreqVolTable byte(zic.insfreqvoltable)
|
||||
@@tt_PercIndexes byte(zic.percindexes)
|
||||
@@tt_PercFreqTable byte(zic.percfreqtable)
|
||||
@@tt_PercCtrlVolTable byte(zic.percctrlvoltable)
|
||||
local patterns = {}
|
||||
for i,pattern in ipairs(zic.patterns) do
|
||||
table.insert(patterns, section("pattern"..i)) byte(pattern)
|
||||
end
|
||||
@@tt_PatternSpeeds byte(zic.patternspeeds)
|
||||
@@tt_PatternPtrLo byte_lo(patterns)
|
||||
@@tt_PatternPtrHi byte_hi(patterns)
|
||||
@@tt_SequenceTable byte(zic.sequence[1]) byte(zic.sequence[2])
|
||||
|
||||
local tt = {
|
||||
-- =====================================================================
|
||||
-- Permanent variables. These are states needed by the player.
|
||||
-- =====================================================================
|
||||
'timer', -- current music timer value
|
||||
'cur_pat_index_c0', -- current pattern index into tt_SequenceTable
|
||||
'cur_pat_index_c1',
|
||||
'cur_note_index_c0', -- note index into current pattern
|
||||
'cur_note_index_c1',
|
||||
'envelope_index_c0', -- index into ADSR envelope
|
||||
'envelope_index_c1',
|
||||
'cur_ins_c0', -- current instrument
|
||||
'cur_ins_c1',
|
||||
-- =====================================================================
|
||||
-- Temporary variables. These will be overwritten during a call to the
|
||||
-- player routine, but can be used between calls for other things.
|
||||
-- =====================================================================
|
||||
'ptr', -- 2 bytes
|
||||
}
|
||||
for k,v in ipairs(tt) do tt[v] = k + 0x7F end
|
||||
|
||||
tt.FREQ_MASK = 0b00011111
|
||||
tt.INS_HOLD = 8
|
||||
tt.INS_PAUSE = 16
|
||||
tt.FIRST_PERC = 17
|
||||
|
||||
tt.fetchCurrentNoteImpl = function()
|
||||
@_constructPatPtr
|
||||
ldy tt.cur_pat_index_c0,x lda tt_SequenceTable,y
|
||||
if zic.usegoto then
|
||||
bpl _noPatternGoto
|
||||
;and #0b01111111 sta tt.cur_pat_index_c0,x bpl _constructPatPtr
|
||||
@_noPatternGoto
|
||||
end
|
||||
tay lda tt_PatternPtrLo,y sta tt.ptr lda tt_PatternPtrHi,y sta tt.ptr+1
|
||||
if zic.overlay then
|
||||
clv
|
||||
lda tt.cur_note_index_c0,x bpl _notPrefetched
|
||||
;and #0b01111111 sta tt.cur_note_index_c0,x
|
||||
bit tt_Bit6Set
|
||||
@_notPrefetched
|
||||
tay
|
||||
else
|
||||
ldy tt.cur_note_index_c0,x
|
||||
end
|
||||
lda (tt.ptr),y bne _noEndOfPattern
|
||||
sta tt.cur_note_index_c0,x
|
||||
inc tt.cur_pat_index_c0,x
|
||||
bne _constructPatPtr
|
||||
@_noEndOfPattern
|
||||
end
|
||||
if zic.useoverlay then
|
||||
@@tt_fetchCurrentNoteSection tt.fetchCurrentNoteImpl() rts
|
||||
tt.fetchCurrentNote = function() jsr tt_fetchCurrentNoteSection end
|
||||
else
|
||||
tt.fetchCurrentNote = tt.fetchCurrentNoteImpl
|
||||
end
|
||||
|
||||
@@tt_CalcInsIndex
|
||||
lsr lsr lsr lsr lsr
|
||||
tay
|
||||
@tt_Bit6Set
|
||||
rts
|
||||
|
||||
local function zic_tick()
|
||||
dec tt.timer bpl _noNewNote
|
||||
ldx #1
|
||||
@_advanceLoop
|
||||
tt.fetchCurrentNote()
|
||||
cmp #tt.INS_PAUSE
|
||||
if zic.useslide then
|
||||
beq _pause
|
||||
bcs _newNote
|
||||
adc tt.cur_ins_c0,x sec sbc #8 sta tt.cur_ins_c0,x
|
||||
bcs _finishedNewNote
|
||||
else
|
||||
bcc _finishedNewNote
|
||||
bne _newNote
|
||||
end
|
||||
@_pause
|
||||
lda tt.cur_ins_c0,x jsr tt_CalcInsIndex
|
||||
lda tt_InsReleaseIndexes-1,y
|
||||
clc adc #1 bcc _storeADIndex
|
||||
@_newNote
|
||||
sta tt.cur_ins_c0,x
|
||||
cmp #tt.FREQ_MASK+1 bcs _startInstrument
|
||||
tay
|
||||
lda tt_PercIndexes-tt.FIRST_PERC,y
|
||||
bne _storeADIndex
|
||||
@_startInstrument
|
||||
if zic.useoverlay then
|
||||
bvs _finishedNewNote
|
||||
end
|
||||
jsr tt_CalcInsIndex
|
||||
lda tt_InsADIndexes-1,y
|
||||
@_storeADIndex
|
||||
sta tt.envelope_index_c0,x
|
||||
@_finishedNewNote
|
||||
inc tt.cur_note_index_c0,x
|
||||
@_sequencerNextChannel
|
||||
dex
|
||||
bpl _advanceLoop
|
||||
if zic.globalspeed then
|
||||
ldx #zic.speed-1
|
||||
if zic.usefunktempo then
|
||||
lda tt.cur_note_index_c0 lsr bcc _noOddFrame ldx #zic.oddspeed-1 @_noOddFrame
|
||||
end
|
||||
stx tt.timer
|
||||
else
|
||||
ldx tt.cur_pat_index_c0 ldy tt_SequenceTable,x
|
||||
if zic.usefunktempo then
|
||||
lda tt.cur_note_index_c0 lsr
|
||||
lda tt_PatternSpeeds,y
|
||||
bcc _evenFrame
|
||||
;and #0x0f
|
||||
bcs _storeFunkTempo
|
||||
@_evenFrame
|
||||
lsr lsr lsr lsr
|
||||
@_storeFunkTempo
|
||||
sta tt.timer
|
||||
else
|
||||
lda tt_PatternSpeeds,y sta tt.timer
|
||||
end
|
||||
end
|
||||
@_noNewNote
|
||||
ldx #1
|
||||
@_updateLoop
|
||||
lda tt.cur_ins_c0,x
|
||||
if not zic.startswithnotes then
|
||||
beq _afterAudioUpdate
|
||||
end
|
||||
cmp #tt.FREQ_MASK+1 bcs _instrument
|
||||
ldy tt.envelope_index_c0,x
|
||||
lda tt_PercCtrlVolTable-1,y beq _endOfPercussion inc tt.envelope_index_c0,x @_endOfPercussion
|
||||
sta AUDV0,x sta AUDV0s,x lsr lsr lsr lsr sta AUDC0,x sta AUDC0s,x
|
||||
lda tt_PercFreqTable-1,y
|
||||
sta AUDF0,x
|
||||
sta AUDF0s,x -- EXTRA for vumeter rendering
|
||||
if zic.useoverlay then
|
||||
bpl _afterAudioUpdate
|
||||
tt.fetchCurrentNote()
|
||||
cmp #tt.FREQ_MASK+1
|
||||
bcc _afterAudioUpdate
|
||||
sta tt.cur_ins_c0,x
|
||||
jsr tt_CalcInsIndex
|
||||
lda tt_InsSustainIndexes-1,y sta tt.envelope_index_c0,x
|
||||
asl tt.cur_note_index_c0,x sec ror tt.cur_note_index_c0,x
|
||||
bmi _afterAudioUpdate
|
||||
else
|
||||
jmp _afterAudioUpdate
|
||||
end
|
||||
@_instrument
|
||||
jsr tt_CalcInsIndex
|
||||
lda tt_InsCtrlTable-1,y sta AUDC0,x
|
||||
sta AUDC0s,x -- EXTRA for vumeter rendering
|
||||
lda tt.envelope_index_c0,x cmp tt_InsReleaseIndexes-1,y bne _noEndOfSustain lda tt_InsSustainIndexes-1,y @_noEndOfSustain
|
||||
tay
|
||||
lda tt_InsFreqVolTable,y beq _endOfEnvelope iny @_endOfEnvelope
|
||||
sty tt.envelope_index_c0,x
|
||||
sta AUDV0,x
|
||||
sta AUDV0s,x -- EXTRA for vumeter rendering
|
||||
lsr lsr lsr lsr clc adc tt.cur_ins_c0,x sec sbc #8
|
||||
sta AUDF0,x
|
||||
sta AUDF0s,x -- EXTRA for vumeter rendering
|
||||
@_afterAudioUpdate
|
||||
dex
|
||||
bpl _updateLoop
|
||||
end
|
||||
|
||||
local function zic_init()
|
||||
if zic.c0init ~= 0 then lda#zic.c0init sta tt.cur_pat_index_c0 end
|
||||
if zic.c1init ~= 0 then lda#zic.c1init sta tt.cur_pat_index_c1 end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- display song name and author
|
||||
----------------------------------------------------------------------
|
||||
|
||||
section{ "font", align=256 } dc.b
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,-- <SPC>
|
||||
0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00,-- A
|
||||
0x7c,0x66,0x66,0x7c,0x66,0x66,0x7c,0x00,-- B
|
||||
0x3c,0x66,0x60,0x60,0x60,0x66,0x3c,0x00,-- C
|
||||
0x78,0x6c,0x66,0x66,0x66,0x6c,0x78,0x00,-- D
|
||||
0x7e,0x60,0x60,0x78,0x60,0x60,0x7e,0x00,-- E
|
||||
0x7e,0x60,0x60,0x78,0x60,0x60,0x60,0x00,-- F
|
||||
0x3c,0x66,0x60,0x6e,0x66,0x66,0x3c,0x00,-- G
|
||||
0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00,-- H
|
||||
0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,-- I
|
||||
0x1e,0x0c,0x0c,0x0c,0x0c,0x6c,0x38,0x00,-- J
|
||||
0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x00,-- K
|
||||
0x60,0x60,0x60,0x60,0x60,0x60,0x7e,0x00,-- L
|
||||
0x63,0x77,0x7f,0x6b,0x63,0x63,0x63,0x00,-- M
|
||||
0x66,0x76,0x7e,0x7e,0x6e,0x66,0x66,0x00,-- N
|
||||
0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00,-- O
|
||||
0x7c,0x66,0x66,0x7c,0x60,0x60,0x60,0x00,-- P
|
||||
0x3c,0x66,0x66,0x66,0x66,0x3c,0x0e,0x00,-- Q
|
||||
0x7c,0x66,0x66,0x7c,0x78,0x6c,0x66,0x00,-- R
|
||||
0x3c,0x66,0x60,0x3c,0x06,0x66,0x3c,0x00,-- S
|
||||
0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x00,-- T
|
||||
0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00,-- U
|
||||
0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00,-- V
|
||||
0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00,-- W
|
||||
0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00,-- X
|
||||
0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00,-- Y
|
||||
0x7e,0x06,0x0c,0x18,0x30,0x60,0x7e,0x00 -- Z
|
||||
|
||||
charset(" abcdefghijklmnopqrstuvwxyz", \x(x*8))
|
||||
local normtxt = function(txt)
|
||||
txt = txt:lower()
|
||||
local out = {}
|
||||
for i=1,#txt do
|
||||
local c = string.byte(txt:sub(i,i))
|
||||
if c < string.byte('a') or c > string.byte('z') then c = string.byte(' ') end
|
||||
table.insert(out, string.char(c))
|
||||
end
|
||||
local ex = 12 - #out
|
||||
for i=1,ex do
|
||||
if i&1 ~= 0 then table.insert(out, 1, ' ')
|
||||
else table.insert(out, ' ')
|
||||
end
|
||||
end
|
||||
return table.concat(out)
|
||||
end
|
||||
@@song_name byte(normtxt(zic.name))
|
||||
@@song_author byte(normtxt(zic.author))
|
||||
|
||||
local print_txt = tmp+1 -- text pointer, can cross
|
||||
local print_line_count=tmp -- number of lines to print
|
||||
local print_ptr = tmp+3 -- array of pointers to the characters
|
||||
-- a = line count
|
||||
@@print12
|
||||
sta print_line_count
|
||||
lda#6 sta NUSIZ0 sta NUSIZ1
|
||||
-- set MSB of font character addresses
|
||||
lda#font>>8 ldx#23 @_loadfont sta print_ptr,x dex dex bpl _loadfont
|
||||
-- position sprites
|
||||
samepage
|
||||
sta WSYNC
|
||||
ldx#6 @_delay dex bne _delay
|
||||
sta RESP0 nop sta RESP1 lda#0x70 sta HMP0 lda#0x60 sta HMP1 sta WSYNC sta HMOVE
|
||||
end
|
||||
@_loop
|
||||
-- load text line
|
||||
ldx#0 ldy#0 @_loadline lda (print_txt),y sta print_ptr,x inx inx iny cpy#12 bne _loadline
|
||||
lda#0x80 sta HMP0 sta HMP1
|
||||
ldy#0 samepage @_printline
|
||||
sta WSYNC sta HMOVE
|
||||
-- first scanline
|
||||
lda (print_ptr+2),y sta GRP0 lda (print_ptr+6),y sta GRP1
|
||||
lda (print_ptr+22),y tax sleep(6)
|
||||
lda (print_ptr+10),y sta GRP0 lda (print_ptr+14),y sta GRP1 lda (print_ptr+18),y sta GRP0 stx GRP1
|
||||
sta HMCLR sleep(8) sta HMOVE
|
||||
-- second scanline
|
||||
lda (print_ptr),y sta GRP0 lda (print_ptr+4),y sta GRP1
|
||||
lda (print_ptr+20),y tax lda#0x80 sta HMP0 sta HMP1 nop
|
||||
lda (print_ptr+8),y sta GRP0 lda (print_ptr+12),y sta GRP1 lda (print_ptr+16),y sta GRP0 stx GRP1
|
||||
iny cpy#8 bne _printline
|
||||
end
|
||||
dec print_line_count beq _end
|
||||
lda print_txt clc adc#12 sta print_txt lda print_txt+1 adc#0 sta print_txt+1
|
||||
jmp _loop
|
||||
@_end
|
||||
lda#0 sta GRP0 sta GRP1
|
||||
rts
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- equalizer anim
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- convert to freq: http://atariage.com/forums/topic/257526-musicsound-programming-question-atari-2600/
|
||||
-- maps AUDCi to 0-7 3 bits (<<5) value for wave length of: 1, 2, 6, 15, 31, 93, 465, 511
|
||||
@@wavlen samepage
|
||||
dc.b 0x00,0x60,0xC0,0xC0,0x20,0x20,0x80,0x80,
|
||||
0xF0,0x80,0x80,0x00,0x40,0x40,0xA0,0xA0
|
||||
end
|
||||
local wavelen_map = { 1, 2, 6, 15, 31, 93, 465, 511 }
|
||||
local freq_ranges = { 30, 60, 120, 240, 480, 960, 1920, 9999999 }
|
||||
local t = {}
|
||||
for i=0,255 do
|
||||
local wavelen = wavelen_map[(i>>5)+1]
|
||||
local note = (i&31)+1
|
||||
local freq = 3546894 / 114 / wavelen / note
|
||||
for x=1,9 do
|
||||
if freq <= freq_ranges[x] then
|
||||
t[#t+1] = x-1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
section{'regfreq', align=256} byte(t)
|
||||
@@vm_pf2 samepage
|
||||
dc.b 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
end
|
||||
@@vm_pf1 samepage
|
||||
dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F
|
||||
end
|
||||
@@vm_col samepage
|
||||
dc.b 0x3C,0x7C,0x9C,0xDC,0x2C,0x4C,0x6C,0xAC
|
||||
end
|
||||
local vumeter_tick = function()
|
||||
lda #0 ldy #15 @_vudec ldx vubars,y dex bmi _vudecskip stx vubars,y @_vudecskip dey bpl _vudec
|
||||
lda AUDF0s ldy AUDC0s ora wavlen,y tax ldy regfreq,x
|
||||
lda AUDV0s cmp vubars,y bcc _vuless0 sta vubars,y @_vuless0
|
||||
lda AUDF1s ldy AUDC1s ora wavlen,y tax ldy regfreq,x
|
||||
lda AUDV1s cmp vubars+8,y bcc _vuless1 sta vubars+8,y @_vuless1
|
||||
end
|
||||
local vumeter_draw = function()
|
||||
lda #ctrlpf.PF_MIRRORED sta CTRLPF
|
||||
ldy #7
|
||||
@_vudraw
|
||||
samepage
|
||||
lda #16 sta tmp
|
||||
@_vudraw1
|
||||
sta WSYNC
|
||||
lda vm_col,y sta COLUPF sleep(4)
|
||||
ldx vubars,y
|
||||
lda vm_pf1,x sta PF1
|
||||
lda vm_pf2,x sta PF2
|
||||
sleep(8)
|
||||
ldx vubars+8,y
|
||||
lda vm_pf2,x sta PF2
|
||||
lda vm_pf1,x sta PF1
|
||||
dec tmp bpl _vudraw1
|
||||
sta WSYNC lda #0 sta PF2 sta PF1
|
||||
sta WSYNC
|
||||
dey bpl _vudraw
|
||||
end
|
||||
lda #0 sta CTRLPF
|
||||
sta WSYNC sta WSYNC
|
||||
end
|
||||
|
||||
local tick = function()
|
||||
zic_tick()
|
||||
-- clamp to valid TIA range
|
||||
lda AUDC0s ;and #0x0f sta AUDC0s lda AUDC1s ;and #0x0f sta AUDC1s
|
||||
lda AUDF0s ;and #0x1f sta AUDF0s lda AUDF1s ;and #0x1f sta AUDF1s
|
||||
lda AUDV0s ;and #0x0f sta AUDV0s lda AUDV1s ;and #0x0f sta AUDV1s
|
||||
vumeter_tick()
|
||||
end
|
||||
|
||||
local kernel = function()
|
||||
lda#0x8a sta COLUP0 sta COLUP1
|
||||
setptr(song_author,print_txt) lda#1 jsr print12
|
||||
vumeter_draw()
|
||||
lda#0xaa sta COLUP0 sta COLUP1
|
||||
setptr(song_name,print_txt) lda#1 jsr print12
|
||||
end
|
||||
|
||||
@@main
|
||||
init()
|
||||
zic_init()
|
||||
@_frame
|
||||
overscan() vblank(tick) screen(kernel) jmp _frame
|
||||
|
||||
; -- needed if last instruction is implied
|
||||
writebin(filename..'.bin')
|
||||
writesym(filename..'.sym')
|
||||
print(stats)
|
||||
require'vcs'
|
||||
mappers['2K']()
|
||||
|
||||
local AUDC0s = 0x90
|
||||
local AUDC1s, AUDF0s, AUDF1s, AUDV0s, AUDV1s = AUDC0s+1, AUDC0s+2, AUDC0s+3, AUDC0s+4, AUDC0s+5
|
||||
local vubars = 0xA0
|
||||
local tmp = 0xB0
|
||||
|
||||
local zic_filename = ... or 'Ishtar.ttt'
|
||||
local zic = ttt(zic_filename)
|
||||
print(string.format('Using file %s (ttt version %d)\n Name: %s\n Author: %s\n%s', zic_filename, zic.version, zic.name, zic.author, zic.comment))
|
||||
|
||||
-- debug printing of zic data
|
||||
--[[
|
||||
local printbytetable = function(v)
|
||||
local s = ' '
|
||||
for kk,vv in ipairs(v) do
|
||||
s = s .. string.format('%02x, ', vv)
|
||||
if #s >= 34 then print(s) s = ' ' end
|
||||
end
|
||||
if #s > 0 then print(s) end
|
||||
end
|
||||
for k,v in pairs(zic) do
|
||||
if type(v) ~= 'table' then
|
||||
print(k,v)
|
||||
elseif type(v[1]) == 'number' then
|
||||
print(k) printbytetable(v)
|
||||
elseif type(v[1]) == 'table' then
|
||||
for ek, e in ipairs(v) do
|
||||
print(k, ek, e.name) printbytetable(e)
|
||||
end
|
||||
end
|
||||
end
|
||||
]]
|
||||
|
||||
@@tt_InsCtrlTable byte(zic.insctrltable)
|
||||
@@tt_InsADIndexes byte(zic.insadindexes)
|
||||
@@tt_InsSustainIndexes byte(zic.inssustainindexes)
|
||||
@@tt_InsReleaseIndexes byte(zic.insreleaseindexes)
|
||||
@@tt_InsFreqVolTable byte(zic.insfreqvoltable)
|
||||
@@tt_PercIndexes byte(zic.percindexes)
|
||||
@@tt_PercFreqTable byte(zic.percfreqtable)
|
||||
@@tt_PercCtrlVolTable byte(zic.percctrlvoltable)
|
||||
local patterns = {}
|
||||
for i,pattern in ipairs(zic.patterns) do
|
||||
table.insert(patterns, section("pattern"..i)) byte(pattern)
|
||||
end
|
||||
@@tt_PatternSpeeds byte(zic.patternspeeds)
|
||||
@@tt_PatternPtrLo byte_lo(patterns)
|
||||
@@tt_PatternPtrHi byte_hi(patterns)
|
||||
@@tt_SequenceTable byte(zic.sequence[1]) byte(zic.sequence[2])
|
||||
|
||||
local tt = {
|
||||
-- =====================================================================
|
||||
-- Permanent variables. These are states needed by the player.
|
||||
-- =====================================================================
|
||||
'timer', -- current music timer value
|
||||
'cur_pat_index_c0', -- current pattern index into tt_SequenceTable
|
||||
'cur_pat_index_c1',
|
||||
'cur_note_index_c0', -- note index into current pattern
|
||||
'cur_note_index_c1',
|
||||
'envelope_index_c0', -- index into ADSR envelope
|
||||
'envelope_index_c1',
|
||||
'cur_ins_c0', -- current instrument
|
||||
'cur_ins_c1',
|
||||
-- =====================================================================
|
||||
-- Temporary variables. These will be overwritten during a call to the
|
||||
-- player routine, but can be used between calls for other things.
|
||||
-- =====================================================================
|
||||
'ptr', -- 2 bytes
|
||||
}
|
||||
for k,v in ipairs(tt) do tt[v] = k + 0x7F end
|
||||
|
||||
tt.FREQ_MASK = 0b00011111
|
||||
tt.INS_HOLD = 8
|
||||
tt.INS_PAUSE = 16
|
||||
tt.FIRST_PERC = 17
|
||||
|
||||
tt.fetchCurrentNoteImpl = function()
|
||||
@_constructPatPtr
|
||||
ldy tt.cur_pat_index_c0,x lda tt_SequenceTable,y
|
||||
if zic.usegoto then
|
||||
bpl _noPatternGoto
|
||||
;and #0b01111111 sta tt.cur_pat_index_c0,x bpl _constructPatPtr
|
||||
@_noPatternGoto
|
||||
end
|
||||
tay lda tt_PatternPtrLo,y sta tt.ptr lda tt_PatternPtrHi,y sta tt.ptr+1
|
||||
if zic.overlay then
|
||||
clv
|
||||
lda tt.cur_note_index_c0,x bpl _notPrefetched
|
||||
;and #0b01111111 sta tt.cur_note_index_c0,x
|
||||
bit tt_Bit6Set
|
||||
@_notPrefetched
|
||||
tay
|
||||
else
|
||||
ldy tt.cur_note_index_c0,x
|
||||
end
|
||||
lda (tt.ptr),y bne _noEndOfPattern
|
||||
sta tt.cur_note_index_c0,x
|
||||
inc tt.cur_pat_index_c0,x
|
||||
bne _constructPatPtr
|
||||
@_noEndOfPattern
|
||||
end
|
||||
if zic.useoverlay then
|
||||
@@tt_fetchCurrentNoteSection tt.fetchCurrentNoteImpl() rts
|
||||
tt.fetchCurrentNote = function() jsr tt_fetchCurrentNoteSection end
|
||||
else
|
||||
tt.fetchCurrentNote = tt.fetchCurrentNoteImpl
|
||||
end
|
||||
|
||||
@@tt_CalcInsIndex
|
||||
lsr lsr lsr lsr lsr
|
||||
tay
|
||||
@tt_Bit6Set
|
||||
rts
|
||||
|
||||
local function zic_tick()
|
||||
dec tt.timer bpl _noNewNote
|
||||
ldx #1
|
||||
@_advanceLoop
|
||||
tt.fetchCurrentNote()
|
||||
cmp #tt.INS_PAUSE
|
||||
if zic.useslide then
|
||||
beq _pause
|
||||
bcs _newNote
|
||||
adc tt.cur_ins_c0,x sec sbc #8 sta tt.cur_ins_c0,x
|
||||
bcs _finishedNewNote
|
||||
else
|
||||
bcc _finishedNewNote
|
||||
bne _newNote
|
||||
end
|
||||
@_pause
|
||||
lda tt.cur_ins_c0,x jsr tt_CalcInsIndex
|
||||
lda tt_InsReleaseIndexes-1,y
|
||||
clc adc #1 bcc _storeADIndex
|
||||
@_newNote
|
||||
sta tt.cur_ins_c0,x
|
||||
cmp #tt.FREQ_MASK+1 bcs _startInstrument
|
||||
tay
|
||||
lda tt_PercIndexes-tt.FIRST_PERC,y
|
||||
bne _storeADIndex
|
||||
@_startInstrument
|
||||
if zic.useoverlay then
|
||||
bvs _finishedNewNote
|
||||
end
|
||||
jsr tt_CalcInsIndex
|
||||
lda tt_InsADIndexes-1,y
|
||||
@_storeADIndex
|
||||
sta tt.envelope_index_c0,x
|
||||
@_finishedNewNote
|
||||
inc tt.cur_note_index_c0,x
|
||||
@_sequencerNextChannel
|
||||
dex
|
||||
bpl _advanceLoop
|
||||
if zic.globalspeed then
|
||||
ldx #zic.speed-1
|
||||
if zic.usefunktempo then
|
||||
lda tt.cur_note_index_c0 lsr bcc _noOddFrame ldx #zic.oddspeed-1 @_noOddFrame
|
||||
end
|
||||
stx tt.timer
|
||||
else
|
||||
ldx tt.cur_pat_index_c0 ldy tt_SequenceTable,x
|
||||
if zic.usefunktempo then
|
||||
lda tt.cur_note_index_c0 lsr
|
||||
lda tt_PatternSpeeds,y
|
||||
bcc _evenFrame
|
||||
;and #0x0f
|
||||
bcs _storeFunkTempo
|
||||
@_evenFrame
|
||||
lsr lsr lsr lsr
|
||||
@_storeFunkTempo
|
||||
sta tt.timer
|
||||
else
|
||||
lda tt_PatternSpeeds,y sta tt.timer
|
||||
end
|
||||
end
|
||||
@_noNewNote
|
||||
ldx #1
|
||||
@_updateLoop
|
||||
lda tt.cur_ins_c0,x
|
||||
if not zic.startswithnotes then
|
||||
beq _afterAudioUpdate
|
||||
end
|
||||
cmp #tt.FREQ_MASK+1 bcs _instrument
|
||||
ldy tt.envelope_index_c0,x
|
||||
lda tt_PercCtrlVolTable-1,y beq _endOfPercussion inc tt.envelope_index_c0,x @_endOfPercussion
|
||||
sta AUDV0,x sta AUDV0s,x lsr lsr lsr lsr sta AUDC0,x sta AUDC0s,x
|
||||
lda tt_PercFreqTable-1,y
|
||||
sta AUDF0,x
|
||||
sta AUDF0s,x -- EXTRA for vumeter rendering
|
||||
if zic.useoverlay then
|
||||
bpl _afterAudioUpdate
|
||||
tt.fetchCurrentNote()
|
||||
cmp #tt.FREQ_MASK+1
|
||||
bcc _afterAudioUpdate
|
||||
sta tt.cur_ins_c0,x
|
||||
jsr tt_CalcInsIndex
|
||||
lda tt_InsSustainIndexes-1,y sta tt.envelope_index_c0,x
|
||||
asl tt.cur_note_index_c0,x sec ror tt.cur_note_index_c0,x
|
||||
bmi _afterAudioUpdate
|
||||
else
|
||||
jmp _afterAudioUpdate
|
||||
end
|
||||
@_instrument
|
||||
jsr tt_CalcInsIndex
|
||||
lda tt_InsCtrlTable-1,y sta AUDC0,x
|
||||
sta AUDC0s,x -- EXTRA for vumeter rendering
|
||||
lda tt.envelope_index_c0,x cmp tt_InsReleaseIndexes-1,y bne _noEndOfSustain lda tt_InsSustainIndexes-1,y @_noEndOfSustain
|
||||
tay
|
||||
lda tt_InsFreqVolTable,y beq _endOfEnvelope iny @_endOfEnvelope
|
||||
sty tt.envelope_index_c0,x
|
||||
sta AUDV0,x
|
||||
sta AUDV0s,x -- EXTRA for vumeter rendering
|
||||
lsr lsr lsr lsr clc adc tt.cur_ins_c0,x sec sbc #8
|
||||
sta AUDF0,x
|
||||
sta AUDF0s,x -- EXTRA for vumeter rendering
|
||||
@_afterAudioUpdate
|
||||
dex
|
||||
bpl _updateLoop
|
||||
end
|
||||
|
||||
local function zic_init()
|
||||
if zic.c0init ~= 0 then lda#zic.c0init sta tt.cur_pat_index_c0 end
|
||||
if zic.c1init ~= 0 then lda#zic.c1init sta tt.cur_pat_index_c1 end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- display song name and author
|
||||
----------------------------------------------------------------------
|
||||
|
||||
section{ "font", align=256 } dc.b
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,-- <SPC>
|
||||
0x18,0x3c,0x66,0x7e,0x66,0x66,0x66,0x00,-- A
|
||||
0x7c,0x66,0x66,0x7c,0x66,0x66,0x7c,0x00,-- B
|
||||
0x3c,0x66,0x60,0x60,0x60,0x66,0x3c,0x00,-- C
|
||||
0x78,0x6c,0x66,0x66,0x66,0x6c,0x78,0x00,-- D
|
||||
0x7e,0x60,0x60,0x78,0x60,0x60,0x7e,0x00,-- E
|
||||
0x7e,0x60,0x60,0x78,0x60,0x60,0x60,0x00,-- F
|
||||
0x3c,0x66,0x60,0x6e,0x66,0x66,0x3c,0x00,-- G
|
||||
0x66,0x66,0x66,0x7e,0x66,0x66,0x66,0x00,-- H
|
||||
0x3c,0x18,0x18,0x18,0x18,0x18,0x3c,0x00,-- I
|
||||
0x1e,0x0c,0x0c,0x0c,0x0c,0x6c,0x38,0x00,-- J
|
||||
0x66,0x6c,0x78,0x70,0x78,0x6c,0x66,0x00,-- K
|
||||
0x60,0x60,0x60,0x60,0x60,0x60,0x7e,0x00,-- L
|
||||
0x63,0x77,0x7f,0x6b,0x63,0x63,0x63,0x00,-- M
|
||||
0x66,0x76,0x7e,0x7e,0x6e,0x66,0x66,0x00,-- N
|
||||
0x3c,0x66,0x66,0x66,0x66,0x66,0x3c,0x00,-- O
|
||||
0x7c,0x66,0x66,0x7c,0x60,0x60,0x60,0x00,-- P
|
||||
0x3c,0x66,0x66,0x66,0x66,0x3c,0x0e,0x00,-- Q
|
||||
0x7c,0x66,0x66,0x7c,0x78,0x6c,0x66,0x00,-- R
|
||||
0x3c,0x66,0x60,0x3c,0x06,0x66,0x3c,0x00,-- S
|
||||
0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x00,-- T
|
||||
0x66,0x66,0x66,0x66,0x66,0x66,0x3c,0x00,-- U
|
||||
0x66,0x66,0x66,0x66,0x66,0x3c,0x18,0x00,-- V
|
||||
0x63,0x63,0x63,0x6b,0x7f,0x77,0x63,0x00,-- W
|
||||
0x66,0x66,0x3c,0x18,0x3c,0x66,0x66,0x00,-- X
|
||||
0x66,0x66,0x66,0x3c,0x18,0x18,0x18,0x00,-- Y
|
||||
0x7e,0x06,0x0c,0x18,0x30,0x60,0x7e,0x00 -- Z
|
||||
|
||||
charset(" abcdefghijklmnopqrstuvwxyz", \x(x*8))
|
||||
local normtxt = function(txt)
|
||||
txt = txt:lower()
|
||||
local out = {}
|
||||
for i=1,#txt do
|
||||
local c = string.byte(txt:sub(i,i))
|
||||
if c < string.byte('a') or c > string.byte('z') then c = string.byte(' ') end
|
||||
table.insert(out, string.char(c))
|
||||
end
|
||||
local ex = 12 - #out
|
||||
for i=1,ex do
|
||||
if i&1 ~= 0 then table.insert(out, 1, ' ')
|
||||
else table.insert(out, ' ')
|
||||
end
|
||||
end
|
||||
return table.concat(out)
|
||||
end
|
||||
@@song_name byte(normtxt(zic.name))
|
||||
@@song_author byte(normtxt(zic.author))
|
||||
|
||||
local print_txt = tmp+1 -- text pointer, can cross
|
||||
local print_line_count=tmp -- number of lines to print
|
||||
local print_ptr = tmp+3 -- array of pointers to the characters
|
||||
-- a = line count
|
||||
@@print12
|
||||
sta print_line_count
|
||||
lda#6 sta NUSIZ0 sta NUSIZ1
|
||||
-- set MSB of font character addresses
|
||||
lda#font>>8 ldx#23 @_loadfont sta print_ptr,x dex dex bpl _loadfont
|
||||
-- position sprites
|
||||
samepage
|
||||
sta WSYNC
|
||||
ldx#6 @_delay dex bne _delay
|
||||
sta RESP0 nop sta RESP1 lda#0x70 sta HMP0 lda#0x60 sta HMP1 sta WSYNC sta HMOVE
|
||||
end
|
||||
@_loop
|
||||
-- load text line
|
||||
ldx#0 ldy#0 @_loadline lda (print_txt),y sta print_ptr,x inx inx iny cpy#12 bne _loadline
|
||||
lda#0x80 sta HMP0 sta HMP1
|
||||
ldy#0 samepage @_printline
|
||||
sta WSYNC sta HMOVE
|
||||
-- first scanline
|
||||
lda (print_ptr+2),y sta GRP0 lda (print_ptr+6),y sta GRP1
|
||||
lda (print_ptr+22),y tax sleep(6)
|
||||
lda (print_ptr+10),y sta GRP0 lda (print_ptr+14),y sta GRP1 lda (print_ptr+18),y sta GRP0 stx GRP1
|
||||
sta HMCLR sleep(8) sta HMOVE
|
||||
-- second scanline
|
||||
lda (print_ptr),y sta GRP0 lda (print_ptr+4),y sta GRP1
|
||||
lda (print_ptr+20),y tax lda#0x80 sta HMP0 sta HMP1 nop
|
||||
lda (print_ptr+8),y sta GRP0 lda (print_ptr+12),y sta GRP1 lda (print_ptr+16),y sta GRP0 stx GRP1
|
||||
iny cpy#8 bne _printline
|
||||
end
|
||||
dec print_line_count beq _end
|
||||
lda print_txt clc adc#12 sta print_txt lda print_txt+1 adc#0 sta print_txt+1
|
||||
jmp _loop
|
||||
@_end
|
||||
lda#0 sta GRP0 sta GRP1
|
||||
rts
|
||||
|
||||
----------------------------------------------------------------------
|
||||
-- equalizer anim
|
||||
----------------------------------------------------------------------
|
||||
|
||||
-- convert to freq: http://atariage.com/forums/topic/257526-musicsound-programming-question-atari-2600/
|
||||
-- maps AUDCi to 0-7 3 bits (<<5) value for wave length of: 1, 2, 6, 15, 31, 93, 465, 511
|
||||
@@wavlen samepage
|
||||
dc.b 0x00,0x60,0xC0,0xC0,0x20,0x20,0x80,0x80,
|
||||
0xF0,0x80,0x80,0x00,0x40,0x40,0xA0,0xA0
|
||||
end
|
||||
local wavelen_map = { 1, 2, 6, 15, 31, 93, 465, 511 }
|
||||
local freq_ranges = { 30, 60, 120, 240, 480, 960, 1920, 9999999 }
|
||||
local t = {}
|
||||
for i=0,255 do
|
||||
local wavelen = wavelen_map[(i>>5)+1]
|
||||
local note = (i&31)+1
|
||||
local freq = 3546894 / 114 / wavelen / note
|
||||
for x=1,9 do
|
||||
if freq <= freq_ranges[x] then
|
||||
t[#t+1] = x-1
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
section{'regfreq', align=256} byte(t)
|
||||
@@vm_pf2 samepage
|
||||
dc.b 0x00,0x80,0xC0,0xE0,0xF0,0xF8,0xFC,0xFE,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
end
|
||||
@@vm_pf1 samepage
|
||||
dc.b 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x01,0x03,0x07,0x0F,0x1F,0x3F,0x7F
|
||||
end
|
||||
@@vm_col samepage
|
||||
dc.b 0x3C,0x7C,0x9C,0xDC,0x2C,0x4C,0x6C,0xAC
|
||||
end
|
||||
local vumeter_tick = function()
|
||||
lda #0 ldy #15 @_vudec ldx vubars,y dex bmi _vudecskip stx vubars,y @_vudecskip dey bpl _vudec
|
||||
lda AUDF0s ldy AUDC0s ora wavlen,y tax ldy regfreq,x
|
||||
lda AUDV0s cmp vubars,y bcc _vuless0 sta vubars,y @_vuless0
|
||||
lda AUDF1s ldy AUDC1s ora wavlen,y tax ldy regfreq,x
|
||||
lda AUDV1s cmp vubars+8,y bcc _vuless1 sta vubars+8,y @_vuless1
|
||||
end
|
||||
local vumeter_draw = function()
|
||||
lda #ctrlpf.PF_MIRRORED sta CTRLPF
|
||||
ldy #7
|
||||
@_vudraw
|
||||
samepage
|
||||
lda #16 sta tmp
|
||||
@_vudraw1
|
||||
sta WSYNC
|
||||
lda vm_col,y sta COLUPF sleep(4)
|
||||
ldx vubars,y
|
||||
lda vm_pf1,x sta PF1
|
||||
lda vm_pf2,x sta PF2
|
||||
sleep(8)
|
||||
ldx vubars+8,y
|
||||
lda vm_pf2,x sta PF2
|
||||
lda vm_pf1,x sta PF1
|
||||
dec tmp bpl _vudraw1
|
||||
sta WSYNC lda #0 sta PF2 sta PF1
|
||||
sta WSYNC
|
||||
dey bpl _vudraw
|
||||
end
|
||||
lda #0 sta CTRLPF
|
||||
sta WSYNC sta WSYNC
|
||||
end
|
||||
|
||||
local tick = function()
|
||||
zic_tick()
|
||||
-- clamp to valid TIA range
|
||||
lda AUDC0s ;and #0x0f sta AUDC0s lda AUDC1s ;and #0x0f sta AUDC1s
|
||||
lda AUDF0s ;and #0x1f sta AUDF0s lda AUDF1s ;and #0x1f sta AUDF1s
|
||||
lda AUDV0s ;and #0x0f sta AUDV0s lda AUDV1s ;and #0x0f sta AUDV1s
|
||||
vumeter_tick()
|
||||
end
|
||||
|
||||
local kernel = function()
|
||||
lda#0x8a sta COLUP0 sta COLUP1
|
||||
setptr(song_author,print_txt) lda#1 jsr print12
|
||||
vumeter_draw()
|
||||
lda#0xaa sta COLUP0 sta COLUP1
|
||||
setptr(song_name,print_txt) lda#1 jsr print12
|
||||
end
|
||||
|
||||
@@main
|
||||
init()
|
||||
zic_init()
|
||||
@_frame
|
||||
overscan() vblank(tick) screen(kernel) jmp _frame
|
||||
|
||||
; -- needed if last instruction is implied
|
||||
writebin(filename..'.bin')
|
||||
writesym(filename..'.sym')
|
||||
print(stats)
|
||||
|
@ -577,7 +577,7 @@ syn match l65Opcode /\<sre\%(.[bw]\)\=\>/
|
||||
syn match l65Opcode /\<far\>/
|
||||
syn match l65Opcode /\<rtx\>/
|
||||
syn match l65Opcode /\<xsr\>/
|
||||
" Common alias, reomve if desired.
|
||||
" Common alias, remove if desired.
|
||||
syn match l65Opcode /\<dna\%(.[bw]\)\=\>/
|
||||
syn match l65Keyword /\<dnaimm\>/
|
||||
syn match l65Keyword /\<dnazpg\>/
|
||||
|
Loading…
x
Reference in New Issue
Block a user