Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MDFourier: Add MDF FDS and FDS configuration format #57

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ __pycache__/
/fc-mdf/*map.txt
/fc-mdf/mdfourier-*.nes
/fc-mdf/mdfourier.prg
/fc-mdf/*.dbg
/fc-mdf/*.fdb
/fc-mdf/obj/nes/*.s
/fc-mdf/obj/nes/*.sav
/fc-mdf/obj/nes/mdfourier*
/fc-mdf/*.nes
/fc-mdf/*.nsf
/fc-mdf/*.fds
/gameboy/obj/gb/*.z80
/gameboy/obj/gb/*.nam
/gameboy/obj/gb/*.iu
Expand All @@ -45,6 +53,7 @@ __pycache__/
/gba/compile_commands.json
/nes/obj/nes/*.s
/nes/obj/nes/*.sav
/nes/obj/nes/mdfourier*
/nes/obj/nes/last-commit*
/nes/*.dbg
/nes/*.fdb
Expand All @@ -55,11 +64,12 @@ __pycache__/
/nes/mdfourier4k.nes
/nes/mdfourier4k-chrrom.nes
/nes/240p-nes-others.7z
/nes/mdfourier4k-fdsheader.fds
/common/tools/dte
/common/tools/dte.exe
/nes-palpar/palpar.nes
/nes-palpar/obj/nes/*.sav
/nes-palpar/obj/nes/*.nam

# this is NES and Game Boy homebrew, not DSiWare
*.DS_Store
*.DS_Store
58 changes: 55 additions & 3 deletions fc-mdf/docs/sequence.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Test sequences
Test sequences
==============

Mapper detection
Expand Down Expand Up @@ -74,5 +74,57 @@ inspiration from that.

Disk System
-----------
Pending. Will need a whole different link script, as well as a way
to obtain a lawfully made copy of the BIOS with which to test.
1. Sync pulses (20 frames silence, 10 loops of 1 frame 1 kHz 8x
square wave and 1 frame silence, 20 frames silence)
2. 94-note chromatic scale, beginning at lowest
C (8.11 Hz) and ascending to out-of-tune A 7 octaves up
(1747.40 Hz) at 10 frames per note, followed by 10 frames silence.
Repeat for waveforms sine, square, and 32x square at volume 32.
TODO: increase silence before next test
3. Three DC offset pops for 20 frames, first with wave value $3F,
then $00, both at volume 32, phase resetted, and waveform halted.
Third DC pop silences second DC pop, testing for DC offset.
10 frames silence
TODO: halt waveform instead of setting to highest period
4. A (440 Hz) for 20 frames, halting and then resuming waveform
playback. Halting the waveform resets the phase.
Then, 10 frames silence
5. Pitch Slide from C (8.11 Hz) up at 8 period unit per frame
for 560 frames, then 10 frames silence. Repeat for sine, square,
sawtooth, and 32x square. 32x square tests aliasing and ultrasound
response, while the rest tests for general frequency response.
TODO: shorten length and add silence
6. db_fds, from rainwarrior's nes-audio-tests.
Loudest FDS square at A (439.94 Hz) for two seconds (12 frames).
Then 1 second of silence (6 frames).
Then loudest 2A03 pulse square at A (440.40 Hz) for two seconds (12
frames).
Then 1 second of silence (6 frames).
7. Relative phase test. Sawtooth wave note at C (65.29 hz) for 30
frames. 10 frames silence.
2A03 25% pulse note at C (65.42 Hz) for 30 frames.
10 frames silence.
8. Nonlinear FDS DAC test. "Sorted" sawtooth wave note at C (65.29 hz)
for 30 frames. 10 frames silence.
9. Envelope / Master volume test.
4 sawtooth wave notes of C (523.15 hz) for 40 frames with volume
gain of A, envelope enabled with direction decreasing.
(value $0A to $4080).
Each note decreases master volume (00, 01, 10, 11).
TODO: compare envelope with manual volume fade.
TODO: compare with reverse envelope and manual volume fade.
TODO: measure exact envelope length by writing to $4080 and
counting cycles
xx. Mod envelope tests
10. Modulator test.
NOTE: i don't know what i'm testing for exactly
TODO: mod envelope tests
TODO: mod overflow/underflow tests
4 notes of C (261.58 Hz) for 7 frames, each with varying
modulator properties.
a. sine wave, Dn-FT mod sine, mod depth of $01, mod period of $004
b. sine wave, FT "NEZPlug" mod sine, mod depth of $3F, mod period
of $265
c. sine wave, Dn-FT mod sine, mod depth of $3F, mod period of $265
d. saw wave, Dn-FT mod sine, mod depth of $3F, mod period of $04C
11. Repeat sync pulses
52 changes: 52 additions & 0 deletions fc-mdf/fds.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#
# Linker script for MDFourier alone (a 4 KiB ROM)
# Copyright 2010-2021 Damian Yerrick
# Modified for FDS by Persune 2023
# Based on code by Brad Smith 2021
#
# Copying and distribution of this file, with or without
# modification, are permitted in any medium without royalty
# provided the copyright notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
MEMORY {
# use first $10 zeropage locations as locals
ZP: start = $0010, size = $00E9, type = rw;
HEADER: start = 0, size = $0010, type = ro, file = %O, fill=yes, fillval=$00;
SIDE1A: start = $0000, size = 65500, type = ro, file = %O, fill=yes, fillval=$FF;
RAM: start = $0300, size = $0500, type = rw;

PRG0: start = $C000, size = $1FF6, type = rw, file = "";
VEC1: start = $DFF6, size = $000A, type = rw, file = "";
CHR2: start = $0000, size = $1000, type = rw, file = "";
CHR3: start = $1000, size = $1000, type = rw, file = "";
CHK4: start = $2000, size = $0200, type = rw, file = "";
}

SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
BSS: load = RAM, type = bss, define = yes, align = $100;

FDSHEADER: load = HEADER, type = ro, align = $10;

SIDE1A: load = SIDE1A, type = ro;

FILE0_HDR: load = SIDE1A, type = ro;
FILE0_DAT: load = SIDE1A, run = PRG0, define = yes;

FILE1_HDR: load = SIDE1A, type = ro;
FILE1_DAT: load = SIDE1A, run = VEC1, define = yes;

FILE2_HDR: load = SIDE1A, type = ro;
FILE2_DAT: load = SIDE1A, run = CHR2, define = yes;

FILE3_HDR: load = SIDE1A, type = ro;
FILE3_DAT: load = SIDE1A, run = CHR3, define = yes;

FILE4_HDR: load = SIDE1A, type = ro;
FILE4_DAT: load = SIDE1A, run = CHK4, define = yes;
}

FILES {
%O: format = bin;
}
36 changes: 36 additions & 0 deletions fc-mdf/fds_nsf.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#
# Linker script for NSF
# Modified for NSF FDS by Persune 2024
# Copyright 2011 Damian Yerrick
#
# Copying and distribution of this file, with or without
# modification, are permitted in any medium without royalty
# provided the copyright notice and this notice are preserved.
# This file is offered as-is, without any warranty.
#
MEMORY {
ZP: start = $10, size = $f0, type = rw;
# use first $10 zeropage locations as locals
RAM: start = $0300, size = $0500, type = rw;

HEADER: start = $0000, size = $0080, type = ro, file = "%O_nsfhdr.bin", fill=yes, fillval=$00;
ROM7: start = $C000, size = $3FF0, type = rw, file = "%O.bin", fillval=$FF, define=yes;
FOOTER: start = $0000, size = $4000, type = ro, file = "%O.bin", fillval=$00;
}

SEGMENTS {
NSFHDR: load = HEADER, type = ro, align = $80;
NSFEFOOTER: load = FOOTER, type = ro, optional = yes;
ZEROPAGE: load = ZP, type = zp;
BSS: load = RAM, type = bss, define = yes, align = $100;
CODE: load = ROM7, type = ro, align = 64;
RODATA: load = ROM7, type = ro, align = 64;
DMC: load = ROM7, type = ro, align = 64, optional = yes;
}

FILES {
"%O.bin": format = bin;
# align debug symbols by separating header and concatenating later
"%O_nsfhdr.bin": format = bin;
}

84 changes: 76 additions & 8 deletions fc-mdf/makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,20 @@ version := wip
defaultmapper := mmc5
allmappers := mmc5 vrc6 vrc6ed2 vrc7 fme7 n163
objlist := init main bg

objlistnsf := mdfouriernsf mdfourier ntscPeriods
objlistnsffds := mdfourier-common mdfouriernsf-fds mdfourier-fds \
ntscPeriods ntscFDSPeriods
objlistmdffds4kfdsh := mdfourier4kfe-fds-fdsheader \
mdfourier-common-fdsheader mdfourier-fds-fdsheader \
padsnodas-fdsheader ntscPeriods-fdsheader ntscFDSPeriods-fdsheader

AS65:=ca65
LD65:=ld65
CFLAGS65:=-g
LFLAGS65:=-v
objdir := obj/nes
srcdir := src
extdir := ../nes
imgdir := tilesets

# Windows needs .exe suffixed to the names of executables; UNIX does
Expand All @@ -26,6 +37,10 @@ EMU:=fceux
DEBUGEMU := ~/.wine/drive_c/Program\ Files\ \(x86\)/FCEUX/fceux.exe
endif

objlistnsfo := $(foreach o,$(objlistnsf),$(objdir)/$(o).o)
objlistnsffdso := $(foreach o,$(objlistnsffds),$(objdir)/$(o).o)
objlistmdffds4kfdsho := $(foreach o,$(objlistmdffds4kfdsh),$(objdir)/$(o).o)

# Phony targets

.PHONY: run debug all clean dist
Expand All @@ -36,10 +51,11 @@ run: $(title)-$(defaultmapper).nes
debug: $(title)-$(defaultmapper).nes
$(DEBUGEMU) $<

all: $(foreach o,$(allmappers),$(title)-$(o).nes)
all: $(foreach o,$(allmappers),$(title)-$(o).nes) \
mdfourier-fds.nsf mdfourier-fds.fds

clean:
-rm $(objdir)/*.o $(objdir)/*.chr $(title).prg
-rm $(objdir)/*.o $(objdir)/*.s $(objdir)/*.chr $(title).prg

dist: \
$(foreach o,$(allmappers),$(title)-$(o).nes) $(objdir)/index.txt \
Expand All @@ -50,18 +66,44 @@ dist: \
$(objdir)/%16.chr: $(imgdir)/%.png
$(PY) ../common/tools/pilbmp2nes.py $< --planes "0;1" -H16 -o $@

# Assembly
$(objdir)/mdf4k%_chr.chr: $(imgdir)/mdf4k%_chr.png
$(PY) ../common/tools/pilbmp2nes.py -H 16 --planes "0" $< $@

$(objdir)/%.o: $(srcdir)/%.s $(srcdir)/nes.inc $(srcdir)/global.inc
ca65 -o $@ $<
# source files

$(objdir)/%.o: $(objdir)/%.s
ca65 -o $@ $<
# MDFourier needs the period lookup table
$(objdir)/ntscPeriods.s: $(extdir)/tools/mktables.py
$(PY) $< period $@

$(objdir)/ntscFDSPeriods.s: $(extdir)/tools/mktables.py
$(PY) $< fdsperiod $@

$(objdir)/ntscPeriods-fdsheader.s: $(extdir)/tools/mktables.py
$(PY) $< periodfdsc $@

$(objdir)/ntscFDSPeriods-fdsheader.s: $(extdir)/tools/mktables.py
$(PY) $< fdsperiodfdsc $@

$(objdir)/mdfourier4k-fdsheader.cfg: $(extdir)/mdfourier4k-fdsheader.cfg
cp $^ $@

$(objdir)/padsnodas.s: $(extdir)/$(srcdir)/padsnodas.s
cp $^ $@

# Includes

$(objdir)/init.o: $(objdir)/fizztersmboldmono16.chr

$(objdir)/mdfourier.o: $(objdir)/instsamp1.dmc
$(objdir)/instsamp1.dmc: $(extdir)/audio/instsamp1.dmc
cp $^ $@

$(objdir)/mdfourier4kfe-chrrom.o $(objdir)/mdfourier4kfe-common.o $(objdir)/mdfourier4kfe-common-fdsheader.o: \
$(objdir)/mdf4k_chr.chr

$(objdir)/mdfourier4kfe-fds.o $(objdir)/mdfourier4kfe-fds-fdsheader.o: \
$(objdir)/mdf4k-fds_chr.chr

# Linking

$(title).prg: vrc7.x $(foreach o,$(objlist),$(objdir)/$(o).o)
Expand All @@ -70,6 +112,32 @@ $(title).prg: vrc7.x $(foreach o,$(objlist),$(objdir)/$(o).o)
$(title)-%.nes: tools/mkines.py $(title).prg
$(PY) $^ $* $@

mdf_nsf_map.txt mdfourier.nsf: $(extdir)/nsf.cfg $(objlistnsfo)
$(LD65) $(LFLAGS65) -o $(objdir)/mdfourier -m mdf_nsf_map.txt --dbgfile mdfourier.dbg -C $^
cat $(objdir)/mdfourier_header $(objdir)/mdfourier > mdfourier.nsf

mdf_fds_nsf_map.txt mdfourier-fds.nsf: fds_nsf.cfg $(objlistnsffdso)
$(LD65) $(LFLAGS65) -o $(objdir)/mdfourier-fds -m mdf_fds_nsf_map.txt --dbgfile mdfourier-fds.dbg -C $^
cat $(objdir)/mdfourier-fds_nsfhdr.bin $(objdir)/mdfourier-fds.bin > mdfourier-fds.nsf

mdf_fds_fdsh_map.txt mdfourier-fds.fds: fds.cfg $(objlistmdffds4kfdsho)
$(LD65) $(LFLAGS65) -o mdfourier-fds.fds -m mdffdshmap.txt \
--dbgfile mdfourier-fds.dbg -C $^

# Assembly

$(objdir)/%.o: $(srcdir)/%.s $(srcdir)/nes.inc $(srcdir)/global.inc
$(AS65) $(CFLAGS65) -o $@ $<

$(objdir)/%.o: $(objdir)/%.s
$(AS65) $(CFLAGS65) -o $@ $<

$(objdir)/%-fdsheader.o: $(srcdir)/%.s $(srcdir)/nes.inc $(srcdir)/global.inc
$(AS65) $(CFLAGS65) $< -DFDSHEADER=1 -o $@

$(objdir)/padsnodas-fdsheader.o: $(extdir)/$(srcdir)/pads.s $(srcdir)/nes.inc $(srcdir)/global.inc
$(AS65) $(CFLAGS65) $< -o $@ -DUSE_DAS=0 -DUSE_2P=0 -DFDSHEADER=1

# Packaging

$(objdir)/index.txt: makefile
Expand Down
28 changes: 28 additions & 0 deletions fc-mdf/src/global.inc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,34 @@ MAPPER_N163 = 6
.global ppu_puts_ay, ppu_puts_0, ppu_putchar, ppu_newline
.global OAM, ppu_clear_oam

IS_MULTICART = 0

; main.s
.global OAM
.global main, nmi_handler, irq_handler
.globalzp cur_keys, new_keys, das_keys, das_timer
.globalzp oam_used, nmis, tvSystem

; mdfourierfe.s and mdfourier.s
.global do_mdfourier, mdfourier_present
.global mdfourier_init_apu, mdfourier_run, mdfourier_ready_tone
.global mdfourier_push_apu
.global mdfourier_good_phase
.globalzp test_state
SIZEOF_TEST_STATE = 24
FDS_OFFSET = (.defined(FDSHEADER) = 1) * 4
; due to FDS BIOS using the triangle, the phase is trash on cold boot
INITIAL_GOOD_PHASE = (IS_MULTICART = 0) && (.defined(FDSHEADER) = 0)

; ntscPeriods.s
.global periodTableLo, periodTableHi

; ntscFDSPeriods.s
.global fdsPeriodTableLo, fdsPeriodTableHi

; pads.s
.global read_pads, autorepeat




Expand Down
Loading