[NES] Revamped and tested all GxROM PRG bank switching, and added a sample.

Added asserts in 6502.lua.
This commit is contained in:
g012 2018-01-03 20:34:09 +01:00
parent c888a63ee3
commit 9c576ef774
4 changed files with 169 additions and 44 deletions

View File

@ -8,18 +8,7 @@ compiler:
script:
- cmake . -DCMAKE_BUILD_TYPE=Release
- make
- cd samples
- ../l65 vcs_banks.l65
- ../l65 vcs_basic.l65
- ../l65 vcs_flush.l65
- ../l65 vcs_hello.l65
- ../l65 vcs_hooks.l65
- ../l65 vcs_music.l65
- ../l65 vcs_mcart.l65
- ../l65 vcs_spr48.l65
- ../l65 nes_hello.l65
- ../l65 nes_bank1.l65
- cd ..
- cd samples; for f in *.l65; do echo $f; ../l65 $f || break; done; cd ..
- cp l65 l65-$TRAVIS_TAG-$TRAVIS_OS_NAME
deploy:
provider: releases

View File

@ -515,6 +515,8 @@ end
-- -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

80
nes.l65
View File

@ -447,18 +447,6 @@ mappers.GxROM = function(t)
hdrrom = location{0x7ff0, 0x7fff, name='header'}
header(t)
local bc = t.prgsize//0x8000
for bi=0,bc-1 do
local o,ix = 0x8000 + bi*0x8000, bc-1-bi
_ENV['prgrom'..ix] = location{o, o+0x7fff, rorg=0x8000, name='prgrom'..ix}
section{"vectors"..ix, org=o+0x8000-6} dc.w nmi, main, irq
section{"bankbytes"..ix, org=o+0x8000-6-16} samepage -- for handling bus conflicts
dc.b 0x00, 0x01, 0x02, 0x03
dc.b 0x10, 0x11, 0x12, 0x13
dc.b 0x20, 0x21, 0x22, 0x23
dc.b 0x30, 0x31, 0x32, 0x33
end
end
prgrom = prgrom0
local cc = t.chrsize//0x2000
local ci, chrstart = 0, 0x8000 + bc*0x8000
local chrmap = t.chrmap or function(ci) return ci*0x1000, 0x1000, (ci&1)*0x1000 end
@ -471,38 +459,66 @@ mappers.GxROM = function(t)
until off + sz >= t.chrsize
chrrom = chrrom0
-- RAM address of bank register copy, to switch using A instead of immediate
bankregister_shadow = -1
-- if bankregister_shadow is negative, only immediate bankswitching is available
bankregister = 0
bankregister_shadow = -1
-- otherwise, just set the value directly: xxPPxxCC in A, xxxxPPCC in X with sta bankbytes0,x
function switchroms(prgbankix, chrbankix)
if prgbankix then
assert(prgbankix < bc) prgbankix = bc-1-prgbankix
assert(chrbankix, "GxROM must specify both PRG and CHR roms to switch simultaneously")
assert(chrbankix < cc)
local br = prgbankix<<4 | chrbankix
ldx #br&3|br>>2 lda #br sta bankbytes0,x
else -- A contains 00PP00CC
if bankregister_shadow >= 0 then
sta bankregister_shadow -- bankregister_shadow = 00PP00CC
lsr lsr -- A = 0000PP00, c
-- compute bc-1-prgbankix (reverse indexing)
eor #0xff adc #(bc-1<<2)+1 -- negate and +bc-1 combined, NN = bc-1-PP: A = 0000NN00
ora bankregister_shadow ;and #0xf tax -- X = 0000NNCC
else -- use stack instead
tsx sta 0x100,x lsr lsr -- A = 0000PP00, s[0] = 00PP00CC, c
-- compute bc-1-prgbankix (reverse indexing)
eor #0xff adc #(bc-1<<2)+1 -- negate and +bc-1 combined, NN = bc-1-PP: A = 0000NN00
ora 0x100,x ;and #0xf tax -- X = 0000NNCC
end
lda bankbytes0,x sta bankbytes0,x -- A = 00NN00CC, from table
end
end
for bi=0,bc-1 do
local o,ix = 0x8000 + bi*0x8000, bc-1-bi
_ENV['prgrom'..ix] = location{o, o+0x7fff, rorg=0x8000, name='prgrom'..ix}
local start=section{"entry"..ix, org=o+0x8000-6-16-10} switchroms(0,0) if ix==0 then jmp main end
section{"vectors"..ix, org=o+0x8000-6} dc.w "nmi"..ix, start, "irq"..ix
section{"bankbytes"..ix, org=o+0x8000-6-16} samepage -- for handling bus conflicts
dc.b 0x00, 0x01, 0x02, 0x03
dc.b 0x10, 0x11, 0x12, 0x13
dc.b 0x20, 0x21, 0x22, 0x23
dc.b 0x30, 0x31, 0x32, 0x33
end
end
prgrom = prgrom0
function switchprgrom(bankix)
if bankix then
assert(bankix < bc)
bankregister = (bankregister & ~0x30) | (bankix << 4)
ldx #bankregister&3|bankregister>>2 lda #bankregister sta bankbytes0,x
lda #bc-1-bankix
else
assert(bankregister_shadow >= 0, "no RAM slot assigned to bankregister_shadow")
tay lda bankregister_shadow ;and #3 sta bankregister_shadow
tya asl asl ora bankregister_shadow tax
;and #0xc asl asl ora bankregister_shadow sta bankregister_shadow
sta bankbytes0,x
clc eor #0xff adc #bc -- bc-1 - A
end
assert(bankregister_shadow >= 0, "no RAM slot assigned to bankregister_shadow")
tay lda bankregister_shadow ;and #3 sta bankregister_shadow
tya asl asl ora bankregister_shadow tax
lda bankbytes0,x sta bankregister_shadow sta bankbytes0,x
end
function switchchrrom(bankix)
if bankix then
assert(bankix < cc)
bankregister = (bankregister & ~3) | bankix
ldx #bankregister&3|bankregister>>2 lda #bankregister sta bankbytes0,x
else
assert(bankregister_shadow >= 0, "no RAM slot assigned to bankregister_shadow")
tay lda bankregister_shadow lsr lsr sta bankregister_shadow
tya ora bankregister_shadow tax ;and #0xc
asl asl sta bankregister_shadow tya ora bankregister_shadow sta bankregister_shadow
sta bankbytes0,x
lda #bankix
end
end
mappers.init = function()
switchchrrom(0)
assert(bankregister_shadow >= 0, "no RAM slot assigned to bankregister_shadow")
tay lda bankregister_shadow lsr lsr sta bankregister_shadow
tya ora bankregister_shadow tax
lda bankbytes0,x sta bankregister_shadow sta bankbytes0,x
end
end
mappers[66] = mappers.GxROM

