1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-05-17 12:12:43 +00:00

NES: update mappers

This commit is contained in:
Gyorgy Szombathelyi
2020-02-20 12:18:18 +01:00
parent 8b0c06f838
commit 0cb69d733e
14 changed files with 1358 additions and 369 deletions

View File

@@ -30,7 +30,7 @@ module cart_top (
output reg [7:0] prg_dout, // CPU Data Out
input [7:0] prg_from_ram, // PRG Data from RAM
output reg prg_allow, // PRG Allow write access
output reg prg_open_bus, // PRG Data Not Driven
output reg prg_bus_write, // PRG Data Driven
output reg prg_conflict, // PRG Data is ROM & prg_din
input chr_read, // Read from CHR
input chr_write, // Write to CHR
@@ -91,7 +91,7 @@ MMC0 mmc0(
//*****************************************************************************//
// Name : MMC1 //
// Mappers: 1, 155 //
// Mappers: 1, 155, 171 (hard wired vertical mirroring) //
// Status : Working //
// Notes : //
// Games : Simon's Quest //
@@ -99,7 +99,7 @@ MMC0 mmc0(
MMC1 mmc1(
.clk (clk),
.ce (ce),
.enable (me[155] | me[1]),
.enable (me[171] | me[155] | me[1]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
@@ -340,9 +340,10 @@ MMC5 mmc5(
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_in (mmc5_audio),
.audio_b (audio_out_b),
// Special ports
.audio_dout (mmc5_data),
.chr_din (chr_din),
.chr_write (chr_write),
.chr_dout_b (chr_dout_b),
@@ -414,10 +415,10 @@ Mapper15 map15(
//*****************************************************************************//
// Name : Bandai 16 //
// Mappers: 159, 16 //
// Mappers: 159, 153, 16 //
// Status : Working/EEPROM needs testing //
// Notes : //
// Games : SD Gundam Gaiden, Dragon Ball 3 //
// Games : SD Gundam Gaiden, Dragon Ball 3, Famicom Jump II //
//*****************************************************************************//
wire map16_prg_write, map16_ovr;
wire [7:0] map16_data_out;
@@ -425,7 +426,7 @@ wire [17:0] map16_mapper_addr;
Mapper16 map16(
.clk (clk),
.ce (ce),
.enable (me[159] | me[16]),
.enable (me[159] | me[153] | me[16]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
@@ -609,12 +610,12 @@ Mapper65 map65(
//*****************************************************************************//
// Name : GxROM //
// Mappers: 11, 38, 66, 86, 87, 101, 140 //
// Mappers: 11, 38, 46, 66, 86, 87, 101, 140 //
// Status : 38/66 - Working, 38/87/101/140 - Needs eval, 86 - No Audio Samples //
// Notes : //
// Games : Doraemon, Dragon Power, Sidewinder (145), Taiwan Mahjong 16 (149) //
//*****************************************************************************//
wire mapper66_en = me[11] | me[38] | me[86] | me[87] | me[101] | me[140] | me[66] | me[145] | me[149];
wire mapper66_en = me[11] | me[38] | me[46] | me[86] | me[87] | me[101] | me[140] | me[66] | me[145] | me[149];
Mapper66 map66(
.clk (clk),
.ce (ce),
@@ -728,7 +729,7 @@ Mapper69 map69(
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_in (ss5b_audio),
.audio_b (audio_out_b)
);
@@ -888,6 +889,37 @@ Mapper79 map79(
.audio_b (audio_out_b)
);
//*****************************************************************************//
// Name : Cony/Yoko (unlicensed) //
// Mappers: 83 //
// Status : Supports all submappers, could use further evaluation //
// Notes : No user ability to control dipswitch setting //
// Games : Fatal Fury 2, World Heroes 2, Dragon Ball Party //
//*****************************************************************************//
Mapper83 map83(
.clk (clk),
.ce (ce),
.enable (me[83]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
.prg_read (prg_read),
.prg_write (prg_write),
.prg_din (prg_din),
.prg_dout_b (prg_dout_b),
.prg_allow_b(prg_allow_b),
.chr_ain (chr_ain),
.chr_aout_b (chr_addr_b),
.chr_read (chr_read),
.chr_allow_b(chr_allow_b),
.vram_a10_b (vram_a10_b),
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_b (audio_out_b)
);
//*****************************************************************************//
// Name : Sunsoft //
// Mappers: 89, 93, 184 //
@@ -950,6 +982,37 @@ Mapper107 map107(
.audio_b (audio_out_b)
);
//*****************************************************************************//
// Name : GTROM //
// Mappers: 111 //
// Status : Passes all tests except reflash test //
// Notes : No LED or self-reflash support //
// Games : Super Homebrew War, Candelabra: Estoscerro, more homebrew //
//*****************************************************************************//
Mapper111 map111(
.clk (clk),
.ce (ce),
.enable (me[111]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
.prg_read (prg_read),
.prg_write (prg_write),
.prg_din (prg_din),
.prg_dout_b (prg_dout_b),
.prg_allow_b(prg_allow_b),
.chr_ain (chr_ain),
.chr_aout_b (chr_addr_b),
.chr_read (chr_read),
.chr_allow_b(chr_allow_b),
.vram_a10_b (vram_a10_b),
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_b (audio_out_b)
);
//*****************************************************************************//
// Name : Mapper 165 //
// Mappers: 165 //
@@ -1079,9 +1142,9 @@ Mapper234 map234(
//*****************************************************************************//
// Name : RAMBO1 (Tengen MMC3) //
// Mappers: 64, 158 //
// Status : Significant graphical errors //
// Status : Needs testing. Irq might be slightly off. //
// Notes : Consider merging with MMC3 //
// Games : Shinobi, Rolling Thunder, Klax //
// Games : Rolling Thunder, Klax, Skull and Crossbones, Alien Syndrome (158) //
//*****************************************************************************//
Rambo1 rambo1(
.clk (clk),
@@ -1203,7 +1266,7 @@ VRC3 vrc3(
//*****************************************************************************//
// Name : Konami VRC2/4 //
// Mappers: 21, 22, 23, 25 //
// Mappers: 21, 22, 23, 25, 27 (pirate of 23) //
// Status : Needs Evaluation //
// Notes : //
// Games : Wai Wai World 2, Twinbee 3, Contra (j), Gradius II (j) //
@@ -1211,7 +1274,7 @@ VRC3 vrc3(
VRC24 vrc24(
.clk (clk),
.ce (ce),
.enable (me[21] | me[22] | me[23] | me[25]),
.enable (me[21] | me[22] | me[23] | me[25] | me[27]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
@@ -1259,7 +1322,7 @@ VRC6 vrc6(
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_in (vrc6_audio),
.audio_b (audio_out_b)
);
@@ -1290,7 +1353,7 @@ VRC7 vrc7(
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_in (vrc7_audio),
.audio_b (audio_out_b)
);
@@ -1301,7 +1364,7 @@ VRC7 vrc7(
// Notes : This mapper requires submappers for correct operation //
// Games : Digital Devil Story, Battle Fleet, Famista //
//*****************************************************************************//
N106 n106(
N163 n163(
.clk (clk),
.ce (ce),
.enable (me[210] | me[19]),
@@ -1321,8 +1384,10 @@ N106 n106(
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_b (audio_out_b)
.audio_in (n163_audio),
.audio_b (audio_out_b),
// Special ports
.audio_dout (n163_data)
);
//*****************************************************************************//
@@ -1335,7 +1400,7 @@ N106 n106(
Mapper162 map162(
.clk (clk),
.ce (ce),
.enable (me[162] | me[163]),
.enable (me[162]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
@@ -1356,6 +1421,41 @@ Mapper162 map162(
.audio_b (audio_out_b)
);
//*****************************************************************************//
// Name : Nanjing 163 //
// Mappers: 163 //
// Status : Working //
// Notes : //
// Games : Final Fantasy VII (163), Pokemon Yellow (163) //
//*****************************************************************************//
Nanjing map163(
.clk (clk),
.ce (ce),
.enable (me[163]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
.prg_read (prg_read),
.prg_write (prg_write),
.prg_din (prg_din),
.prg_dout_b (prg_dout_b),
.prg_allow_b(prg_allow_b),
.chr_ain (chr_ain),
.chr_aout_b (chr_addr_b),
.chr_read (chr_read),
.chr_allow_b(chr_allow_b),
.vram_a10_b (vram_a10_b),
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_b (audio_out_b),
// Special Ports
.ppu_ce (ppu_ce),
.ppuflags (ppuflags)
);
//*****************************************************************************//
// Name : Waixing 164 //
// Mappers: 164 //
@@ -1520,7 +1620,7 @@ JYCompany jycompany(
// Name : Mapper 225 //
// Mappers: 225, 255 //
// Status : Working //
// Notes : Defining 225 as with 74'670 (4-byte RAM) and 255 as without //
// Notes : Defining 225 as with 74'670 (4-nybble RAM) and 255 as without //
// Games : 64-in-1 (225), 110-in-1 (255 - with glitched menu selection) //
//*****************************************************************************//
Mapper225 map225(
@@ -1575,15 +1675,138 @@ MapperFDS mapfds(
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (audio_in),
.audio_in (fds_audio),
.audio_b (audio_out_b),
// Special ports
.audio_dout (fds_data),
.diskside_auto_b (fds_diskside_auto),
.diskside (diskside),
.fds_busy (fds_busy),
.fds_eject (fds_eject)
);
//*****************************************************************************//
// Name : Mapper 31 //
// Mappers: 31 and NSF Player //
// Status : Testing //
// Notes : Uses Mapper 31.15 (submapper) for NSF Player; NSF 1.0 only //
// Games : Famicompo Pico 2014, NSF 1.0 //
//*****************************************************************************//
wire [5:0] exp_audioe;
NSF nsfplayer(
.clk (clk),
.ce (ce),
.enable (me[31]),
.flags (flags),
.prg_ain (prg_ain),
.prg_aout_b (prg_addr_b),
.prg_read (prg_read),
.prg_write (prg_write),
.prg_din (prg_din),
.prg_dout_b (prg_dout_b),
.prg_allow_b(prg_allow_b),
.chr_ain (chr_ain),
.chr_aout_b (chr_addr_b),
.chr_read (chr_read),
.chr_allow_b(chr_allow_b),
.vram_a10_b (vram_a10_b),
.vram_ce_b (vram_ce_b),
.irq_b (irq_b),
.flags_out_b(flags_out_b),
.audio_in (exp_audioe[5] ? ss5b_audio :
exp_audioe[4] ? n163_audio :
exp_audioe[3] ? mmc5_audio :
exp_audioe[2] ? fds_audio :
exp_audioe[1] ? vrc7_audio :
exp_audioe[0] ? vrc6_audio :
audio_in),
.exp_audioe (exp_audioe), // Expansion Enabled (0x0=None, 0x1=VRC6, 0x2=VRC7, 0x4=FDS, 0x8=MMC5, 0x10=N163, 0x20=SS5B
.audio_b (audio_out_b),
.fds_din (fds_data)
);
wire [15:0] ss5b_audio;
SS5b_mixed snd_5bm (
.clk(clk),
.ce(ce),
.enable(me[69] | (me[31] && exp_audioe[5])),
.wren(prg_write),
.addr_in(prg_ain),
.data_in(prg_din),
.audio_in(audio_in),
.audio_out(ss5b_audio)
);
wire [15:0] n163_audio;
wire [7:0] n163_data;
namco163_mixed snd_n163 (
.clk(clk),
.ce(ce),
.submapper(flags[24:21]),
.enable(me[19] | (me[31] && exp_audioe[4])),
.wren(prg_write),
.addr_in(prg_ain),
.data_in(prg_din),
.data_out(n163_data),
.audio_in(audio_in),
.audio_out(n163_audio)
);
wire [15:0] mmc5_audio;
wire [7:0] mmc5_data;
mmc5_mixed snd_mmc5 (
.clk(clk),
.ce(ce),
.enable(me[5] | (me[31] && exp_audioe[3])),
.wren(prg_write),
.rden(prg_read),
.addr_in(prg_ain),
.data_in(prg_din),
.data_out(mmc5_data),
.audio_in(audio_in),
.audio_out(mmc5_audio)
);
wire [15:0] fds_audio;
wire [7:0] fds_data;
fds_mixed snd_fds (
.clk(clk),
.ce(ce),
.enable(me[20] | (me[31] && exp_audioe[2])),
.wren(prg_write),
.addr_in(prg_ain),
.data_in(prg_din),
.data_out(fds_data),
.audio_in(audio_in),
.audio_out(fds_audio)
);
wire [15:0] vrc7_audio;
vrc7_mixed snd_vrc7 (
.clk(clk),
.ce(ce),
.enable(me[85] | (me[31] && exp_audioe[1])),
.wren(prg_write),
.addr_in(prg_ain),
.data_in(prg_din),
.audio_in(audio_in),
.audio_out(vrc7_audio)
);
wire [15:0] vrc6_audio;
vrc6_mixed snd_vrc6 (
.clk(clk),
.ce(ce),
.enable(me[24] | me[26] | (me[31] && exp_audioe[0])),
.wren(prg_write),
.addr_invert(me[26]),
.addr_in(prg_ain),
.data_in(prg_din),
.audio_in(audio_in),
.audio_out(vrc6_audio)
);
wire [6:0] prg_mask;
wire [6:0] chr_mask;
wire [255:0] me;
@@ -1625,7 +1848,7 @@ always @* begin
{diskside_auto} = {fds_diskside_auto};
// Behavior helper flags
{prg_conflict, prg_open_bus, has_chr_dout} = {flags_out_b[2], flags_out_b[1], flags_out_b[0]};
{prg_conflict, prg_bus_write, has_chr_dout} = {flags_out_b[2], flags_out_b[1], flags_out_b[0]};
// Address translation for SDRAM
if (prg_aout[21] == 1'b0)

View File

@@ -21,8 +21,9 @@ module MapperFDS(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
// Special ports
input [7:0] audio_dout,
inout [1:0] diskside_auto_b,
input [1:0] diskside,
input fds_busy,
@@ -38,7 +39,7 @@ assign vram_a10_b = enable ? vram_a10 : 1'hZ;
assign vram_ce_b = enable ? vram_ce : 1'hZ;
assign irq_b = enable ? irq : 1'hZ;
assign flags_out_b = enable ? flags_out : 16'hZ;
assign audio_b = enable ? 16'hFFFF - audio[16:1] : 16'hZ;
assign audio_b = enable ? audio[15:0] : 16'hZ;
assign diskside_auto_b = enable ? diskside_auto : 2'hZ;
wire [21:0] prg_aout, chr_aout;
@@ -47,9 +48,11 @@ wire chr_allow;
wire vram_a10;
wire vram_ce;
wire [7:0] prg_dout;
reg [15:0] flags_out = 0;
wire [15:0] flags_out = {14'd0, prg_bus_write, 1'b0};
wire prg_bus_write;
wire irq;
wire [1:0] diskside_auto;
wire [15:0] audio = audio_in;
wire nesprg_oe;
wire [7:0] neschrdout;
@@ -69,11 +72,11 @@ always @(posedge clk) begin
end
MAPFDS fds(m2[7], m2_n, clk, ~enable, prg_write, nesprg_oe, 0,
1, prg_ain, chr_ain, prg_din, 8'b0, prg_dout,
1, prg_ain, chr_ain, prg_din, 8'b0, prg_dout, prg_bus_write,
neschrdout, neschr_oe, chr_allow, chrram_oe, wram_oe, wram_we, prgram_we,
prgram_oe, chr_aout[18:10], prg_aout[18:0], irq, vram_ce, exp6,
0, 7'b1111111, 6'b111111, flags[14], flags[16], flags[15],
ce, prg_allow, audio_exp, diskside_auto, diskside, fds_busy, fds_eject);
ce, prg_allow, audio_dout, diskside_auto, diskside, fds_busy, fds_eject);
assign chr_aout[21:19] = 3'b100;
assign chr_aout[9:0] = chr_ain[9:0];
@@ -81,20 +84,6 @@ assign vram_a10 = chr_aout[10];
assign prg_aout[21:19] = prg_aout[18] ? 3'b111 : 3'b000; //Switch to Cart Ram for Disk access
//assign prg_aout[12:0] = prg_ain[12:0];
wire [11:0] audio_exp;
// XXX: This needs to be replaced with a proper ~2000hz LPF
lpf_aud fds_lpf
(
.CLK(clk),
.CE(ce),
.IDATA(16'hFFFF - {1'b0, audio_exp[11:0], audio_exp[11:9]}),
.ODATA(audio_exp_f)
);
wire [15:0] audio_exp_f;
wire [16:0] audio = audio_in + audio_exp_f;
endmodule
// Loopy's FDS mapper for the Power Pak mapFDS.v
@@ -116,6 +105,7 @@ module MAPFDS( //signal descriptions in powerpak.v
input [7:0] nesprgdin,
input [7:0] ramprgdin,
output reg [7:0] nesprgdout,
output prg_bus_write,
output [7:0] neschrdout,
output neschr_oe,
@@ -141,7 +131,8 @@ module MAPFDS( //signal descriptions in powerpak.v
input ce,// add
output prg_allow,
output [11:0] snd_level,
input [7:0] audio_dout,
//output [11:0] snd_level,
output reg [1:0] diskside_auto,
input [1:0] diskside,
input fds_busy,
@@ -158,7 +149,6 @@ module MAPFDS( //signal descriptions in powerpak.v
reg timer_irq;
reg [1:0] Wstate;
reg [1:0] Rstate;
wire [7:0] audio_dout;
assign chrram_we=!chrain[13] & neschr_wr;
assign chrram_oe=!chrain[13] & neschr_rd;
@@ -177,6 +167,10 @@ module MAPFDS( //signal descriptions in powerpak.v
reg [17:0] sideoffset;
wire [17:0] romoffset;
assign prg_bus_write = (fds_prg_bus_write | fds_audio_prg_bus_write);
reg fds_prg_bus_write;
wire fds_audio_prg_bus_write = (prgain >= 16'h4040 && prgain < 16'h4080) | (prgain >= 16'h4090 && prgain <= 16'h4097);
// Loopy's patched bios use a trick to catch requested diskside for games
// using standard bios load process.
// Unlicensed games sometimes doesn't use standard bios load process. This
@@ -245,7 +239,8 @@ wire match7=(prgain==16'hE233) & infinite_loop_on_E233 & (ramprgaout[18]==1'b0);
wire match8=(prgain==16'hE234) & infinite_loop_on_E233 & (ramprgaout[18]==1'b0);
wire match9=(prgain==16'hE235) & infinite_loop_on_E233 & (ramprgaout[18]==1'b0);
wire match10=prgain==16'h4029; //MiSTer Busy
always@*
always @* begin
fds_prg_bus_write = 1'b1;
case(1)
match0: nesprgdout={7'd0, timer_irq};
match1: nesprgdout={5'd0, disk_eject, diskend, disk_eject};
@@ -258,8 +253,13 @@ always@*
match8: nesprgdout=8'h33;
match9: nesprgdout=8'hE2;
match10:nesprgdout={7'd0,~fds_busy};//MiSTer busy (zero = busy)
default: nesprgdout=ramprgdin;
default: begin
nesprgdout=ramprgdin;
fds_prg_bus_write = 0;
end
endcase
end
assign prg_allow = (nesprg_we & (Wstate==2 | (prgain[15]^(&prgain[14:13]))))
| (~nesprg_we & ((prgain[15] & !match3 & !match4 & !match7 & !match8 & !match9) | prgain[15:13]==3));
@@ -403,19 +403,48 @@ assign ramchraout[18:11]={6'd0,chrain[12:11]};
assign ramchraout[10]=!chrain[13]? chrain[10]: ((vertical & chrain[10]) | (!vertical & chrain[11]));
assign ciram_ce=chrain[13];
endmodule
module fds_mixed (
input clk,
input ce, // Negedge M2 (aka CPU ce)
input enable,
input wren,
input [15:0] addr_in,
input [7:0] data_in,
output [7:0] data_out,
input [15:0] audio_in, // Inverted audio from APU
output [15:0] audio_out
);
//expansion audio
fds_audio fds_audio
(
.clk(clk20),
.clk(clk),
.m2(ce),
.reset(reset),
.wr(nesprg_we),
.addr_in(prgain),
.data_in(nesprgdin),
.data_out(audio_dout),
.audio_out(snd_level)
.reset(!enable),
.wr(wren),
.addr_in(addr_in),
.data_in(data_in),
.data_out(data_out),
.audio_out(audio_exp)
);
wire [11:0] audio_exp;
// XXX: This needs to be replaced with a proper ~2000hz LPF
lpf_aud fds_lpf
(
.CLK(clk),
.CE(ce),
.IDATA(16'hFFFF - {1'b0, audio_exp[11:0], audio_exp[11:9]}),
.ODATA(audio_exp_f)
);
wire [15:0] audio_exp_f;
wire [16:0] audio = audio_in + audio_exp_f;
assign audio_out = 16'hFFFF - audio[16:1];
endmodule
// FDS Audio module by Kitrinx
@@ -681,7 +710,6 @@ end
endmodule
module lpf_aud
(
input CLK,

View File

@@ -19,11 +19,11 @@ module multiplier (
always @(posedge clk) begin
if (start && ce) begin
bindex <= 1 << 1;
bindex <= 9'd1 << 1;
product <= {8'h00, b[0] ? a : 8'h00};
shift_a <= a << 1;
end else if (bindex < 9'h100) begin
product <= product + ((bindex[7:0] & b) ? shift_a : 0);
product <= product + ((bindex[7:0] & b) ? shift_a : 16'd0);
bindex <= bindex << 1;
shift_a <= shift_a << 1;
end
@@ -53,7 +53,7 @@ module JYCompany(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
// Special ports
input ppu_ce
);
@@ -76,9 +76,9 @@ wire chr_allow;
wire vram_a10;
reg [7:0] chr_dout, prg_dout;
wire vram_ce;
wire [15:0] flags_out = {14'h0, prg_open_bus, 1'b0};
wire [15:0] flags_out = {14'h0, prg_bus_write, 1'b0};
wire irq;
wire prg_open_bus, prg_conflict;
reg prg_bus_write;
wire mapper90 = (flags[7:0] == 90);
wire mapper211 = (flags[7:0] == 211); // Should just be 209 with correct behavior below
@@ -197,13 +197,12 @@ multiplier mp(
.done()
);
wire prg_6xxx = prg_ain[15:13] == 2'b011;
wire prg_6xxx = prg_ain[15:13] == 2'b011; // $6000-$7FFF
wire prg_ram = prg_6xxx && !bank_mode[7];
// Read from JYCompany
always @* begin
prg_dout = 8'hFF; // By default open bus.
prg_open_bus = 0;
prg_bus_write = 1'b1;
if ((prg_ain == 16'h5000) || (prg_ain == 16'h5400)) begin // || (prg_ain == 16'h5C00)) begin
prg_dout = {dip, 6'h00};
end else if (prg_ain == 16'h5800) begin
@@ -215,7 +214,8 @@ always @* begin
end else if (prg_ain == 16'h5803) begin
prg_dout = accumtest;
end else begin
prg_open_bus = ((prg_ain[15] == 1'b0) && ((&prg_ain[14:12]) || (prg_ram && ~ram_support)));
prg_dout = 8'hFF; // By default open bus.
prg_bus_write = 0;
end
end
@@ -242,7 +242,7 @@ always @* begin
endcase
end
assign prg_aout = prg_ram && ram_support ? {9'b11_1100_000, prg_ain[12:0]} : {1'b0, outer_bank[2:1], prg_sel, prg_ain[12:0]};
assign prg_allow = (prg_ain >= 16'h6000) && (!prg_write || (prg_ram && ram_support));
assign prg_allow = (prg_ain >= 16'h6000) && (prg_ram ? ram_support : !prg_write);
reg [1:0] chr_latch;
// latch is set to 0 when the PPU reads from $0FD8-$0FDF/$1FD8-$1FDF and to 1 when the PPU reads from $0FE8-$0FEF/$1FE8-$1FEF.

View File

@@ -22,7 +22,7 @@ module MMC1(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -41,6 +41,7 @@ wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
wire mapper171 = (flags[7:0] == 171); //Mapper 171 has hardwired mirroring
reg [15:0] flags_out = 0;
reg [4:0] shift;
@@ -138,7 +139,7 @@ wire [21:0] prg_aout_tmp = prg_size == 5 ? {3'b000, chrsel[4], prgsel, prg_ain[1
// The a10 VRAM address line. (Used for mirroring)
reg vram_a10_t;
always @* begin
casez(control[1:0])
casez(mapper171 ? 2'b10 : control[1:0]) //if mapper 171 then set to vertical mirroring, else do normal MMC1 mirroring selection.
2'b00: vram_a10_t = 0; // One screen, lower bank
2'b01: vram_a10_t = 1; // One screen, upper bank
2'b10: vram_a10_t = chr_ain[10]; // One screen, vertical
@@ -181,7 +182,7 @@ module NesEvent(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;

View File

@@ -22,7 +22,7 @@ module MMC2(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -182,7 +182,7 @@ module MMC4(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;

View File

@@ -22,7 +22,7 @@ module Rambo1(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -53,16 +53,18 @@ reg chr_a12_invert; // Mode for CHR banking
reg mirroring; // 0 = vertical, 1 = horizontal
reg irq_enable, irq_reload; // IRQ enabled, and IRQ reload requested
reg [7:0] irq_latch, counter; // IRQ latch value and current counter
reg want_irq;
reg [1:0] irq_delay;
wire irq_imm;
reg [7:0] chr_bank_0, chr_bank_1; // Selected CHR banks
reg [7:0] chr_bank_2, chr_bank_3, chr_bank_4, chr_bank_5;
reg [7:0] chr_bank_8, chr_bank_9;
reg [5:0] prg_bank_0, prg_bank_1, prg_bank_2; // Selected PRG banks
reg irq_cycle_mode;
reg irq_cycle_mode, next_irq_cycle_mode;
reg [1:0] cycle_counter;
// Mapper has vram_a10 wired to CHR A17
wire mapper64 = (flags[7:0] == 64);
//wire mapper64 = (flags[7:0] == 64);//default
wire mapper158 = (flags[7:0] == 158);
// This code detects rising edges on a12.
reg old_a12_edge;
@@ -83,16 +85,38 @@ if (~enable) begin
mirroring <= 0;
{irq_enable, irq_reload} <= 0;
{irq_latch, counter} <= 0;
want_irq <= 0;
{chr_bank_0, chr_bank_1} <= 0;
{chr_bank_2, chr_bank_3, chr_bank_4, chr_bank_5} <= 0;
{chr_bank_8, chr_bank_9} <= 0;
{prg_bank_0, prg_bank_1, prg_bank_2} <= 6'b111111;
irq_cycle_mode <= 0;
next_irq_cycle_mode <= 0;
cycle_counter <= 0;
irq <= 0;
end else if (ce) begin
// Process these before writes so irq_reload and cycle_counter register writes take precedence.
cycle_counter <= cycle_counter + 1'd1;
irq_delay <= {1'b0, irq_delay[1]};
if ((cycle_counter == 3) || (!irq_cycle_mode))
irq_cycle_mode <= next_irq_cycle_mode;
irq_imm = 1'b0;
if (irq_cycle_mode ? (cycle_counter == 3) : a12_edge) begin
if (irq_reload || counter == 8'h00) begin
counter <= irq_latch + ((irq_reload && (|irq_latch[7:1])) ? 1'd1 : 1'd0);
irq_imm = irq_latch == 0;
end else begin
counter <= counter - 1'd1;
end
if (((counter == 1) || (irq_imm)) && irq_enable)
irq_delay <= irq_cycle_mode ? 2'b01 : 2'b10;
irq_reload <= 0;
end
if (irq_delay[0]) begin
irq <= 1;
irq_delay <= 2'b00;
end
if (prg_write && prg_ain[15]) begin
case({prg_ain[14:13], prg_ain[0]})
@@ -117,27 +141,13 @@ end else if (ce) begin
3'b01_1: begin end
3'b10_0: irq_latch <= prg_din; // IRQ latch ($C000-$DFFE, even)
3'b10_1: begin
{irq_reload, irq_cycle_mode} <= {1'b1, prg_din[0]}; // IRQ reload ($C001-$DFFF, odd)
{irq_reload, next_irq_cycle_mode} <= {1'b1, prg_din[0]}; // IRQ reload ($C001-$DFFF, odd)
cycle_counter <= 0;
end
3'b11_0: {irq_enable, irq} <= 2'b0; // IRQ disable ($E000-$FFFE, even)
3'b11_1: irq_enable <= 1; // IRQ enable ($E001-$FFFF, odd)
3'b11_0: {irq_enable, irq} <= 2'b00; // IRQ disable ($E000-$FFFE, even)
3'b11_1: {irq_enable, irq} <= 2'b10; // IRQ enable ($E001-$FFFF, odd)
endcase
end
if (irq_cycle_mode ? (cycle_counter == 3) : a12_edge) begin
if (irq_reload || counter == 0) begin
counter <= irq_latch;
want_irq <= irq_reload;
end else begin
counter <= counter - 1'd1;
want_irq <= 1;
end
if (counter == 0 && want_irq && !irq_reload && irq_enable)
irq <= 1;
irq_reload <= 0;
end
end
// The PRG bank to load. Each increment here is 8kb. So valid values are 0..63.
@@ -176,7 +186,7 @@ end
assign prg_aout = {3'b00_0, prgsel, prg_ain[12:0]};
assign {chr_allow, chr_aout} = {flags[15], 4'b10_00, chrsel, chr_ain[9:0]};
assign prg_allow = prg_ain[15] && !prg_write;
assign vram_a10 = mapper64 ? chrsel[7] : // Mapper 64 controls mirroring by switching the top bits of the CHR address
assign vram_a10 = mapper158 ? chrsel[7] : // Mapper 158 controls mirroring by switching the top bits of the CHR address
mirroring ? chr_ain[11] : chr_ain[10];
assign vram_ce = chr_ain[13];
endmodule
@@ -203,7 +213,7 @@ module MMC3 (
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -237,12 +247,13 @@ reg ram6_enabled, ram6_enable, ram6_protect; //extra bits for mmc6
reg [7:0] chr_bank_0, chr_bank_1; // Selected CHR banks
reg [7:0] chr_bank_2, chr_bank_3, chr_bank_4, chr_bank_5;
reg [5:0] prg_bank_0, prg_bank_1, prg_bank_2; // Selected PRG banks
reg last_a12;
wire prg_is_ram;
reg [4:0] irq_reg;
assign irq = mapper48 ? irq_reg[4] : irq_reg[0];
// The alternative behavior has slightly different IRQ counter semantics.
wire mmc3_alt_behavior = 0;
wire mmc3_alt_behavior = acclaim;
wire TQROM = (flags[7:0] == 119); // TQROM maps 8kB CHR RAM
wire TxSROM = (flags[7:0] == 118); // Connects CHR A17 to CIRAM A10
@@ -265,8 +276,9 @@ wire mapper192 = (flags[7:0] == 192); // Has 4KB CHR RAM
wire mapper194 = (flags[7:0] == 194); // Has 2KB CHR RAM
wire mapper195 = (flags[7:0] == 195); // Has 4KB CHR RAM
wire MMC6 = ((flags[7:0] == 4) && (flags[24:21] == 1)); // mapper 4, submapper 1 = MMC6
wire acclaim = ((flags[7:0] == 4) && (flags[24:21] == 3)); // Acclaim mapper
wire four_screen_mirroring = flags[16] | DxROM;
wire four_screen_mirroring = flags[16];// | DxROM; // not all DxROM are 4-screen
reg mapper47_multicart;
reg [2:0] mapper37_multicart;
wire [7:0] new_counter = (counter == 0 || irq_reload) ? irq_latch : counter - 1'd1;
@@ -294,6 +306,7 @@ if (~enable) begin
{prg_bank_0, prg_bank_1} <= 0;
prg_bank_2 <= 6'b111110;
a12_ctr <= 0;
last_a12 <= 0;
mapper37_multicart <= 3'b000;
end else if (ce) begin
irq_reg[4:1] <= irq_reg[3:0]; // 4 cycle delay
@@ -322,7 +335,7 @@ end else if (ce) begin
endcase
end else if (!mapper112) begin
casez({prg_ain[14:13], prg_ain[1:0], mapper48})
5'b00_00_0: begin prg_bank_0 <= prg_din[5:0]; mirroring <= prg_din[6]; end // Select 8 KB PRG ROM bank at $8000-$9FFF
5'b00_00_0: {mirroring, prg_bank_0} <= prg_din[6:0] ^ 7'h40; // Select 8 KB PRG ROM bank at $8000-$9FFF
5'b00_00_1: prg_bank_0 <= prg_din[5:0]; // Select 8 KB PRG ROM bank at $8000-$9FFF
5'b00_01_?: prg_bank_1 <= prg_din[5:0]; // Select 8 KB PRG ROM bank at $A000-$BFFF
5'b00_10_?: chr_bank_0 <= prg_din; // Select 2 KB CHR bank at PPU $0000-$07FF
@@ -335,7 +348,7 @@ end else if (ce) begin
5'b10_00_1: irq_latch <= prg_din ^ 8'hFF; // IRQ latch ($C000-$DFFC)
5'b10_01_1: irq_reload <= 1; // IRQ reload ($C001-$DFFD)
5'b10_10_1: irq_enable <= 1; // IRQ enable ($C002-$DFFE)
5'b10_11_1: begin irq_enable <= 0; irq_reg[0] <= 0; end// IRQ disable ($C003-$DFFF)
5'b10_11_1: {irq_enable, irq_reg[0]} <= 2'b00; // IRQ disable ($C003-$DFFF)
5'b11_00_1: mirroring <= !prg_din[6]; // Mirroring
endcase
@@ -360,9 +373,10 @@ end else if (ce) begin
endcase
end
if (mapper154) begin
mirroring <= !prg_din[6];
end
if (mapper154)
mirroring <= !prg_din[6];
if (DxROM || mapper76)
mirroring <= flags[14]; // Hard-wired mirroring
end
else if (regs_7e && prg_write && prg_ain[15:4]==12'h7EF) begin
casez({prg_ain[3:0], mapper82})
@@ -405,17 +419,26 @@ end else if (ce) begin
// All MMC3C's and Sharp MMC3B's will generate an IRQ on each scanline while $C000 is $00.
// This is because this version of the MMC3 generates IRQs when the scanline counter is equal to 0.
// In the community, this is known as the "normal" or "new" behavior.
if (chr_ain[12] && a12_ctr == 0) begin
last_a12 <= chr_ain[12];
if ((acclaim && (!last_a12 && chr_ain[12]) && (a12_ctr == 6)) ||
(~acclaim && chr_ain[12] && (a12_ctr == 0))) begin
counter <= new_counter;
// MMC Scanline
if ( (!mmc3_alt_behavior || counter != 0 || irq_reload) && new_counter == 0 && irq_enable && irq_support) begin
if ( (!mmc3_alt_behavior || counter != 0 || irq_reload) && new_counter == 0 && irq_enable && irq_support) begin
irq_reg[0] <= 1;
end
irq_reload <= 0;
end
a12_ctr <= chr_ain[12] ? 4'b1111 : (a12_ctr != 0) ? a12_ctr - 4'b0001 : a12_ctr;
if (acclaim) begin
if (!last_a12 && chr_ain[12]) // acclaim mapper counts down 8 pulses, or 16 edges total
a12_ctr <= (a12_ctr != 0) ? a12_ctr - 4'b0001 : 4'b0111;
if (prg_ain == 16'hC001 && prg_write) a12_ctr <= 4'b0111;
end else begin // nintendo mapper 'cools down' for 16 low cycles
a12_ctr <= chr_ain[12] ? 4'b1111 : (a12_ctr != 0) ? a12_ctr - 4'b0001 : a12_ctr;
end
end
// The PRG bank to load. Each increment here is 8kb. So valid values are 0..63.
@@ -468,23 +491,14 @@ always @* begin
end
wire [21:0] prg_aout_tmp = {3'b00_0, prgsel, prg_ain[12:0]};
wire ram_enable_a = MMC6 ?
(ram6_enabled && ram6_enable && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b0)
|| (ram6_enabled && ram_enable[3] && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b1)
:
(ram_enable[0] && prg_ain[12:11] == 2'b00)
|| (ram_enable[1] && prg_ain[12:11] == 2'b01)
|| (ram_enable[2] && prg_ain[12:11] == 2'b10)
|| (ram_enable[3] && prg_ain[12:11] == 2'b11);
wire ram_protect_a = MMC6 ?
!(ram6_enabled && ram6_enable && ram6_protect && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b0)
&& !(ram6_enabled && ram_enable[3] && ram_protect[3] && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b1)
:
(ram_protect[0] && prg_ain[12:11] == 2'b00)
|| (ram_protect[1] && prg_ain[12:11] == 2'b01)
|| (ram_protect[2] && prg_ain[12:11] == 2'b10)
|| (ram_protect[3] && prg_ain[12:11] == 2'b11);
wire ram_enable_a = !MMC6 ? (ram_enable[prg_ain[12:11]])
: (ram6_enabled && ram6_enable && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b0)
|| (ram6_enabled && ram_enable[3] && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b1);
wire ram_protect_a = !MMC6 ? (ram_protect[prg_ain[12:11]])
: !(ram6_enabled && ram6_enable && ram6_protect && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b0)
&& !(ram6_enabled && ram_enable[3] && ram_protect[3] && prg_ain[12] == 1'b1 && prg_ain[9] == 1'b1);
assign {chr_allow, chr_aout} =
(TQROM && chrsel[6]) ? {1'b1, 9'b11_1111_111, chrsel[2:0], chr_ain[9:0]} : // TQROM 8kb CHR-RAM
@@ -533,7 +547,7 @@ module Mapper165(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;

View File

@@ -21,8 +21,9 @@ module MMC5(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
// Special ports
input [7:0] audio_dout,
input [7:0] chr_din, // CHR Data in
input chr_write, // CHR Write
inout [7:0] chr_dout_b, // chr data (non standard)
@@ -40,7 +41,7 @@ assign vram_a10_b = enable ? vram_a10 : 1'hZ;
assign vram_ce_b = enable ? vram_ce : 1'hZ;
assign irq_b = enable ? irq : 1'hZ;
assign flags_out_b = enable ? flags_out : 16'hZ;
assign audio_b = enable ? audio_out[16:1] : 16'hZ;
assign audio_b = enable ? audio : 16'hZ;
wire [21:0] prg_aout;
reg [21:0] chr_aout;
@@ -49,13 +50,10 @@ wire chr_allow;
wire vram_a10;
reg [7:0] chr_dout, prg_dout;
wire vram_ce;
wire [15:0] flags_out = {15'h0, has_chr_dout};
wire [15:0] flags_out = {14'h0, prg_bus_write, has_chr_dout};
wire irq;
wire prg_open_bus, prg_conflict, has_chr_dout;
wire [15:0] audio;
// NOTE: The apu volume is 100% of MMC5 and the polarity is reversed.
wire [16:0] audio_out = audio + audio_in;
wire prg_bus_write, has_chr_dout;
wire [15:0] audio = audio_in;
reg [1:0] prg_mode, chr_mode;
reg prg_protect_1, prg_protect_2;
@@ -180,7 +178,7 @@ end
// Read from MMC5
always @* begin
prg_dout = 8'hFF; // By default open bus.
prg_bus_write = 1'b1;
if (prg_ain[15:10] == 6'b010111 && extended_ram_mode[1]) begin
prg_dout = last_read_ram;
end else if (prg_ain == 16'h5204) begin
@@ -190,8 +188,11 @@ always @* begin
end else if (prg_ain == 16'h5206) begin
prg_dout = multiply_result[15:8];
end else if (prg_ain == 16'h5015) begin
prg_dout = {6'h00, apu_dout[1:0]};
prg_dout = {6'h00, audio_dout[1:0]};
// TODO: 5010
end else begin
prg_dout = 8'hFF; // By default open bus.
prg_bus_write = 0;
end
end
@@ -412,8 +413,27 @@ assign prg_allow = (prg_ain >= 16'h6000) && (!prg_write || ((!prgsel[7]) && prg_
// MMC5 boards typically have no CHR RAM.
assign chr_allow = flags[15];
wire [7:0] apu_dout;
wire apu_cs = (prg_ain[15:5]==11'b0101_0000_000) && (prg_ain[3]==0);
endmodule
module mmc5_mixed (
input clk,
input ce, // Negedge M2 (aka CPU ce)
input enable,
input wren,
input rden,
input [15:0] addr_in,
input [7:0] data_in,
output [7:0] data_out,
input [15:0] audio_in, // Inverted audio from APU
output [15:0] audio_out
);
// NOTE: The apu volume is 100% of MMC5 and the polarity is reversed.
wire [16:0] audio_o = audio + audio_in;
wire [15:0] audio;
assign audio_out = audio_o[16:1];
wire apu_cs = (addr_in[15:5]==11'b0101_0000_000) && (addr_in[3]==0);
wire DmaReq; // 1 when DMC wants DMA
wire [15:0] DmaAddr; // Address DMC wants to read
reg odd_or_even;
@@ -431,11 +451,11 @@ APU mmc5apu(
.clk (clk),
.ce (ce),
.reset (~enable),
.ADDR (prg_ain[4:0]),
.DIN (prg_din),
.DOUT (apu_dout),
.MW (prg_write && apu_cs),
.MR (prg_read && apu_cs),
.ADDR (addr_in[4:0]),
.DIN (data_in),
.DOUT (data_out),
.MW (wren && apu_cs),
.MR (rden && apu_cs),
.audio_channels (5'b10011),
.Sample (audio),
.DmaReq (DmaReq),

View File

@@ -1,6 +1,6 @@
// Namco mappers
module N106(
module N163(
input clk, // System clock
input ce, // M2 ~cpu_clk
input enable, // Mapper enabled
@@ -21,7 +21,9 @@ module N106(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
// Special ports
input [7:0] audio_dout
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -33,7 +35,7 @@ assign vram_a10_b = enable ? vram_a10 : 1'hZ;
assign vram_ce_b = enable ? vram_ce : 1'hZ;
assign irq_b = enable ? irq : 1'hZ;
assign flags_out_b = enable ? flags_out : 16'hZ;
assign audio_b = enable ? audio_mix[16:1] : 16'hZ;
assign audio_b = enable ? audio[15:0] : 16'hZ;
wire [21:0] prg_aout, chr_aout;
wire prg_allow;
@@ -41,9 +43,10 @@ wire chr_allow;
wire vram_a10;
wire vram_ce;
wire irq;
reg [15:0] flags_out = 0;
wire [15:0] flags_out = {14'h0, prg_bus_write, 1'b0};
wire prg_bus_write = nesprg_oe;
wire [7:0] prg_dout;
wire [15:0] audio;
wire [15:0] audio = audio_in;
wire nesprg_oe;
wire [7:0] neschrdout;
@@ -57,22 +60,22 @@ wire [18:13] ramprgaout;
wire exp6;
reg [7:0] m2;
wire m2_n = 1;//~ce; //m2_n not used as clk. Invert m2 (ce).
wire [18:10] chr_aoutm;
always @(posedge clk) begin
m2[7:1] <= m2[6:0];
m2[0] <= ce;
end
MAPN106 n106(m2[7], m2_n, clk, ~enable, prg_write, nesprg_oe, 0,
MAPN163 n163(m2[7], m2_n, clk, ~enable, prg_write, nesprg_oe, 0,
1, prg_ain, chr_ain, prg_din, 8'b0, prg_dout,
neschrdout, neschr_oe, chr_allow, chrram_oe, wram_oe, wram_we, prgram_we,
prgram_oe, chr_aout[18:10], ramprgaout, irq, vram_ce, exp6,
prgram_oe, chr_aoutm, ramprgaout, irq, vram_ce, exp6,
0, 7'b1111111, 6'b111111, flags[14], flags[16], flags[15],
ce, (flags[7:0]==210), flags[24:21], audio[15:5]);
ce, (flags[7:0]==210), flags[24:21], audio_dout);
wire [16:0] audio_mix = audio_in + audio;
assign chr_aout[21:19] = 3'b100;
assign chr_aout[21:18] = {4'b1000};
assign chr_aout[17:10] = chr_aoutm[17:10];
assign chr_aout[9:0] = chr_ain[9:0];
assign vram_a10 = chr_aout[10];
wire [21:13] prg_aout_tmp = {3'b00_0, ramprgaout};
@@ -81,14 +84,13 @@ wire prg_is_ram = prg_ain >= 'h6000 && prg_ain < 'h8000;
assign prg_aout[21:13] = prg_is_ram ? prg_ram : prg_aout_tmp;
assign prg_aout[12:0] = prg_ain[12:0];
assign prg_allow = (prg_ain[15] && !prg_write) || prg_is_ram;
assign audio[4:0] = 4'b0;
endmodule
//Taken from Loopy's Power Pak mapper source mapN106.v
//fixme- sound ram is supposed to be readable (does this affect any games?)
module MAPN106( //signal descriptions in powerpak.v
module MAPN163( //signal descriptions in powerpak.v
input m2,
input m2_n,
input clk20,
@@ -129,7 +131,8 @@ module MAPN106( //signal descriptions in powerpak.v
input ce,// add
input mapper210,
input [3:0] submapper,
output [15:0] snd_level
//output [15:0] snd_level,
input [7:0] audio_dout
);
assign exp6 = 0;
@@ -224,17 +227,17 @@ always@* begin
chrram=(~(chrain[12]?chr_en[1]:chr_en[0]))&(&chrbank[17:15]); //ram/rom select
if(!chrain[13]) begin
ciram_ce=0;
ciram_ce=chrram && ~mapper210;
chrram_oe=neschr_rd;
chrram_we=neschr_wr & chrram;
ramchraout[10]=chrbank[10];
end else begin
ciram_ce=(&chrbank[17:15] | mirror[0]) | mapper210;
ciram_ce=(&chrbank[17:15]) | mapper210;
chrram_oe=~ciram_ce & neschr_rd;
chrram_we=~ciram_ce & neschr_wr & chrram;
casez({mapper210,submapper1,mirror,cfg_vertical})
5'b0?_?0_?: ramchraout[10] = chrbank[10];
5'b0?_?1_?: ramchraout[10] = chrain[10];
5'b0?_??_?: ramchraout[10] = chrbank[10];
//5'b0?_?1_?: ramchraout[10] = chrain[10];
5'b10_00_?: ramchraout[10] = 1'b0;
5'b10_01_?: ramchraout[10] = chrain[10];
5'b10_10_?: ramchraout[10] = chrain[11];
@@ -245,7 +248,7 @@ always@* begin
end
ramchraout[11]=chrbank[11];
ramchraout[17:12]=chrbank[17:12] & cfg_chrmask[17:12];
ramchraout[18]=chrram;
ramchraout[18]=ciram_ce;
end
assign wram_oe=m2_n & ~nesprg_we & prgain[15:13]==3'b011;
@@ -259,38 +262,68 @@ wire config_rd = 0;
//gamegenie gg(m2, reset, nesprg_we, prgain, nesprgdin, ramprgdin, gg_out, config_rd);
//PRG data out
wire counter_oe = m2_n & ~nesprg_we & prgain[15:12]=='b0101;
wire mapper_oe = m2_n & ~nesprg_we & ((prgain[15:12]=='b0101) || (prgain[15:11]=='b01001));
always @* begin
case(prgain[15:11])
5'b01001: nesprgdout=audio_dout;
5'b01010: nesprgdout=count[7:0];
5'b01011: nesprgdout=count[15:8];
default: nesprgdout=nesprgdin;
endcase
end
assign nesprg_oe=wram_oe | prgram_oe | counter_oe | config_rd;
assign nesprg_oe=wram_oe | prgram_oe | mapper_oe | config_rd;
assign neschr_oe=0;
assign neschrdout=0;
//sound
wire [10:0] n106_out;
wire [9:0] saturated=n106_out[9:0] | {10{n106_out[10]}}; //this is still too quiet for the suggested 47k resistor, but more clipping will make some games sound bad
endmodule
namco106_sound n106(ce, clk20, reset, nesprg_we, prgain, nesprgdin, n106_out);
module namco163_mixed (
input clk,
input ce,
input [3:0] submapper,
input enable,
input wren,
input [15:0] addr_in,
input [7:0] data_in,
output [7:0] data_out,
input [15:0] audio_in,
output [15:0] audio_out
);
reg disabled;
always@(posedge clk) begin
if (!enable)
disabled <= 1'b0;
else if (ce) begin
if(wren & addr_in[15:11]==5'b11100) //E000..E7FF
disabled<=data_in[6];
end
end
//sound
wire [10:0] n163_out;
namco163_sound n163(clk, ce, !enable, wren, addr_in, data_in, data_out, n163_out);
//pdm #(10) pdm_mod(clk20, saturated, exp6);
assign snd_level = (mapper210 | mirror[0]) ? 16'b0 : {6'b0, saturated};
wire [9:0] saturated=n163_out[9:0] | {10{n163_out[10]}}; //this is still too quiet for the suggested 47k resistor, but more clipping will make some games sound bad
wire [15:0] audio = {1'b0, saturated, 5'b0};
wire [16:0] audio_mix = (!enable | disabled) ? {audio_in, 1'b0} : (submapper==5) ? (audio_in>>>2) + audio : (submapper==4) ? (audio_in>>>1) + audio : audio_in + audio;
assign audio_out = audio_mix[16:1];
endmodule
module namco106_sound(
input m2,
module namco163_sound(
input clk20,
input m2,
input reset,
input wr,
input [15:0] ain,
input [7:0] din,
output [7:0] dout,
output reg [10:0] out //range is 0..0x708
);
@@ -312,14 +345,18 @@ reg [10:0] out_acc;
wire [10:0] sum=out_acc+chan_out;
reg addr_lsb;
wire [7:0] sample_addr=ram_dout+sample_pos[ch];
reg do_inc;
//ram in
always@(posedge clk20) begin
if (m2) begin
do_inc<= 0;
if (do_inc)
ram_ain<=ram_ain+1'd1;
if(wr & ain[15:11]==5'b11111) //F800..FFFF
{autoinc,ram_ain}<=din;
else if(ain[15:11]==5'b01001 & autoinc) //4800..4FFF
ram_ain<=ram_ain+1'd1;
do_inc<=1;
end
end
@@ -375,6 +412,7 @@ dpram #(.widthad_a(7)) modtable
.wren_a (wr & ain[15:11]==5'b01001),
.byteena_a (1),
.data_a (din),
.q_a (dout),
.clock_b (clk20),
.address_b (ram_aout),

View File

@@ -23,7 +23,7 @@ module Sachen8259(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -42,10 +42,11 @@ wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
reg [15:0] flags_out = 0;
wire [15:0] flags_out = {14'd0, prg_bus_write, 1'b0};
// 0x4100
wire [7:0] prg_dout = {5'b00111, (~register)}; // ^ (counter & 0x1)
wire prg_bus_write = ({prg_ain[15:14], prg_ain[8], prg_ain[0]} == 4'b0110);
wire mapper137 = (flags[7:0] == 137);
wire mapper138 = (flags[7:0] == 138);
@@ -164,7 +165,7 @@ module SachenJV001(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -183,7 +184,7 @@ wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
reg [15:0] flags_out = 0;
wire [15:0] flags_out = {14'd0, prg_bus_write, 1'b0};
reg [5:0] input_reg; //s_reg = input_reg[3]
reg [5:0] output_reg;
@@ -205,6 +206,8 @@ wire [7:0] prg_din_adj = mapper147 ? {2'b00, prg_din[7:2]} :
mapper172 ? {2'b00, prg_din[0], prg_din[1], prg_din[2], prg_din[3], prg_din[4], prg_din[5]} :
prg_din;
wire prg_bus_write = (prg_ain[15:13] == 3'b010 && prg_ain[8]); //0x4100-3
always @(posedge clk)
if (~enable) begin
//
@@ -279,7 +282,7 @@ module SachenNROM(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -298,12 +301,12 @@ wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
wire prg_open_bus;
wire [15:0] flags_out = {14'h0, prg_open_bus, 1'b0};
wire prg_bus_write;
wire [15:0] flags_out = {14'h0, prg_bus_write, 1'b0};
// 0x4100
wire [7:0] prg_dout = {2'b01, ~prg_ain[5:0]}; // top 2 bits are actually open bus
assign prg_open_bus = ~((prg_ain[15:13] == 3'b010) && prg_ain[8]);
assign prg_bus_write = ((prg_ain[15:13] == 3'b010) && prg_ain[8]);
assign prg_aout = {7'b00_0000_0, prg_ain[14:0]};
assign prg_allow = prg_ain[15] && !prg_write;

View File

@@ -20,7 +20,7 @@ module Mapper69(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -122,20 +122,36 @@ always begin
chrout = chr_bank[chr_ain[12:10]];
end
wire ram_cs = (prg_ain[15] == 0 && ram_select);
assign prg_aout = {1'b0, ram_cs, 2'b00, prgout[4:0], prg_ain[12:0]};
assign prg_allow = ram_cs ? ram_enable : !prg_write;
wire ram_cs = (prg_ain[15:13] == 3'b011 && ram_select);
assign prg_aout = {ram_cs ? 4'b1111 : 4'b0000, prgout[4:0], prg_ain[12:0]};
assign prg_allow = (prg_ain >= 16'h6000) && (ram_cs ? ram_enable : !prg_write);
assign chr_allow = flags[15];
assign chr_aout = {4'b10_00, chrout, chr_ain[9:0]};
assign vram_ce = chr_ain[13];
assign audio = audio_in;
endmodule
module SS5b_mixed (
input clk,
input ce, // Negedge M2 (aka CPU ce)
input enable,
input wren,
input [15:0] addr_in,
input [7:0] data_in,
input [15:0] audio_in, // Inverted audio from APU
output [15:0] audio_out
);
SS5b_audio snd_5b (
.clk(clk),
.ce(ce),
.enable(enable),
.wren(prg_write),
.addr_in(prg_ain),
.data_in(prg_din),
.wren(wren),
.addr_in(addr_in),
.data_in(data_in),
.audio_out(exp_out)
);
@@ -148,7 +164,7 @@ wire [15:0] exp_out;
wire [15:0] exp_adj = (|exp_out[15:14] ? 16'hFFFF : {exp_out[13:0], exp_out[1:0]});
wire [16:0] audio_mix = audio_in + (exp_adj + exp_adj[15:1]);
assign audio = 16'hFFFF - audio_mix[16:1];
assign audio_out = 16'hFFFF - audio_mix[16:1];
endmodule
@@ -328,7 +344,7 @@ module Mapper67 (
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -347,7 +363,7 @@ wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
wire irq;
reg irq;
reg [15:0] flags_out = 0;
reg [7:0] prg_bank_0;
@@ -393,17 +409,17 @@ end else if (ce) begin
3'b1_10: chr_bank_2 <= prg_din;
3'b1_11: chr_bank_3 <= prg_din;
endcase
if (irq_enable) begin
irq_counter <= irq_counter - 16'd1;
if (irq_counter == 16'h0) begin
irq <= 1'b1; // IRQ
irq_enable <= 0;
end
end
if (irq_ack)
irq <= 1'b0; // IRQ ACK
end
if (irq_enable) begin
irq_counter <= irq_counter - 16'd1;
if (irq_counter == 16'h0) begin
irq <= 1'b1; // IRQ
irq_enable <= 0;
end
end
if (irq_ack)
irq <= 1'b0; // IRQ ACK
end
always begin
@@ -469,7 +485,7 @@ module Mapper68(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -485,6 +501,7 @@ assign audio_b = enable ? {1'b0, audio_in[15:1]} : 16'hZ;
wire [21:0] prg_aout, chr_aout;
wire prg_allow;
wire ram_enable;
wire chr_allow;
wire vram_a10;
wire vram_ce;
@@ -492,9 +509,9 @@ reg [15:0] flags_out = 0;
reg [6:0] chr_bank_0, chr_bank_1, chr_bank_2, chr_bank_3;
reg [6:0] nametable_0, nametable_1;
reg [2:0] prg_bank;
reg [3:0] prg_bank;
reg use_chr_rom;
reg mirroring;
reg [1:0] mirroring;
always @(posedge clk)
if (~enable) begin
@@ -505,6 +522,7 @@ if (~enable) begin
nametable_0 <= 0;
nametable_1 <= 0;
prg_bank <= 0;
ram_enable <= 0;
use_chr_rom <= 0;
mirroring <= 0;
end else if (ce) begin
@@ -516,15 +534,18 @@ end else if (ce) begin
3: chr_bank_3 <= prg_din[6:0]; // $B000-$BFFF: 2kB CHR bank at $1800
4: nametable_0 <= prg_din[6:0]; // $C000-$CFFF: 1kB Nametable register 0 at $2000
5: nametable_1 <= prg_din[6:0]; // $D000-$DFFF: 1kB Nametable register 1 at $2400
6: {use_chr_rom, mirroring} <= {prg_din[4], prg_din[0]}; // $E000-$EFFF: Nametable control
7: prg_bank <= prg_din[2:0];
6: {use_chr_rom, mirroring} <= {prg_din[4], prg_din[1:0]}; // $E000-$EFFF: Nametable control
7: {ram_enable, prg_bank} <= prg_din[4:0]; // $F000-$FFFF: 16kB PRG banks at $8000-$BFFF and WRAM enable
endcase
end
end
wire [2:0] prgout = (prg_ain[14] ? 3'b111 : prg_bank);
assign prg_aout = {5'b00_000, prgout, prg_ain[13:0]};
assign prg_allow = prg_ain[15] && !prg_write;
// $C000-$FFFF wired to last PRG bank
wire [3:0] prgout = ((prg_ain[15:14] == 2'b11) ? 4'b1111 : prg_bank);
wire prg_is_ram = (prg_ain[15:13] == 3'b011);
wire [21:0] prg_ram = {9'b11_1100_000, prg_ain[12:0]};
assign prg_aout = prg_is_ram ? prg_ram : {4'b00_00, prgout, prg_ain[13:0]};
assign prg_allow = (prg_ain[15] && !prg_write) || (prg_is_ram && ram_enable);
reg [6:0] chrout;
always begin
@@ -536,7 +557,14 @@ always begin
endcase
end
assign vram_a10 = mirroring ? chr_ain[11] : chr_ain[10];
always begin
casez(mirroring[1:0])
2'b00: vram_a10 = {chr_ain[10]}; // vertical
2'b01: vram_a10 = {chr_ain[11]}; // horizontal
2'b1?: vram_a10 = {mirroring[0]}; // 1 screen lower
endcase
end
wire [6:0] nameout = (vram_a10 == 0) ? nametable_0 : nametable_1;
assign chr_allow = flags[15];

View File

@@ -22,7 +22,7 @@ module VRC1(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -119,7 +119,7 @@ module VRC3(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -223,7 +223,7 @@ module VRC24(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -254,7 +254,7 @@ reg [8:0] chr_tmp;
reg prg_invert;
wire mapper21 = (flags[7:0] == 21);
wire mapper22 = (flags[7:0] == 22);
wire mapper23 = (flags[7:0] == 23);
wire mapper23 = (flags[7:0] == 23 | flags[7:0] == 27);
//wire mapper25 = (flags[7:0] == 25); //default
wire mapperVRC4 = (flags[7:0] != 22) && (flags[24:21] != 3);
wire [1:0] registers = {mapper21 ? {(prg_ain[7]|prg_ain[2]),(prg_ain[6]|prg_ain[1])} :
@@ -378,7 +378,7 @@ module VRC6(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -399,7 +399,7 @@ wire chr_allow;
wire vram_a10;
wire vram_ce;
wire irq;
wire [15:0] audio;
wire [15:0] audio = audio_in;
reg [15:0] flags_out = 0;
wire nesprg_oe;
@@ -411,7 +411,7 @@ wire prgram_we;
wire chrram_oe;
wire prgram_oe;
wire [18:13] ramprgaout;
wire exp6;
//wire exp6;
reg [7:0] m2;
wire m2_n = 1;//~ce; //m2_n not used as clk. Invert m2 (ce).
@@ -423,18 +423,9 @@ end
MAPVRC6 vrc6(m2[7], m2_n, clk, enable, prg_write, nesprg_oe, 0,
1, prg_ain, chr_ain, prg_din, 8'b0, prg_dout,
neschrdout, neschr_oe, chr_allow, chrram_oe, wram_oe, wram_we, prgram_we,
prgram_oe, chr_aout[18:10], ramprgaout, irq, vram_ce, exp6,
prgram_oe, chr_aout[18:10], ramprgaout, irq, vram_ce,// exp6,
0, 7'b1111111, 6'b111111, flags[14], flags[16], flags[15],
ce, exp_audio, flags[1]);
// VRC6 audio is much louder than APU audio, so match the levels we have to reduce it
// to about 43% to match the audio ratio of the original Famicom with AD3. Note that the
// VRC6 audio is opposite polarity from APU audio.
wire [15:0] exp_audio;
wire [16:0] mixed_audio = audio_in + (exp_audio[15:1] + exp_audio[15:3]);
assign audio = mixed_audio[16:1];
ce, flags[1]);
assign chr_aout[21:19] = 3'b100;
assign chr_aout[9:0] = chr_ain[9:0];
@@ -469,7 +460,7 @@ module VRC7(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -490,7 +481,7 @@ wire vram_a10;
wire vram_ce;
wire irq;
reg [15:0] flags_out = 0;
wire [15:0] audio;
wire [15:0] audio = audio_in;
assign chr_aout[21:18] = 4'b1000;
assign chr_aout[9:0] = chr_ain[9:0];
@@ -513,14 +504,13 @@ reg [5:0] prgbank8;
reg [5:0] prgbankA;
reg [5:0] prgbankC;
wire prg_ain43 = prg_ain[4] ^ prg_ain[3];
reg ramw, soff;
reg ramw;
always@(posedge clk) begin
if (~enable) begin
soff <= 1'b0;
{chrbank0, chrbank1, chrbank2, chrbank3, chrbank4, chrbank5, chrbank6, chrbank7} <= 0;
{prgbank8, prgbankA, prgbankC} <= 0;
{ramw, soff} <= 0;
ramw <= 0;
end else if(ce && prg_write) begin
casex({prg_ain[15:12],prg_ain43})
5'b10000:prgbank8<=prg_din[5:0]; //8000
@@ -534,7 +524,7 @@ always@(posedge clk) begin
5'b11001:chrbank5<=prg_din; //C008/10
5'b11010:chrbank6<=prg_din; //D000
5'b11011:chrbank7<=prg_din; //D008/10
5'b11100:{ramw,soff,mirror}<={prg_din[7:6],prg_din[1:0]}; //E000
5'b11100:{ramw,mirror}<={prg_din[7],prg_din[1:0]}; //E000
//5'b11101:irqlatch<=nesprgdin; //E008/10
//5'b11110:{irqM,irqA}<={nesprgdin[2],nesprgdin[0]}; //F000
endcase
@@ -569,35 +559,6 @@ wire irqa = {prg_ain[15:12],prg_ain43}==5'b11111; // 0xF008 or 0xF010
vrcIRQ vrc7irq(clk,enable,prg_write,{irql,irql},irqc,irqa,prg_din,irq,ce);
reg [3:0] ce_count;
always@(posedge clk) begin
if (~enable)
ce_count <= 0;
else if (ce)
ce_count <= 0;
else
ce_count <= ce_count + 4'd1;
end
wire ack;
wire ce_ym2143 = ce | (ce_count==4'd5);
wire signed [13:0] ym2143audio;
wire wr_audio = prg_write && (prg_ain[15:6]==10'b1001_0000_00) && (prg_ain[4:0]==5'b1_0000); //0x9010 or 0x9030
eseopll ym2143vrc7 (clk,~enable, ce_ym2143,wr_audio,ce_ym2143,ack,wr_audio,{15'b0,prg_ain[5]},prg_din,ym2143audio);
// The strategy here:
// VRC7 sound is very low, and the top two bit is seldom (if ever) used. It's output as signed, so
// what we do is convert to unsigned, then drop the top bit, clipping if needed. It's still very
// low compared to NES audio, so we drop the bottom bit of NES audio, mix the two, then boost the
// mixed result times two, again clipping if needed. The result is audio mixed more or less correctly
// and at a similar level to the audio from regular games. I do not know the polarity of
// VRC7 audio.
wire [13:0] audio_exp = ym2143audio + 13'd4095;
wire [15:0] audio_clip = audio_exp[13] ? 16'hFFFF : {audio_exp[12:0], audio_exp[13:11]};
wire [16:0] audio_mixed = audio_in[15:1] + audio_clip;
assign audio = soff ? 16'h8000 : (audio_mixed[16] ? 16'hFFFF : audio_mixed[15:0]);
endmodule
@@ -633,7 +594,7 @@ module MAPVRC6( //signal descriptions in powerpak.v
output irq,
output ciram_ce,
output exp6,
// output exp6,
input cfg_boot,
input [18:12] cfg_chrmask,
@@ -643,7 +604,7 @@ module MAPVRC6( //signal descriptions in powerpak.v
input cfg_chrram,
input ce,// add
output [15:0] audio,
//output [15:0] audio,
input mapper26
);
@@ -737,18 +698,6 @@ module MAPVRC6( //signal descriptions in powerpak.v
assign nesprgdout=8'b0;
assign nesprg_oe=wram_oe | prgram_oe | config_rd;
//sound
// wire [5:0] vrc6_out;
assign exp6 = 0;
wire [3:0] vrc6sq1_out;
wire [3:0] vrc6sq2_out;
wire [4:0] vrc6saw_out;
vrc6sound snd(clk20, ce, enable, nesprg_we, ain, nesprgdin, vrc6sq1_out, vrc6sq2_out, vrc6saw_out);
// VRC6 sound is mixed before amplification, and them amplified linearly
wire [5:0] exp_audio = vrc6sq1_out + vrc6sq2_out + vrc6saw_out;
assign audio = {exp_audio, exp_audio, exp_audio[5:2]};
endmodule
module vrcIRQ(
@@ -831,18 +780,119 @@ assign irq=timeout & irqE;
endmodule
module vrc7_mixed (
input clk,
input ce, // Negedge M2 (aka CPU ce)
input enable,
input wren,
input [15:0] addr_in,
input [7:0] data_in,
input [15:0] audio_in, // Inverted audio from APU
output [15:0] audio_out
);
reg soff;
wire prg_ain43 = addr_in[4] ^ addr_in[3];
always@(posedge clk) begin
if (~enable) begin
soff <= 1'b0;
end else if(ce && wren && {addr_in[15:12],prg_ain43} == 5'b11100) begin
soff<=data_in[6]; //E000
end
end
reg [3:0] ce_count;
always@(posedge clk) begin
if (~enable)
ce_count <= 0;
else if (ce)
ce_count <= 0;
else
ce_count <= ce_count + 4'd1;
end
wire ack;
wire ce_ym2143 = ce | (ce_count==4'd5);
wire signed [13:0] ym2143audio;
wire wr_audio = wren && (addr_in[15:6]==10'b1001_0000_00) && (addr_in[4:0]==5'b1_0000); //0x9010 or 0x9030
eseopll ym2143vrc7 (clk,~enable, ce_ym2143,wr_audio,ce_ym2143,ack,wr_audio,{15'b0,addr_in[5]},data_in,ym2143audio);
// The strategy here:
// VRC7 sound is very low, and the top bit is seldom (if ever) used. It's output as signed with
// an actual used range of 6 * +/-512 = +/-3072. What we do is convert to unsigned (+2048),
// then clip to 4095. This clips the top 50% of the values, which are unlikely to be needed. This volume
// is low compared to NES audio, so we mix accordingly, again clipping if needed. The result
// is audio mixed more or less correctly and at a similar level to the audio from regular games.
wire [13:0] audio_exp = ym2143audio + 14'h800;
wire [13:0] audio_clip = audio_exp > 14'hFFF ? 14'hFFF : audio_exp;
wire [15:0] audio_boost = {audio_clip[11:0], 4'b0000};
wire [16:0] audio_mixed = audio_in[15:1] + audio_boost[15:1] + audio_boost[15:2] + audio_boost[15:4];
assign audio_out = soff ? audio_in[15:1] : (audio_mixed[16] ? 16'hFFFF : audio_mixed[15:0]);
endmodule
module vrc6_mixed (
input clk,
input ce, // Negedge M2 (aka CPU ce)
input enable,
input wren,
input addr_invert,
input [15:0] addr_in,
input [7:0] data_in,
input [15:0] audio_in, // Inverted audio from APU
output [15:0] audio_out
);
vrc6sound snd_vrc6 (
.clk(clk),
.ce(ce),
.enable(enable),
.wr(wren),
.addr_invert(addr_invert),
.addr_in(addr_in),
.din(data_in),
.outSq1(vrc6sq1_out),
.outSq2(vrc6sq2_out),
.outSaw(vrc6saw_out)
);
//sound
// wire [5:0] vrc6_out;
// assign exp6 = 0;
wire [3:0] vrc6sq1_out;
wire [3:0] vrc6sq2_out;
wire [4:0] vrc6saw_out;
// VRC6 sound is mixed before amplification, and them amplified linearly
wire [5:0] exp_audio = vrc6sq1_out + vrc6sq2_out + vrc6saw_out;
wire [15:0] audio = {exp_audio, exp_audio, exp_audio[5:2]};
// VRC6 audio is much louder than APU audio, so match the levels we have to reduce it
// to about 43% to match the audio ratio of the original Famicom with AD3. Note that the
// VRC6 audio is opposite polarity from APU audio.
wire [16:0] mixed_audio = audio_in + (audio[15:1] + audio[15:3]);
assign audio_out = mixed_audio[16:1];
endmodule
module vrc6sound(
input clk,
input ce,
input enable,
input wr,
input [15:0] ain,
input addr_invert,
input [15:0] addr_in,
input [7:0] din,
output [3:0] outSq1, //range=0..0x0F
output [3:0] outSq2, //range=0..0x0F
output [4:0] outSaw //range=0..0x1F
);
wire [15:0] ain=addr_invert ? {addr_in[15:2],addr_in[0],addr_in[1]} : addr_in; //MAP1A : MAP18
reg mode0, mode1;
reg [3:0] vol0, vol1;
reg [5:0] vol2;

View File

@@ -22,7 +22,7 @@ module MMC0(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -75,7 +75,7 @@ module Mapper13(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -137,7 +137,7 @@ module Mapper30(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -161,47 +161,48 @@ reg [15:0] flags_out = 0;
reg [4:0] prgbank;
reg [1:0] chrbank;
reg [2:0] mirror;
wire four_screen = (mirror[2:1] == 2'b11);
reg nametable;
wire four_screen = flags[16] && flags[14];
always @(posedge clk) begin
if (~enable) begin
// Set value for mirroring
mirror[2:1] <= {flags[16], flags[14]};
prgbank <= 0;
chrbank <= 0;
nametable <= 0;
end else if (ce) begin
if (prg_ain[15] & prg_write) begin
{mirror[0], chrbank, prgbank} <= prg_din[7:0];
{nametable, chrbank, prgbank} <= prg_din[7:0];
end
end
end
always begin
// mirroring mode
casez({mirror[2:1],chr_ain[13]})
3'b001 : vram_a10 = {chr_ain[11]}; // horizontal
3'b011 : vram_a10 = {chr_ain[10]}; // vertical
3'b101 : vram_a10 = {mirror[0]}; // 1 screen
3'b111 : vram_a10 = {chr_ain[10]}; // 4 screen
default : vram_a10 = {chr_ain[10]}; // pattern table
casez({flags[16], flags[14]})
3'b00 : vram_a10 = chr_ain[11]; // horizontal
3'b01 : vram_a10 = chr_ain[10]; // vertical
3'b10 : vram_a10 = nametable; // 1 screen
default : vram_a10 = chr_ain[10]; // 4 screen
endcase
end
assign prg_aout = {3'b000, prg_ain[14] ? 5'b11111 : prgbank, prg_ain[13:0]};
assign prg_aout = {3'b000, (prg_ain[15:14] == 2'b11) ? 5'b11111 : prgbank, prg_ain[13:0]};
assign prg_allow = prg_ain[15] && !prg_write;
assign chr_allow = flags[15];
assign chr_aout = {flags[15] ? 7'b11_1111_1 : 7'b10_0000_0, (four_screen && (chr_ain[13])) ? 2'b11 : chrbank, chr_ain[12:11], vram_a10, chr_ain[9:0]};
assign chr_aout = {flags[15] ? 7'b11_1111_1 : 7'b10_0000_0, (four_screen && chr_ain[13]) ? 2'b11 : chrbank, chr_ain[12:0]};
assign vram_ce = chr_ain[13] && !four_screen;
endmodule
// 11 - Color Dreams
// 38 - Bit Corps
// 86 - Jaleco JF-13 -- no audio samples
// 87 - Jaleco JF-11,JF-14
// 11 - Color Dreams
// 38 - Bit Corps
// 46 - RumbleStation 15-in-1
// 86 - Jaleco JF-13 -- no audio samples
// 87 - Jaleco JF-11,JF-14
// 101 - Jaleco JF-11,JF-14
// 140 - Jaleco JF-11,JF-14
// 66 - GxROM
// 66 - GxROM
// 145 - Sachen
// 149 - Sachen
module Mapper66(
@@ -225,7 +226,7 @@ module Mapper66(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -247,13 +248,14 @@ wire vram_ce;
wire [15:0] flags_out = {13'h0, prg_conflict, 2'b00};
reg [1:0] prg_bank;
reg [3:0] chr_bank;
reg [4:0] prg_bank;
reg [6:0] chr_bank;
wire [7:0] mapper = flags[7:0];
wire GXROM = (mapper == 66);
wire BitCorps = (mapper == 38);
wire Mapper140 = (mapper == 140);
wire Mapper101 = (mapper == 101);
wire Mapper46 = (mapper == 46);
wire Mapper86 = (mapper == 86);
wire Mapper87 = (mapper == 87);
wire Mapper145 = (mapper == 145);
@@ -266,33 +268,37 @@ if (~enable) begin
end else if (ce) begin
if (prg_ain[15] & prg_write) begin
if (GXROM)
{prg_bank, chr_bank} <= {prg_din[5:4], 2'b0, prg_din[1:0]};
{prg_bank, chr_bank} <= {3'b0, prg_din[5:4], 5'b0, prg_din[1:0]};
else if (Mapper149)
{chr_bank} <= {3'b0, prg_din[7]};
{chr_bank} <= {6'b0, prg_din[7]};
else if (Mapper46)
{chr_bank[2:0], prg_bank[0]} <= {prg_din[6:4], prg_din[0]};
else // Color Dreams
{chr_bank, prg_bank} <= {prg_din[7:4], prg_din[1:0]};
{chr_bank, prg_bank} <= {3'b0, prg_din[7:4], 3'b0, prg_din[1:0]};
end else if ((prg_ain[15:12]==4'h7) & prg_write & BitCorps) begin
{chr_bank, prg_bank} <= {prg_din[3:0]};
{chr_bank, prg_bank} <= {3'b0, prg_din[3:0]};
end else if ((prg_ain[15:12]==4'h6) & prg_write) begin
if (Mapper140) begin
{prg_bank, chr_bank} <= {prg_din[5:4], prg_din[3:0]};
{prg_bank, chr_bank} <= {3'b0, prg_din[5:4], 3'b0, prg_din[3:0]};
end else if (Mapper46) begin
{chr_bank[6:3], prg_bank[4:1]} <= {prg_din[7:4], prg_din[3:0]};
end else if (Mapper101) begin
{chr_bank} <= {prg_din[3:0]}; // All 8 bits instead?
{chr_bank} <= {3'b0, prg_din[3:0]}; // All 8 bits instead?
end else if (Mapper87) begin
{chr_bank} <= {2'b00, prg_din[0], prg_din[1]};
{chr_bank} <= {5'b00, prg_din[0], prg_din[1]};
end else if (Mapper86) begin
{prg_bank, chr_bank} <= {prg_din[5:4], 1'b0, prg_din[6], prg_din[1:0]};
{prg_bank, chr_bank} <= {3'b0, prg_din[5:4], 4'b0, prg_din[6], prg_din[1:0]};
end
end else if ((prg_ain[15:8]==8'h41) & prg_write) begin
if (Mapper145)
{chr_bank} <= {3'b0, prg_din[7]};
{chr_bank} <= {6'b0, prg_din[7]};
end
end
assign prg_aout = {5'b00_000, prg_bank, prg_ain[14:0]};
assign prg_aout = {2'b00, prg_bank, prg_ain[14:0]};
assign prg_allow = prg_ain[15] && !prg_write;
assign chr_allow = flags[15];
assign chr_aout = {5'b10_000, chr_bank, chr_ain[12:0]};
assign chr_aout = {2'b10, chr_bank, chr_ain[12:0]};
assign vram_ce = chr_ain[13];
assign vram_a10 = flags[14] ? chr_ain[10] : chr_ain[11];
wire prg_conflict = prg_ain[15] && (Mapper149);
@@ -322,7 +328,7 @@ module Mapper34(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -404,7 +410,7 @@ module Mapper71(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -486,7 +492,7 @@ module Mapper77(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -559,7 +565,7 @@ module Mapper78(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -647,7 +653,7 @@ module Mapper79(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -725,7 +731,7 @@ module Mapper89(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -831,7 +837,7 @@ module Mapper107(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -900,7 +906,7 @@ module Mapper28(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -921,9 +927,9 @@ wire chr_allow;
reg vram_a10;
reg [7:0] chr_dout;
wire vram_ce;
wire [15:0] flags_out = {13'h0, prg_conflict, prg_open_bus, has_chr_dout};
wire [15:0] flags_out = {13'h0, prg_conflict, 1'b0, has_chr_dout};
wire prg_open_bus, prg_conflict, has_chr_dout;
wire prg_conflict, has_chr_dout;
reg [6:0] a53prg; // output PRG ROM (A14-A20 on ROM)
reg [1:0] a53chr; // output CHR RAM (A13-A14 on RAM)
@@ -1039,7 +1045,6 @@ assign vram_ce = chr_ain[13];
assign prg_aout = {1'b0, (a53prg & 7'b0011111), prg_ain[13:0]};
assign prg_allow = prg_ain[15] && !prg_write;
assign prg_conflict = prg_ain[15] && (mapper == 3) && (submapper != 1);
assign prg_open_bus = (prg_ain[15:13] == 3'b011) && (mapper == 7);
assign chr_allow = flags[15];
assign chr_aout = {7'b10_0000_0, a53chr, chr_ain[12:0]};
wire [4:0] submapper = flags[24:21];

View File

@@ -1,5 +1,5 @@
// These are misc small one-off mappers. Some may end up being merged with Generic mappers.
// altera message_off 10027
// #15 - 100-in-1 Contra Function 16
module Mapper15(
input clk, // System clock
@@ -22,7 +22,7 @@ module Mapper15(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -102,7 +102,7 @@ assign vram_a10 = mirroring ? chr_ain[11] : chr_ain[10];
endmodule
// Mapper 16, 159 Bandai
// Mapper 16, 153, 159 Bandai
module Mapper16(
input clk, // System clock
input ce, // M2 ~cpu_clk
@@ -124,7 +124,7 @@ module Mapper16(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
// Special ports
output [17:0] mapper_addr,
input [7:0] mapper_data_in,
@@ -150,10 +150,11 @@ wire chr_allow;
reg vram_a10;
wire vram_ce;
reg irq;
reg [15:0] flags_out = 0;
wire [15:0] flags_out = {14'd0, prg_bus_write, 1'b0};
wire [7:0] prg_dout;
reg [3:0] prg_bank;
reg outer_prg_bank;
reg [3:0] inner_prg_bank;
reg [7:0] chr_bank_0, chr_bank_1, chr_bank_2, chr_bank_3,
chr_bank_4, chr_bank_5, chr_bank_6, chr_bank_7;
reg [3:0] prg_sel;
@@ -164,12 +165,14 @@ reg [15:0] irq_counter;
reg [15:0] irq_latch;
reg eeprom_scl, eeprom_sda;
wire submapper5 = (flags[24:21] == 5);
wire mapper153 = (flags[7:0] == 153);
wire mapper159 = (flags[7:0] == 159);
wire mapperalt = submapper5 | mapper159;
wire mapperalt = submapper5 | mapper159 | mapper153;
always @(posedge clk) begin
if (~enable) begin
prg_bank <= 4'hF;
outer_prg_bank <= 0;
inner_prg_bank <= 0;
chr_bank_0 <= 0;
chr_bank_1 <= 0;
chr_bank_2 <= 0;
@@ -189,15 +192,15 @@ always @(posedge clk) begin
if (prg_write)
if(((prg_ain[14:13] == 2'b11) && (!mapperalt)) || (prg_ain[15])) // Cover all from $6000 to $FFFF to maximize compatibility
case(prg_ain & 'hf) // Registers are mapped every 16 bytes
'h0: chr_bank_0 <= prg_din[7:0];
'h1: chr_bank_1 <= prg_din[7:0];
'h2: chr_bank_2 <= prg_din[7:0];
'h3: chr_bank_3 <= prg_din[7:0];
'h4: chr_bank_4 <= prg_din[7:0];
'h5: chr_bank_5 <= prg_din[7:0];
'h6: chr_bank_6 <= prg_din[7:0];
'h7: chr_bank_7 <= prg_din[7:0];
'h8: prg_bank <= prg_din[3:0];
'h0: if (!mapper153) chr_bank_0 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h1: if (!mapper153) chr_bank_1 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h2: if (!mapper153) chr_bank_2 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h3: if (!mapper153) chr_bank_3 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h4: if (!mapper153) chr_bank_4 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h5: if (!mapper153) chr_bank_5 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h6: if (!mapper153) chr_bank_6 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h7: if (!mapper153) chr_bank_7 <= prg_din[7:0]; else outer_prg_bank <= prg_din[0];
'h8: inner_prg_bank <= prg_din[3:0];
'h9: mirroring <= prg_din[1:0];
'ha: {irq_up, irq_enable} <= {1'b1, prg_din[0]};
'hb: begin
@@ -240,11 +243,11 @@ always begin
endcase
end
reg [3:0] prgsel;
reg [4:0] prgsel;
always begin
case(prg_ain[15:14])
2'b10: prgsel = prg_bank; // $8000 is swapable
2'b11: prgsel = 4'hF; // $C000 is hardwired to last bank
2'b10: prgsel = {outer_prg_bank, inner_prg_bank}; // $8000 is swapable
2'b11: prgsel = {outer_prg_bank, 4'hF}; // $C000 is hardwired to last inner bank
default: prgsel = 0;
endcase
end
@@ -263,16 +266,17 @@ always begin
endcase
end
assign chr_aout = {4'b10_00, chrsel, chr_ain[9:0]}; // 1kB banks
wire [21:0] prg_aout_tmp = {4'b00_00, prgsel, prg_ain[13:0]}; // 16kB banks
assign chr_aout = mapper153 ? {9'b10_0000_000, chr_ain[12:0]} : {4'b10_00, chrsel, chr_ain[9:0]}; // 1kB banks or 8kb unbanked
wire [21:0] prg_aout_tmp = {3'b00_0, prgsel, prg_ain[13:0]}; // 16kB banks
wire prg_is_ram = (prg_ain >= 'h6000) && (prg_ain < 'h8000);
wire [21:0] prg_ram = {9'b11_1100_000, prg_ain[12:0]};
assign prg_aout = prg_is_ram ? prg_ram : prg_aout_tmp;
// EEPROM - not used - Could use write to EEPROM cycle for both reads and write accesses, but this is easier
assign prg_dout = prg_is_ram ? prg_write ? mapper_data_out : {3'b111, sda_out, 4'b1111} : 8'hFF;
assign prg_dout = (!mapper153 && prg_is_ram) ? prg_write ? mapper_data_out : {3'b111, sda_out, 4'b1111} : 8'hFF;
wire prg_bus_write = (!mapper153 && prg_is_ram);
assign prg_allow = (prg_ain[15] && !prg_write);
assign prg_allow = (prg_ain[15] && !prg_write) || (prg_is_ram && eeprom_scl && mapper153);
assign chr_allow = flags[15];
assign vram_ce = chr_ain[13];
@@ -281,7 +285,7 @@ wire [7:0] ram_addr;
wire ram_read;
assign mapper_addr[17:8] = 0;
assign mapper_addr[7:0] = ram_addr;
assign mapper_ovr = 1'b1;
assign mapper_ovr = mapper159 || submapper5;
EEPROM_24C0x eeprom(
.type_24C01(mapper159), //24C01 is 128 bytes, 24C02 is 256 bytes
@@ -325,7 +329,7 @@ module Mapper18(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -514,7 +518,7 @@ module Mapper32(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -559,7 +563,7 @@ end else if (ce) begin
casez ({prg_ain[13:12], submapper1, prg_ain[2:0]})
6'b00_?_???: prgreg0 <= prg_din[4:0];
6'b01_0_???: {prgmode, mirror} <= prg_din[1:0];
6'b10_0_???: prgreg1 <= prg_din[4:0];
6'b10_?_???: prgreg1 <= prg_din[4:0];
6'b11_?_000: chrreg0 <= prg_din;
6'b11_?_001: chrreg1 <= prg_din;
6'b11_?_010: chrreg2 <= prg_din;
@@ -633,7 +637,7 @@ module Mapper42(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -739,7 +743,7 @@ module Mapper65(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -879,7 +883,7 @@ module Mapper41(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -951,7 +955,7 @@ module Mapper218(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -1003,7 +1007,7 @@ module Mapper228(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -1074,7 +1078,7 @@ module Mapper234(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -1153,7 +1157,7 @@ module Mapper72(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -1231,7 +1235,7 @@ module Mapper162(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -1313,7 +1317,7 @@ module Mapper164(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -1361,10 +1365,147 @@ assign vram_a10 = flags[14] ? chr_ain[10] : chr_ain[11];
endmodule
// 163 Nanjing
module Nanjing(
input clk, // System clock
input ce, // M2 ~cpu_clk
input enable, // Mapper enabled
input [31:0] flags, // Cart flags
input [15:0] prg_ain, // prg address
inout [21:0] prg_aout_b, // prg address out
input prg_read, // prg read
input prg_write, // prg write
input [7:0] prg_din, // prg data in
inout [7:0] prg_dout_b, // prg data out
inout prg_allow_b, // Enable access to memory for the specified operation.
input [13:0] chr_ain, // chr address in
inout [21:0] chr_aout_b, // chr address out
input chr_read, // chr ram read
inout chr_allow_b, // chr allow write
inout vram_a10_b, // Value for A10 address line
inout vram_ce_b, // True if the address should be routed to the internal 2kB VRAM.
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
input [19:0] ppuflags,
input ppu_ce
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
assign prg_dout_b = enable ? prg_dout : 8'hZ;
assign prg_allow_b = enable ? prg_allow : 1'hZ;
assign chr_aout_b = enable ? chr_aout : 22'hZ;
assign chr_allow_b = enable ? chr_allow : 1'hZ;
assign vram_a10_b = enable ? vram_a10 : 1'hZ;
assign vram_ce_b = enable ? vram_ce : 1'hZ;
assign irq_b = enable ? 1'b0 : 1'hZ;
assign flags_out_b = enable ? flags_out : 16'hZ;
assign audio_b = enable ? {1'b0, audio_in[15:1]} : 16'hZ;
wire [21:0] prg_aout, chr_aout;
wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
reg [7:0] prg_dout;
wire [15:0] flags_out = {14'd0, prg_bus_write, 1'b0};
reg prg_bus_write;
reg [7:0] prg_bank;
reg chr_bank;
reg chr_switch;
reg trigger;
reg trig_comp;
reg [7:0] security[4];
wire [8:0] scanline = ppuflags[19:11];
wire [8:0] cycle = ppuflags[10:2];
always @(posedge clk) begin
if (~enable) begin
prg_bank <= 8'h0F;
trigger <= 0; // Initial value 0
security <= '{8'h00, 8'h00, 8'h00, 8'h00};
chr_switch <= 0;
trig_comp <= 1; // Initial value 1
end else if (ce) begin
prg_dout <= prg_din;
prg_bus_write <= 0;
if (prg_write) begin
if (prg_ain == 16'h5101) begin
if (trig_comp && ~|prg_din)
trigger <= ~trigger;
trig_comp <= |prg_din;
end else begin
case (prg_ain & 16'h7300)
// If the most significant bit of this register is set, it does automatic CHR RAM switching
'h5000: begin
prg_bank[3:0] <= prg_din[3:0];
chr_switch <= prg_din[7];
security[0] <= prg_din;
end
'h5100: begin
security[1] <= prg_din;
if (prg_din == 6)
prg_bank <= 8'h3;
end
'h5200: begin
prg_bank[7:4] <= prg_din[3:0];
security[2] <= prg_din;
end
'h5300: security[3] <= prg_din;
endcase
end
end else if (prg_read) begin // Security stuff as Mesen does it
prg_bus_write <= 1'b1;
case (prg_ain & 16'h7700)
'h5100: prg_dout <= security[0] | security[1] | security[3] | (security[2] ^ 8'hFF);
'h5500: prg_dout <= trigger ? (security[3] | security[0]) : 8'h0;
default: begin
prg_dout <= 8'hFF;
prg_bus_write <= 0;
end
endcase
end
end
// The exact way this works is unknown but is conjectured
// to resemble iNES Mapper 096, latching PA9 at start of nametable reads.
// When turned on, both 4K CHR RAM banks 0000-0FFF and 1000-1FFF map to 0000-0FFF
// for scanline 240 until scanline 128. Then at scanline 128, both 4K CHR banks
// point to 1000-1FFF.
if(~enable) begin
chr_bank <= 0;
end else if (ppu_ce) begin
if (cycle > 254) begin
if (scanline == 239)
chr_bank <= 0;
else if(scanline == 127)
chr_bank <= 1;
end
end
end
wire prg_is_ram = prg_ain >= 'h6000 && prg_ain < 'h8000;
wire [21:0] prg_ram = {9'b11_1100_000, prg_ain[12:0]};
assign prg_aout = prg_is_ram ? prg_ram : {prg_bank[5:0], prg_ain[14:0]};
assign prg_allow = prg_ain[15] && !prg_write || prg_is_ram;
assign chr_allow = flags[15];
assign chr_aout = {9'b10_0000_000, chr_switch ? chr_bank : chr_ain[12], chr_ain[11:0]};
assign vram_ce = chr_ain[13];
assign vram_a10 = flags[14] ? chr_ain[10] : chr_ain[11];
endmodule
// Combine with other mapper (15?)
// #225 - 64-in-1
// #255 - 110-in-1 - This runs with buggy menu selection. It runs correctly as mapper 225.
// Unsure if any games require simulating missing 74-670 RAM (4 bytes).
// Unsure if any games require simulating missing 74-670 RAM (4 nybbles).
module Mapper225(
input clk, // System clock
input ce, // M2 ~cpu_clk
@@ -1386,7 +1527,7 @@ module Mapper225(
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_open_bus, has_chr_dout}
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
@@ -1406,9 +1547,9 @@ wire chr_allow;
wire vram_a10;
wire vram_ce;
wire [7:0] prg_dout;
wire prg_open_bus = mapper255 && prg_ram || (!prg_ram && !prg_ain[15]);
wire prg_bus_write = (~mapper255 & prg_ram);
wire prg_ram = (prg_ain[15:11] == 5'b01011);
wire [15:0] flags_out = {14'h0, prg_open_bus, 1'b0};
wire [15:0] flags_out = {14'h0, prg_bus_write, 1'b0};
wire [7:0] mapper = flags[7:0];
wire mapper255 = (mapper == 8'd255);
@@ -1450,3 +1591,447 @@ assign vram_ce = chr_ain[13];
assign vram_a10 = mirroring ? chr_ain[11] : chr_ain[10];
endmodule
// #31 - NSF Player
module NSF(
input clk, // System clock
input ce, // M2 ~cpu_clk
input enable, // Mapper enabled
input [31:0] flags, // Cart flags
input [15:0] prg_ain, // prg address
inout [21:0] prg_aout_b, // prg address out
input prg_read, // prg read
input prg_write, // prg write
input [7:0] prg_din, // prg data in
inout [7:0] prg_dout_b, // prg data out
inout prg_allow_b, // Enable access to memory for the specified operation.
input [13:0] chr_ain, // chr address in
inout [21:0] chr_aout_b, // chr address out
input chr_read, // chr ram read
inout chr_allow_b, // chr allow write
inout vram_a10_b, // Value for A10 address line
inout vram_ce_b, // True if the address should be routed to the internal 2kB VRAM.
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
output [5:0] exp_audioe, // Expansion Enabled (0x0=None, 0x1=VRC6, 0x2=VRC7, 0x4=FDS, 0x8=MMC5, 0x10=N163, 0x20=SS5B
inout [15:0] flags_out_b, // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
input [7:0] fds_din // fds data in
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
assign prg_dout_b = enable ? prg_dout : 8'hZ;
assign prg_allow_b = enable ? prg_allow : 1'hZ;
assign chr_aout_b = enable ? chr_aout : 22'hZ;
assign chr_allow_b = enable ? chr_allow : 1'hZ;
assign vram_a10_b = enable ? vram_a10 : 1'hZ;
assign vram_ce_b = enable ? vram_ce : 1'hZ;
assign irq_b = enable ? 1'b0 : 1'hZ;
assign flags_out_b = enable ? flags_out : 16'hZ;
assign audio_b = enable ? {audio_in[15:0]} : 16'hZ;
assign exp_audioe = enable ? nsf_reg[3][5:0] : 6'h00;
wire [21:0] prg_aout, chr_aout;
wire [7:0] prg_dout;
wire prg_allow;
wire chr_allow;
wire vram_a10;
wire vram_ce;
wire [15:0] flags_out = {14'd0, prg_bus_write, 1'b0};
reg prg_bus_write;
wire [3:0] submapper = flags[24:21];
reg [7:0] nsf_reg [15:0];
reg [15:0] counter;
reg [5:0] clk1MHz;
// Resuse MMC5 multiplier instead?
reg [7:0] multiplier_1;
reg [7:0] multiplier_2;
wire [15:0] multiply_result = multiplier_1 * multiplier_2;
/*
;----------------------------------
; NSF player for PowerPak
;
; Player rom is at $4100-4FFF (NSF header at $4100)
;
; PowerPak registers:
;
; 5FF0: timer latch LSB
; 5FF1: timer latch MSB
; 5FF2: timer status (Read: bit7=timer wrapped, Write: clear status)
; 5FF3: Expansion audio control (copy header[0x7B] here)
; 5FF6-5FFF: banking registers (as described in NSF spec)
;
; Timer details:
; PowerPak NSF mapper has a 16bit 1MHz counter that counts down from [5FF1:5FF0] to 0.
; After the counter reaches 0, it's automatically reloaded and timer status bit is set.
; Clear the status bit by writing to $5FF2.
;
;-----------------------------------
*/
always @(posedge clk) begin
// 21.477272MHz/1MHz
// Using 21.5; Replace with actual pll?
clk1MHz <= clk1MHz + 1'b1;
if (clk1MHz == 6'd42)
clk1MHz <= 6'd0;
if (clk1MHz == 6'd21 || clk1MHz == 6'd42) begin
counter <= counter - 1'b1;
if (counter == 16'h0000)
begin
counter <= {nsf_reg[1], nsf_reg[0]};
nsf_reg[2] <= 8'h80;
end
end
if (~enable) begin
nsf_reg[4'h3] <= 8'h00;
nsf_reg[4'h6] <= 8'h06;
nsf_reg[4'h7] <= 8'h07;
nsf_reg[4'h8] <= 8'h00;
nsf_reg[4'h9] <= 8'h01;
nsf_reg[4'hA] <= 8'h02;
nsf_reg[4'hB] <= 8'h03;
nsf_reg[4'hC] <= 8'h04;
nsf_reg[4'hD] <= 8'h05;
nsf_reg[4'hE] <= 8'h06;
nsf_reg[4'hF] <= 8'hFF;
end else if (ce) begin
if ((prg_ain[15:4]==12'h5FF) && prg_write)
nsf_reg[prg_ain[3:0]] <= prg_din;
if ((prg_ain==16'h5FF2) && prg_write)
nsf_reg[2] <= 8'h00;
if ((prg_ain==16'h5205) && prg_write)
multiplier_1 <= prg_din;
if ((prg_ain==16'h5206) && prg_write)
multiplier_2 <= prg_din;
end
end
wire [9:0] prg_bank;
always begin
casez({prg_ain[15:12], exp_audioe[2]})
5'b00???: prg_bank = 10'h0;//{10'b11_1110_0000};
5'b0100?: prg_bank = 10'h0;//{10'b11_1110_0000};
5'b0101?: prg_bank = {10'b11_1110_0000};
5'b011?0: prg_bank = {9'b11_1100_000, prg_ain[12]};
5'b011?1: prg_bank = {2'b01, nsf_reg[{3'b011, prg_ain[12]}]};
5'b1????: prg_bank = {2'b01, nsf_reg[{1'b1, prg_ain[14:12]}]};
endcase
end
always begin
prg_bus_write = 1'b1;
if (prg_ain == 16'h5205) begin
prg_dout = multiply_result[7:0];
end else if (prg_ain == 16'h5206) begin
prg_dout = multiply_result[15:8];
end else if (prg_ain[15:8] == 8'h40) begin
prg_dout = fds_din;
end else if (prg_ain == 16'h5FF2) begin
prg_dout = nsf_reg[4'h2];
end else begin
prg_dout = prg_din;
prg_bus_write = 0;
end
end
assign prg_aout = ((submapper == 4'hF) && ({prg_ain[15:1],1'b0} == 16'hFFFC)) ? {10'h0, prg_ain[11:0]} : {prg_bank, prg_ain[11:0]};
assign prg_allow = (((prg_ain[15] || ((prg_ain>=16'h4080) && (prg_ain<16'h4FFF))) && !prg_write) || (prg_ain[15:13]==3'b011)
|| (prg_ain[15:10]==6'b010111 && prg_ain[9:4]!=6'b111111) || ((prg_ain>=16'h8000) && (prg_ain<16'hDFFF) && exp_audioe[2]));
assign chr_allow = flags[15]; // CHR RAM always...
assign chr_aout = {9'b10_0000_000, chr_ain[12:0]};
assign vram_ce = chr_ain[13];
assign vram_a10 = flags[14] ? chr_ain[10] : chr_ain[11];
endmodule
// 111 - Cheapocabra/GTROM
// Supports all features except LED and self-reflashing support
module Mapper111(
input clk, // System clock
input ce, // M2 ~cpu_clk
input enable, // Mapper enabled
input [31:0] flags, // Cart flags
input [15:0] prg_ain, // prg address
inout [21:0] prg_aout_b, // prg address out
input prg_read, // prg read
input prg_write, // prg write
input [7:0] prg_din, // prg data in
inout [7:0] prg_dout_b, // prg data out
inout prg_allow_b, // Enable access to memory for the specified operation.
input [13:0] chr_ain, // chr address in
inout [21:0] chr_aout_b, // chr address out
input chr_read, // chr ram read
inout chr_allow_b, // chr allow write
inout vram_a10_b, // Value for A10 address line
inout vram_ce_b, // True if the address should be routed to the internal 2kB VRAM.
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
assign prg_dout_b = enable ? prg_dout : 8'hZ;
assign prg_allow_b = enable ? prg_allow : 1'hZ;
assign chr_aout_b = enable ? chr_aout : 22'hZ;
assign chr_allow_b = enable ? chr_allow : 1'hZ;
assign vram_a10_b = enable ? vram_a10 : 1'hZ;
assign vram_ce_b = enable ? vram_ce : 1'hZ;
assign irq_b = enable ? irq : 1'hZ;
assign flags_out_b = enable ? flags_out : 16'hZ;
assign audio_b = enable ? audio : 16'hZ;
wire [21:0] prg_aout, chr_aout;
wire [7:0] prg_dout;
wire prg_allow, chr_allow;
wire vram_ce, vram_a10;
wire [15:0] audio = audio_in;
wire irq;
reg [15:0] flags_out = 0;
reg [3:0] prgbank_reg;
reg chrbank_reg;
reg namebank_reg;
always@(posedge clk) begin // register mask: 01x1 xxxx xxxx xxxx
if (~enable) begin
{prgbank_reg, chrbank_reg, namebank_reg} <= 0;
end else if(ce & prg_write & prg_ain[12] & prg_ain[14] & !prg_ain[15]) begin
prgbank_reg <= prg_din[3:0];
chrbank_reg <= prg_din[4];
namebank_reg <= prg_din[5];
end
end
assign chr_aout[21:15] = 7'b11_1100_0;
assign chr_aout[14:13] = {chr_ain[13], chr_ain[13]?namebank_reg:chrbank_reg};
assign chr_aout[12:0] = chr_ain[12:0];
assign vram_a10 = chr_aout[10];
assign prg_aout[21:19] = 3'b000;
assign prg_aout[18:15] = prgbank_reg;
assign prg_aout[14:0] = prg_ain[14:0];
assign prg_allow = prg_ain[15] && !prg_write;
assign chr_allow = 1'b1;
assign prg_dout = 8'hFF;
assign vram_ce = 1'b0;
assign irq = 1'b0;
endmodule
// 83 Cony/Yoko - Unlicensed fighting game bootlegs
// Street Fighter II Pro, Fatal Fury 2, World Heroes 2
module Mapper83(
input clk, // System clock
input ce, // M2 ~cpu_clk
input enable, // Mapper enabled
input [31:0] flags, // Cart flags
input [15:0] prg_ain, // prg address
inout [21:0] prg_aout_b, // prg address out
input prg_read, // prg read
input prg_write, // prg write
input [7:0] prg_din, // prg data in
inout [7:0] prg_dout_b, // prg data out
inout prg_allow_b, // Enable access to memory for the specified operation.
input [13:0] chr_ain, // chr address in
inout [21:0] chr_aout_b, // chr address out
input chr_read, // chr ram read
inout chr_allow_b, // chr allow write
inout vram_a10_b, // Value for A10 address line
inout vram_ce_b, // True if the address should be routed to the internal 2kB VRAM.
inout irq_b, // IRQ
input [15:0] audio_in, // Inverted audio from APU
inout [15:0] audio_b, // Mixed audio output
inout [15:0] flags_out_b // flags {0, 0, 0, 0, 0, prg_conflict, prg_bus_write, has_chr_dout}
);
assign prg_aout_b = enable ? prg_aout : 22'hZ;
assign prg_dout_b = enable ? prg_dout : 8'hZ;
assign prg_allow_b = enable ? prg_allow : 1'hZ;
assign chr_aout_b = enable ? chr_aout : 22'hZ;
assign chr_allow_b = enable ? chr_allow : 1'hZ;
assign vram_a10_b = enable ? vram_a10 : 1'hZ;
assign vram_ce_b = enable ? vram_ce : 1'hZ;
assign irq_b = enable ? irq : 1'hZ;
assign flags_out_b = enable ? flags_out : 16'hZ;
assign audio_b = enable ? audio : 16'hZ;
wire [21:0] prg_aout, chr_aout;
reg [7:0] prg_dout;
wire prg_allow, chr_allow;
wire vram_ce, vram_a10;
wire [15:0] audio = audio_in;
wire [15:0] flags_out = {14'h0, prg_bus_write, 1'h0};
wire prg_bus_write;
wire submapper1 = flags[21];
wire submapper2 = flags[22];
// mode register bits
reg [1:0] prgbank_mode; // determines PRG banking mode
reg [1:0] mirroring;
reg prg_reg3_enable; // if 1, maps 8 KiB PRG bank to 0x6000-0x7FFF for submapper 0 and 1
reg irq_mode, irq_latch;
reg irq;
reg irq_enable;
reg [15:0] irq_counter;
reg [4:0] prgbank_reg[3:0];
reg [3:0] prgbank_reg4;
reg [7:0] chrbank_reg[7:0];
reg [1:0] dipswitch; // alters title screen, wrong dipswitch can result in garbled graphics
reg [7:0] scratch_ram[3:0];
// Submapper 2 only
// outer 256 KiB PRG/CHR-ROM bank
reg [1:0] outer_bank;
// select 8 KiB WRAM bank
reg [1:0] wrambank;
always@(posedge clk) begin
if (~enable) begin
{irq, irq_mode, irq_latch, irq_enable, irq_counter} <= 0;
{prg_reg3_enable, prgbank_mode, mirroring} <= 0;
outer_bank <= 0;
wrambank <= 0;
dipswitch <= 0;
chrbank_reg <= '{default:0};
prgbank_reg <= '{default:0};
prgbank_reg4 <= 0;
scratch_ram <= '{default:0};
end else if(ce) begin
if (prg_write) begin
casez(prg_ain[15:8])
8'b1???_??00 : begin
{wrambank, outer_bank} <= prg_din[7:4];
{prgbank_reg4} <= prg_din[3:0];
end
8'b1???_??01 : begin
{irq_latch, irq_mode, prg_reg3_enable, prgbank_mode} <= prg_din[7:3];
mirroring <= prg_din[1:0];
end
8'b1???_??10 : begin
if (prg_ain[0]) begin
irq_counter[15:8] <= prg_din;
irq_enable <= irq_latch;
end else begin
irq_counter[7:0] <= prg_din;
irq <= 1'b0; // IRQ ACK
end
end
8'b1???_??11 : begin
if (prg_ain[4]) begin
if (!prg_ain[3])
chrbank_reg[prg_ain[2:0]] <= prg_din;
end else
prgbank_reg[prg_ain[1:0]] <= prg_din[4:0];
end
8'b0101_???? : begin
if (|prg_ain[11:8])
scratch_ram[prg_ain[1:0]] <= prg_din;
end
endcase
end
if (irq_enable) begin
if (irq_mode)
irq_counter <= irq_counter - 16'd1;
else
irq_counter <= irq_counter + 16'd1;
end
if (irq_enable && (irq_counter == 16'h0000)) begin
irq <= 1'b1;
irq_enable <= 1'b0;
end
end
end
always_comb begin
// mirroring
casez(mirroring[1:0])
2'b00: vram_a10 = {chr_ain[10]}; // vertical
2'b01: vram_a10 = {chr_ain[11]}; // horizontal
2'b1?: vram_a10 = {mirroring[0]}; // single screen
endcase
end
// PRG address space mapping
reg [4:0] prgsel;
always_comb begin
casez ({prgbank_mode, prg_ain[15:13]})
// mode 0
5'b00_10? : prgsel = {prgbank_reg4, prg_ain[13]}; // 0x8000-0xBFFF
5'b00_11? : prgsel = {4'b1111, prg_ain[13]}; // 0xC000-0xFFFF
// mode 1
5'b01_1?? : prgsel = {prgbank_reg4[3:1], prg_ain[14:13]}; // 0x8000-0xFFFF
// mode 2 and 3
5'b1?_100 : prgsel = prgbank_reg[0]; // 0x8000-0x9FFF
5'b1?_101 : prgsel = prgbank_reg[1]; // 0xA000-0xBFFF
5'b1?_110 : prgsel = prgbank_reg[2]; // 0xC000-0xDFFF
5'b1?_111 : prgsel = 5'b11_111; // 0xE000-0xFFFF
// all modes
5'b??_011 : prgsel = prgbank_reg[3]; // 0x6000-0x7FFF
default : prgsel = {2'd0, prg_ain[15:13]};
endcase
end
// CHR address space mapping
reg [9:0] chrsel;
always_comb begin
chrsel = 0;
casez({submapper1, chr_ain[13:11]})
// submapper 1
4'b1_000 : chrsel = {1'b0, chrbank_reg[0], chr_ain[10]};
4'b1_001 : chrsel = {1'b0, chrbank_reg[1], chr_ain[10]};
4'b1_010 : chrsel = {1'b0, chrbank_reg[6], chr_ain[10]};
4'b1_011 : chrsel = {1'b0, chrbank_reg[7], chr_ain[10]};
// submapper 0 and 2
4'b0_0?? : chrsel = {submapper2 ? outer_bank : 2'b00, chrbank_reg[chr_ain[12:10]]};
// all submappers
default : chrsel = {6'd0, chr_ain[13:10]};
endcase
end
// handle reads from scratch RAM and dipswitch
always_comb begin
casez(prg_ain[15:12])
4'h5 : begin
if (|prg_ain[11:8]) begin
prg_dout = scratch_ram[prg_ain[1:0]];
end else
prg_dout = {6'b1111_11, dipswitch};
end
default : begin
prg_dout = 8'hFF;
end
endcase
end
wire prg_read_blocked = (prg_ain[15:13] == 3'b011) && !submapper2 && !prg_reg3_enable;
assign prg_bus_write = (prg_ain[15:12] == 4'h5) || prg_read_blocked;
wire is_wram = submapper2 && (prg_ain[15:13] == 3'b011);
assign chr_aout[21:20] = 2'b10;
assign chr_aout[19:10] = chrsel;
assign chr_aout[9:0] = chr_ain[9:0];
assign prg_aout[21:18] = is_wram ? 4'b11_11 : {2'b00, submapper2 ? outer_bank : 2'b00};
assign prg_aout[17:13] = is_wram ? {3'b00_0, wrambank} : prgsel;
assign prg_aout[12:0] = prg_ain[12:0];
assign prg_allow = (prg_ain[15] && !prg_write) || is_wram;
assign chr_allow = flags[15];
assign vram_ce = chr_ain[13];
endmodule

View File

@@ -425,7 +425,7 @@ wire [7:0] prg_din = dbus & (prg_conflict ? cpumem_din : 8'hFF);
wire prg_read = mr_int && cart_pre && !apu_cs && !ppu_cs;
wire prg_write = mw_int && cart_pre && !apu_cs && !ppu_cs;
wire prg_allow, prg_open_bus, prg_conflict, vram_a10, vram_ce, chr_allow;
wire prg_allow, prg_bus_write, prg_conflict, vram_a10, vram_ce, chr_allow;
wire [21:0] prg_linaddr, chr_linaddr;
wire [7:0] prg_dout_mapper, chr_from_ppu_mapper;
wire has_chr_from_ppu_mapper;
@@ -472,7 +472,7 @@ cart_top multi_mapper (
.ppu_ce (ppu_ce), // PPU Clock (cheat for MMC5/2/4)
// Behavior helper flags
.has_chr_dout (has_chr_from_ppu_mapper), // Output specific data for CHR rather than from SDRAM
.prg_open_bus (prg_open_bus), // Simulate open bus
.prg_bus_write (prg_bus_write), // PRG data driven to bus
.prg_conflict (prg_conflict), // Simulate bus conflicts
// User input/FDS controls
.fds_eject (fds_eject), // Used to trigger FDS disk changes
@@ -512,10 +512,6 @@ assign ppumem_read = chr_read;
assign ppumem_write = chr_write && (chr_allow || vram_ce);
assign ppumem_dout = chr_from_ppu;
// These registers are open bus if FDS is not in use
// Some games hacks (Super Mario All-Stars) rely on this behavior
wire bus_is_open = (mapper_flags[7:0] == 8'd20) ? 1'b0 : (addr >= 16'h4018 && addr < 16'h4100);
reg [7:0] open_bus_data;
always @(posedge clk) begin
@@ -536,16 +532,14 @@ always @* begin
raw_data_bus = {open_bus_data[7:5], joypad_data[3:2], 2'b00, joypad_data[1]};
else
raw_data_bus = (addr == 16'h4015) ? apu_dout : open_bus_data;
end else if (bus_is_open) begin
raw_data_bus = open_bus_data;
end else if (ppu_cs) begin
raw_data_bus = ppu_dout;
end else if (prg_allow) begin
raw_data_bus = cpumem_din;
end else if (prg_open_bus) begin
raw_data_bus = open_bus_data;
end else begin
end else if (prg_bus_write) begin
raw_data_bus = prg_dout_mapper;
end else begin
raw_data_bus = open_bus_data;
end
end