mirror of
https://github.com/g012/l65.git
synced 2024-12-27 04:29:37 +00:00
Added first version of NES lib and hello world sample.
This commit is contained in:
parent
d27e4ce8d1
commit
cbe967a074
@ -9,7 +9,7 @@ set(L65_BINARY_DIR ${PROJECT_BINARY_DIR})
|
||||
|
||||
set(L65_VERSION_MAJOR "1")
|
||||
set(L65_VERSION_MINOR "2")
|
||||
set(L65_VERSION_REVISION "1")
|
||||
set(L65_VERSION_REVISION "2")
|
||||
set(L65_VERSION "${L65_VERSION_MAJOR}.${L65_VERSION_MINOR}.${L65_VERSION_REVISION}")
|
||||
configure_file("${L65_SOURCE_DIR}/l65cfg.lua.in" "${L65_BINARY_DIR}/l65cfg.lua")
|
||||
|
||||
|
1
main.c
1
main.c
@ -145,6 +145,7 @@ static struct script { const char *name; int t; const char *data; size_t sz; }
|
||||
SRC_LUA(dkjson),
|
||||
SRC_LUA(l65cfg),
|
||||
SRC_LUA(re),
|
||||
SRC_L65(nes),
|
||||
SRC_L65(vcs),
|
||||
};
|
||||
#undef SRC_LUA
|
||||
|
181
nes.l65
Normal file
181
nes.l65
Normal file
@ -0,0 +1,181 @@
|
||||
-- set cpu to 6502
|
||||
cpu = require "6502"
|
||||
setmetatable(_ENV, cpu)
|
||||
|
||||
nes = {
|
||||
OAM = 0x200, -- 0x100 bytes
|
||||
RAM = 0x300, -- 0x500 bytes + ZP 0x100 bytes + Stack 0x100 bytes + OAM 0x100 bytes = 0x800 bytes
|
||||
|
||||
-- 2C02 PPU
|
||||
PPUCNT0 = 0x2000,
|
||||
PPUCNT1 = 0x2001,
|
||||
PPUSTAT = 0x2002,
|
||||
SPRADDR = 0x2003,
|
||||
SPRIO = 0x2004,
|
||||
BGSCROL = 0x2005,
|
||||
PPUADDR = 0x2006,
|
||||
PPUIO = 0x2007,
|
||||
|
||||
-- 2A03 / 2A07 CPU+APU
|
||||
SQ1VOL = 0x4000,
|
||||
SQ1SWEEP = 0x4001,
|
||||
SQ1LO = 0x4002,
|
||||
SQ1HI = 0x4003,
|
||||
SQ2VOL = 0x4004,
|
||||
SQ2SWEEP = 0x4005,
|
||||
SQ2LO = 0x4006,
|
||||
SQ2HI = 0x4007,
|
||||
TRILINEAR = 0x4008,
|
||||
TRILO = 0x400A,
|
||||
TRIHI = 0x400B,
|
||||
NOISEVOL = 0x400C,
|
||||
NOISELO = 0x400E,
|
||||
NOISEHI = 0x400F,
|
||||
DMCFREQ = 0x4010,
|
||||
DMCRAW = 0x4011,
|
||||
DMCSTART = 0x4012,
|
||||
DMCLEN = 0x4013,
|
||||
SPRDMA = 0x4014,
|
||||
SNDCNT = 0x4015,
|
||||
SPECIO1 = 0x4016,
|
||||
SPECIO2 = 0x4017,
|
||||
|
||||
SRAM = 0x6000, -- 0x2000 bytes
|
||||
ROM = 0x8000, -- 0x8000 bytes
|
||||
|
||||
-- PPU Memory declarations
|
||||
CHAR0 = 0x0000, -- 0x1000 bytes
|
||||
CHAR1 = 0x1000, -- 0x1000 bytes
|
||||
SCREEN0 = 0x2000, -- 0x400 bytes
|
||||
SCREEN1 = 0x2400, -- 0x400 bytes
|
||||
SCREEN2 = 0x2800, -- 0x400 bytes
|
||||
SCREEN3 = 0x2C00, -- 0x400 bytes
|
||||
BGPAL = 0x3F00, -- 0x10 bytes
|
||||
OBJPAL = 0x3F10, -- 0x10 bytes
|
||||
}
|
||||
do
|
||||
local symbols = cpu.symbols
|
||||
for k,v in pairs(nes) do symbols[k] = v end
|
||||
end
|
||||
|
||||
vblank_waitend = function()
|
||||
local l=label() lda PPUSTAT bpl l
|
||||
end
|
||||
|
||||
ppu_addr = function(addr)
|
||||
lda #addr>>8 sta PPUADDR
|
||||
if addr&0xff ~= addr>>8 then lda #addr&0xff end
|
||||
sta PPUADDR
|
||||
end
|
||||
|
||||
oam_clear = function()
|
||||
ldx #0 lda #0xf8
|
||||
local l=label() sta OAM,x inx inx inx inx bne l
|
||||
end
|
||||
|
||||
oam_flush = function()
|
||||
lda #0 sta SPRADDR lda #2 sta SPRDMA
|
||||
end
|
||||
|
||||
init = function()
|
||||
sei cld
|
||||
ldx #0x40 stx SPECIO2
|
||||
ldx #0xff txs inx stx PPUCNT0 stx PPUCNT1 stx DMCFREQ vblank_waitend()
|
||||
-- stop APU channels
|
||||
lda #0 sta SNDCNT
|
||||
-- clear CPU RAM
|
||||
@_zeroram
|
||||
sta 0x00,x
|
||||
sta 0x0100,x sta 0x0200,x sta 0x0300,x sta 0x0400,x
|
||||
sta 0x0500,x sta 0x0600,x sta 0x0700,x
|
||||
inx bne _zeroram
|
||||
vblank_waitend()
|
||||
-- clear OAM
|
||||
oam_clear() oam_flush()
|
||||
-- clear PPU RAM
|
||||
lda PPUSTAT ppu_addr(0x2000) tax ldy #0x10
|
||||
@_zeroppu
|
||||
sta PPUIO dex bne _zeroppu dey bne _zeroppu
|
||||
-- reset latch
|
||||
lda PPUSTAT
|
||||
end
|
||||
|
||||
-- NES 2.0 (backward compatible with iNES)
|
||||
-- https://wiki.nesdev.com/w/index.php/NES_2.0
|
||||
header = function(t)
|
||||
if not t then t = {} end
|
||||
local logsz = function(sz)
|
||||
assert(sz >= 0 and sz <= 1048576, "invalid size: " .. sz .. ", expected [0, 1048576]")
|
||||
if sz < 1 then return 0 end
|
||||
if sz <= 128 then return 1 end
|
||||
return math.ceil(math.log(sz/64, 2))
|
||||
end
|
||||
-- mapper
|
||||
local mi1 = t.mapperid or 0
|
||||
assert(mi1 >= 0 and mi1 < 4096, "invalid mapper id: " .. mi1 .. ", expected [0, 4095]")
|
||||
local ms1 = t.submapperid or 0
|
||||
assert(ms1 >= 0 and ms1 < 16, "invalid submapper id: " .. ms1 .. ", expected [0, 15]")
|
||||
local mapper6 = (mi1 & 0xf) << 4
|
||||
local mapper7 = mi1 & 0xf0
|
||||
local mapper8 = (mi1 >> 8) | (ms1 << 4)
|
||||
-- prgsize
|
||||
local prgsize = math.tointeger((t.prgsize or 16384) / 16384)
|
||||
assert(prgsize, "prgsize must be a multiple of 16384")
|
||||
-- chrsize
|
||||
local chrsize = math.tointeger((t.chrsize or 8192) / 8192)
|
||||
assert(chrsize, "chrsize must be a multiple of 8192")
|
||||
-- wramsize (not battery-backed)
|
||||
local wramsize = logsz(t.wramsize or 0)
|
||||
-- bramsize (battery-backed)
|
||||
local bramsize = logsz(t.bramsize or 0)
|
||||
-- chrbramsize (battery-backed)
|
||||
local chrbramsize = logsz(t.chrbramsize or 0)
|
||||
-- chrramsize (not battery-backed)
|
||||
local chrramsize = logsz(t.chrramsize or (chrbramsize==0 and chrsize==0 and 8192 or 0))
|
||||
local battery_bit = bramsize == 0 and chrbramsize == 0 and 0 or 2
|
||||
-- mirror: 'H' for horizontal mirroring, 'V' for vertical mirroring
|
||||
-- '4' for four-screen VRAM, 218 for four-screen and vertical
|
||||
local mirror = (t.mirror or 'h'):lower()
|
||||
mirror = ({ h=0, v=1, ['4']=8, [218]=9 })[mirror]
|
||||
assert(mirror, "invalid mirror mode: " .. mirror .. ", expected 'H', 'V', '4', or 218")
|
||||
-- tv: 'N' for NTSC, 'P' for PAL, 'NP' for both preferring NTSC, 'PN' for both preferring PAL
|
||||
local tv, tvm = 0, (t.tv or 'n'):lower()
|
||||
assert(tvm=='n' or tvm=='p' or tvm=='np' or tvm=='pn', "invalid tv mode: " .. tostring(t.tv) .. ", expected 'N', 'P', 'NP' or 'PN'")
|
||||
if tvm[1] == 'p' then tv = 1 end
|
||||
if #tvm > 1 then tv = tv + 2 end
|
||||
|
||||
@@header -- size: 16 bytes
|
||||
dc.b 0x4e, 0x45, 0x53 -- 'NES'
|
||||
dc.b 0x1a
|
||||
dc.b prgsize, chrsize
|
||||
dc.b mapper6 | mirror | battery_bit
|
||||
dc.b mapper7 | 8
|
||||
dc.b mapper8
|
||||
dc.b ((chrsize >> 4) & 0xF0) | ((prgsize >> 8) & 0x0F)
|
||||
dc.b (bramsize << 4) | wramsize
|
||||
dc.b (chrbramsize << 4) | chrramsize
|
||||
dc.b tv, 0, 0, 0
|
||||
|
||||
-- update table with defaulted values
|
||||
t.prgsize = prgsize
|
||||
t.chrsize = chrsize
|
||||
t.wramsize = wramsize
|
||||
t.bramsize = bramsize
|
||||
t.chrbramsize = chrbramsize
|
||||
t.chrramsize = chrramsize
|
||||
end
|
||||
|
||||
mappers = {}
|
||||
|
||||
mappers.NROM = function(prgsize)
|
||||
if not prgsize then prgsize = 16384 end
|
||||
if not chrsize then chrsize = 8192 end
|
||||
assert(prgsize == 16384 or prgsize == 32768)
|
||||
local prgstart = 0x10000 - prgsize
|
||||
hdrrom = location{prgstart - 16, prgstart - 1, name='header'}
|
||||
header{ prgsize = prgsize }
|
||||
prgrom = location{prgstart, 0xffff, name='prgrom'}
|
||||
section{"vectors", org=0xfffa} dc.w nmi, main, irq
|
||||
chrrom = location{0x10000, 0x10000 + chrsize-1, name='chrrom'}
|
||||
end
|
||||
mappers[0] = mappers.NROM
|
BIN
samples/nes_ascii.chr
Normal file
BIN
samples/nes_ascii.chr
Normal file
Binary file not shown.
38
samples/nes_hello.l65
Normal file
38
samples/nes_hello.l65
Normal file
@ -0,0 +1,38 @@
|
||||
require'nes'
|
||||
|
||||
mappers.NROM()
|
||||
|
||||
location(chrrom)
|
||||
|
||||
do
|
||||
-- nes_ascii.chr: MIT License Copyright (c) 2016 Doug Fraker, www.nesdoug.com
|
||||
local f = assert(io.open('nes_ascii.chr', 'rb'))
|
||||
local d = f:read('*a') f:close()
|
||||
@@chrdata byte(d)
|
||||
end
|
||||
|
||||
location(prgrom)
|
||||
@@nmi rti
|
||||
@@irq rti
|
||||
|
||||
local hello = "Hello World!"
|
||||
@@text byte(hello)
|
||||
|
||||
@@main
|
||||
init()
|
||||
--lda#0x80 sta PPUSTAT -- enable VBlank IRQ on NMI vector
|
||||
-- load BG palette in PPU RAM
|
||||
ppu_addr(BGPAL)
|
||||
for _,v in ipairs{ 0x1f, 0x00, 0x10, 0x20 } do lda #v sta PPUIO end
|
||||
-- load screen text in PPU RAM 0x21CA
|
||||
ppu_addr(0x21ca)
|
||||
ldy #0 @_loadtxt lda text,y sta PPUIO iny cpy ##hello bne _loadtxt
|
||||
-- reset scroll position
|
||||
ppu_addr(0) sta BGSCROL sta BGSCROL
|
||||
-- turn screen on
|
||||
lda #0x90 sta PPUCNT0 lda #0x1e sta PPUCNT1
|
||||
-- idle
|
||||
@_loop jmp _loop
|
||||
|
||||
writebin(filename..'.nes')
|
||||
print(stats)
|
BIN
samples/nes_hello.nes
Normal file
BIN
samples/nes_hello.nes
Normal file
Binary file not shown.
BIN
samples/nespal.act
Normal file
BIN
samples/nespal.act
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user