From 0cb69d733ec8a85990f3ae7ae0d6bfd398d3876b Mon Sep 17 00:00:00 2001 From: Gyorgy Szombathelyi Date: Thu, 20 Feb 2020 12:18:18 +0100 Subject: [PATCH] NES: update mappers --- cores/nes/src/cart.sv | 269 +++++++++++- cores/nes/src/mappers/FDS.sv | 90 ++-- cores/nes/src/mappers/JYCompany.sv | 20 +- cores/nes/src/mappers/MMC1.sv | 7 +- cores/nes/src/mappers/MMC2.sv | 4 +- cores/nes/src/mappers/MMC3.sv | 116 ++--- cores/nes/src/mappers/MMC5.sv | 54 ++- cores/nes/src/mappers/Namco.sv | 96 +++-- cores/nes/src/mappers/Sachen.sv | 19 +- cores/nes/src/mappers/Sunsoft.sv | 86 ++-- cores/nes/src/mappers/VRC.sv | 186 +++++--- cores/nes/src/mappers/generic.sv | 97 +++-- cores/nes/src/mappers/misc.sv | 667 +++++++++++++++++++++++++++-- cores/nes/src/nes.v | 16 +- 14 files changed, 1358 insertions(+), 369 deletions(-) diff --git a/cores/nes/src/cart.sv b/cores/nes/src/cart.sv index 36ab911..8ebcb85 100644 --- a/cores/nes/src/cart.sv +++ b/cores/nes/src/cart.sv @@ -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) diff --git a/cores/nes/src/mappers/FDS.sv b/cores/nes/src/mappers/FDS.sv index 8604d8b..e382cb7 100644 --- a/cores/nes/src/mappers/FDS.sv +++ b/cores/nes/src/mappers/FDS.sv @@ -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, diff --git a/cores/nes/src/mappers/JYCompany.sv b/cores/nes/src/mappers/JYCompany.sv index 62258c7..c9e0378 100644 --- a/cores/nes/src/mappers/JYCompany.sv +++ b/cores/nes/src/mappers/JYCompany.sv @@ -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. diff --git a/cores/nes/src/mappers/MMC1.sv b/cores/nes/src/mappers/MMC1.sv index 0c9b617..c102e8a 100644 --- a/cores/nes/src/mappers/MMC1.sv +++ b/cores/nes/src/mappers/MMC1.sv @@ -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; diff --git a/cores/nes/src/mappers/MMC2.sv b/cores/nes/src/mappers/MMC2.sv index b89638c..e876d1e 100644 --- a/cores/nes/src/mappers/MMC2.sv +++ b/cores/nes/src/mappers/MMC2.sv @@ -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; diff --git a/cores/nes/src/mappers/MMC3.sv b/cores/nes/src/mappers/MMC3.sv index 8f6cb69..87f6dbf 100644 --- a/cores/nes/src/mappers/MMC3.sv +++ b/cores/nes/src/mappers/MMC3.sv @@ -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; diff --git a/cores/nes/src/mappers/MMC5.sv b/cores/nes/src/mappers/MMC5.sv index 1616110..87171f2 100644 --- a/cores/nes/src/mappers/MMC5.sv +++ b/cores/nes/src/mappers/MMC5.sv @@ -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), diff --git a/cores/nes/src/mappers/Namco.sv b/cores/nes/src/mappers/Namco.sv index b678088..6dd4860 100644 --- a/cores/nes/src/mappers/Namco.sv +++ b/cores/nes/src/mappers/Namco.sv @@ -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), diff --git a/cores/nes/src/mappers/Sachen.sv b/cores/nes/src/mappers/Sachen.sv index e484fa3..8645fa5 100644 --- a/cores/nes/src/mappers/Sachen.sv +++ b/cores/nes/src/mappers/Sachen.sv @@ -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; diff --git a/cores/nes/src/mappers/Sunsoft.sv b/cores/nes/src/mappers/Sunsoft.sv index a06e8fe..2a185b9 100644 --- a/cores/nes/src/mappers/Sunsoft.sv +++ b/cores/nes/src/mappers/Sunsoft.sv @@ -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]; diff --git a/cores/nes/src/mappers/VRC.sv b/cores/nes/src/mappers/VRC.sv index d8db23b..64d987d 100644 --- a/cores/nes/src/mappers/VRC.sv +++ b/cores/nes/src/mappers/VRC.sv @@ -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; diff --git a/cores/nes/src/mappers/generic.sv b/cores/nes/src/mappers/generic.sv index 523ebeb..71f6a03 100644 --- a/cores/nes/src/mappers/generic.sv +++ b/cores/nes/src/mappers/generic.sv @@ -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]; diff --git a/cores/nes/src/mappers/misc.sv b/cores/nes/src/mappers/misc.sv index 8ec7e0e..b17b3e9 100644 --- a/cores/nes/src/mappers/misc.sv +++ b/cores/nes/src/mappers/misc.sv @@ -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 diff --git a/cores/nes/src/nes.v b/cores/nes/src/nes.v index 9cfe50e..2361a72 100644 --- a/cores/nes/src/nes.v +++ b/cores/nes/src/nes.v @@ -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