From 9c576ef77419b15cffd39d6b8729947f96822c5b Mon Sep 17 00:00:00 2001 From: g012 Date: Wed, 3 Jan 2018 20:34:09 +0100 Subject: [PATCH] [NES] Revamped and tested all GxROM PRG bank switching, and added a sample. Added asserts in 6502.lua. --- .travis.yml | 13 +---- 6502.lua | 2 + nes.l65 | 80 ++++++++++++++++------------ samples/nes_bank2.l65 | 118 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 44 deletions(-) create mode 100644 samples/nes_bank2.l65 diff --git a/.travis.yml b/.travis.yml index 939fe3d..e67f384 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/6502.lua b/6502.lua index 6fed81b..d7d4548 100644 --- a/6502.lua +++ b/6502.lua @@ -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 diff --git a/nes.l65 b/nes.l65 index 06305fe..972e1db 100644 --- a/nes.l65 +++ b/nes.l65 @@ -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 diff --git a/samples/nes_bank2.l65 b/samples/nes_bank2.l65 new file mode 100644 index 0000000..52c529e --- /dev/null +++ b/samples/nes_bank2.l65 @@ -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 -- + 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)