118
samples/nes_bank2.l65 Normal file
View File

@ -0,0 +1,118 @@
require'nes'
-- 2 32kB PRG roms
mappers.GxROM{ prgsize=(32*2)*1024 }
location(chrrom0)
local font = section("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
charset(" abcdefghijklmnopqrstuvwxyz", \x(x+(font.org - font.location.start) // 16))
local copytext = function(sec_text, text)
-- load screen text in PPU RAM 0x21CA
ppu_addr(0x21ca)
ldy #0 @_loadtxt lda sec_text,y sta PPUDATA iny cpy ##text bne _loadtxt
-- reset scroll position
ppu_addr(0) sta BGSCROL sta BGSCROL
end
-- RAM
joya = 0
--[[
BANK 0 - startup bank
]]
location(prgrom0)
local text0 = "bank one"
@@text0s byte(text0)
@@nmi0 @irq0 rti
local toprg1s = section("toprg1")
switchroms(1,0)
local fromprg1s = section("fromprg1")
jmp mainloop
@@main
init()
--lda#0x80 sta PPUSTAT -- enable VBlank IRQ on NMI vector
vblank_waitbegin()
-- load BG palette in PPU RAM
ppu_addr(BGPAL)
for _,v in ipairs{ 0x1f, 0x00, 0x10, 0x20 } do lda #v sta PPUDATA end
-- turn screen on
lda #0x0a sta PPUMASK -- show BG
-- idle
@mainloop
vblank_waitbegin()
copytext(text0s, text0)
read_joy_a(1) bcc _noswitch
lda joya bne _switch
lda #1 sta joya jmp toprg1
@_noswitch
lda #0 sta joya
@_switch
jmp mainloop
--[[
BANK 1
]]
location(prgrom1)
local text1 = "bank two"
@@text1s byte(text1)
@@nmi1 @irq1 rti
local toprg0s = section("toprg0")
relate(toprg0s, fromprg1s, 7) -- switchprgrom(immediate) takes 7 bytes
switchroms(0,0)
local fromprg0s = section("fromprg0")
relate(toprg1s, fromprg0s, 7)
jmp mainloop1
@mainloop1
vblank_waitbegin()
copytext(text1s, text1)
read_joy_a(1) bcc _noswitch
lda joya bne _switch
lda #1 sta joya jmp toprg0
@_noswitch
lda #0 sta joya
@_switch
jmp mainloop1
writebin(filename..'.nes')
writesym(filename..'.mlb', 'mesen')
writesym(filename..'.nes', 'fceux')
print(stats)