Action 53 mapper/Verilog
From NESdev Wiki
Jump to navigationJump to search
infiniteneslives
//-------------------------------------------------------------------------------- // INL-ROM Action53 Multi-discrete mapper // Designed for use with a multicart that supports many discrete mappers // such as NROM, AOROM, BNROM, CNROM, UxROM, UxROM variant #180 // written for Xilinx 9500XL series CPLD XC9536XL // // mapper design by: Tepples // verilog code by: infiniteneslives (paul@InfiniteNesLives.com) // Created: 6 Oct 2012 // Modified: 27 Oct 2012 // // Description: Designed to support 32KB of CHR-RAM, and 2MB PRG-ROM // see nesdev wiki for details: // http://wiki.nesdev.org/w/index.php/User:Tepples/Multi-discrete_mapper // // Modifications: // 10/6/12: Corrected prg bank switching 27/36Mcells (75%), 25/34 pins. // Reduced mirror[0] freeing 1 Mcell (26/36 73%) // Corrected fixed banks for both UxROM versions (26/36 73%) // // 10/27/12: Fixed several bugs, and tested to Tepples' Action53 interactive // mapper behavior test of 21Oct12. Everything appears operational at // this point. 29/36Mcells with 2MB and 8KB WRAM. // // 10/28/12: Corrected fix bank behavior, now fixes to current bank based // on outer_bank and PRG A14 value. No change in logic consumption. // Script output of mapper behavior test of 21Oct12 matches for 512KB ROM. // // Options: // 8KB WRAM: control available at the cost of 2 Mcells and // 2 pins for WRAM /CE and /WE. Leaving 27/34 pins used. // 1MB PRG-ROM: shaving off PRG ROM A20 saves 1Mcell and 1pin. // note: Hardwiring WRAM R/W and PRG A13 saves 1Mcell of logic each. // // Possible features with remaining logic: // Upto 32KB of WRAM and/or finer CHR bankswitching. // //-------------------------------------------------------------------------------- module action53 ( input m2, //clock input negedge triggered input prg_rw, //PRG R/W signal from NES input prg_ce, //PRG /CE signal from NES input [7:0] data, //PRG Data bus input input [14:12] prg_addr, //PRG A14-12 input input [11:10] chr_addr, //CHR A11-10 input for mirroring output reg[20:13] pa, //PRG ROM A20-13 outputs output reg[14:13] ca, //CHR RAM A14-13 outputs output reg p_ce, //PRG-ROM /CE signal output output reg ciram_a10, //CIRAM A10 output output reg w_ce_n, //WRAM /CE signal output output reg w_we //WRAM /WE signal output ); wire write_reg_sel, write_reg_val; //active high when writing to $5000->reg_sel, $8000->reg_val assign write_reg_sel = (prg_addr[14] & ~prg_addr[13] & prg_addr[12] & m2 & prg_ce & ~prg_rw); assign write_reg_val = (~prg_ce & ~prg_rw); reg [1:0] reg_sel; //register select S: supervisor=1/user=0 (D7), R: register select (D0) //In a multicart, registers $00 and $01 change the bank within a game, and registers $80 and $81 //remain constant throughout a given game's execution. //$00 CHR bank: used for CNROM, and one screen mirroring reg [1:0] chr_bank; //D1-0 set CHR RAM A14-13 //$01 Inner bank: prg bank for A/B/UxROM etc. reg [3:0] prg_inner_bank; //D4-0 set PRG ROM A14/15 and up for single game in game use //$80 Mode: used by multicart supervisor software reg [1:0] prg_size; //D5-4 0: 32KB, 1: 64KB, 2:128KB, 3:256KB reg [1:0] prg_mode; //D3-2 0,1: current 32KB @ $8000, 2: UNROM #180, 3: UNROM standard reg [1:0] mirror; //D1-0 0: 1scn lower, 1: 1scn upper, 2: vert, 3: horiz //$81 Outer bank: sets the upper PRG ROM bits to select current game reg [5:0] prg_outer_bank; //sets PRG ROM A15-20 //REGISTER SELECT: chooses which of the above registers is written to always @ (negedge write_reg_sel) begin reg_sel[1] <= data[7]; reg_sel[0] <= data[0]; end //REGISTER VALUE WRITING always @ (negedge write_reg_val) begin case (reg_sel) 0: chr_bank <= data[1:0]; 1: prg_inner_bank <= data[3:0]; 2: {prg_size, prg_mode, mirror[1]} <= data[5:1]; 3: prg_outer_bank <= data[5:0]; endcase if (reg_sel[1] == 0 & mirror[1] == 0) begin //$0x registers while in mirror mode 0 & 1 only mirror[0] <= data[4]; end else if (reg_sel == 2) begin //$80 register mirror[0] <= data[0]; end end //OUTPUTS combinational logic always @ (m2, chr_bank, prg_ce, prg_rw, prg_inner_bank, prg_size, prg_mode, mirror, prg_outer_bank, chr_addr, prg_addr) begin //fix to 16KB PRG ROM banks pa[13] = prg_addr[13]; //wram control if ((prg_addr[14:13] == 3) & m2 & prg_ce) w_ce_n = 0; //enabled else w_ce_n = 1; //disabled //wram write control w_we = prg_rw; //prevent bus conflicts for writes to $8000-FFFF if (prg_ce == 0 & prg_rw == 1) p_ce = 0; //enabled else p_ce = 1; //disabled //mirroring case (mirror) 0: ciram_a10 = mirror[0]; 1: ciram_a10 = mirror[0]; 2: ciram_a10 = chr_addr[10]; //vert 3: ciram_a10 = chr_addr[11]; //horiz endcase //chr bankswitching ca = chr_bank; //prg bankswitching pa[20:18] = prg_outer_bank[5:3]; //always controlled directly (independent of prg_mode) //prg bank selecting must control PRG ROM A17-14 if (prg_mode[1] == 0) //modes 0 and 1 NROM, A/BNROM 32KB banks begin pa[14] = prg_addr[14]; //32KB banks //32KB NROM if (prg_size == 0) pa[17:15] = prg_outer_bank[2:0]; //set to 32KB //64KB A/BNROM else if (prg_size[1] == 0) begin pa[17:16] = prg_outer_bank[2:1]; //set to 64KB pa[15] = prg_inner_bank[0]; end //128KB A/BNROM else if (prg_size == 2) begin pa[17] = prg_outer_bank[2]; //set to 128KB pa[16:15] = prg_inner_bank[1:0]; end //256KB A/BNROM else pa[17:15] = prg_inner_bank[2:0]; end else if (prg_mode == 2) //mode 2 UNROM #180 variant first 16KB bank fixed to first bank begin //32KB if (prg_size == 0) begin pa[17:15] = prg_outer_bank[2:0]; //set to 32KB if (prg_addr[14] == 1) //$C000-FFFF pa[14] = prg_inner_bank[0]; else //first bank fixed to first bank pa[14] = 1'b0; end //64KB else if (prg_size == 1) begin pa[17:16] = prg_outer_bank[2:1]; //set to 64KB if (prg_addr[14] == 1) //$C000-FFFF pa[15:14] = prg_inner_bank[1:0]; else //first bank fixed to first bank pa[15:14] = {prg_outer_bank[0], 1'b0}; end //128KB else if (prg_size == 2) begin pa[17] = prg_outer_bank[2]; //set to 128KB if (prg_addr[14] == 1) //$C000-FFFF pa[16:14] = prg_inner_bank[2:0]; else //first bank fixed to first bank pa[16:14] = {prg_outer_bank[1:0], 1'b0}; end //256KB else begin if (prg_addr[14] == 1) //$C000-FFFF pa[17:14] = prg_inner_bank[3:0]; else //first bank fixed to first bank pa[17:14] = {prg_outer_bank[2:0], 1'b0}; end end else // mode 3 standard UNROM 16KB banks last fixed begin //32KB if (prg_size == 0) begin pa[17:15] = prg_outer_bank[2:0]; //set to 32KB if (prg_addr[14] == 0) //$8000-BFFF pa[14] = prg_inner_bank[0]; else //last bank fixed to last bank pa[14] = 1'b1; end //64KB else if (prg_size == 1) begin pa[17:16] = prg_outer_bank[2:1]; //set to 64KB if (prg_addr[14] == 0) //$8000-BFFF pa[15:14] = prg_inner_bank[1:0]; else //last bank fixed to last bank pa[15:14] = {prg_outer_bank[0], 1'b1}; end //128KB else if (prg_size == 2) begin pa[17] = prg_outer_bank[2]; //set to 128KB if (prg_addr[14] == 0) //$8000-BFFF pa[16:14] = prg_inner_bank[2:0]; else //last bank fixed to last bank pa[16:14] = {prg_outer_bank[1:0], 1'b1}; end //256KB else begin if (prg_addr[14] == 0) //$8000-BFFF pa[17:14] = prg_inner_bank[3:0]; else //last bank fixed to last bank pa[17:14] = {prg_outer_bank[2:0], 1'b1}; end end end endmodule
kevtris
The following code was written by Kevin Horton for his FPGA NES and forms the basis of thefox's PowerPak mapper:
// "Action 53" mapper by tepples // rendered into verilog by k.horton // 11022012 // V4 now with syntax errors fixed! // module action53 ( C_A, C_D, C_WR, CLK0, RST, P_A, // inputs a53prg, a53chr, a53mir // outputs ); input wire [15:0] C_A; // NES A0-15 (only A12-15 used) input wire [7:0] C_D; // NES D0-7 input wire C_WR; // NES /WR signal input wire CLK0; // NES M2 signal input wire RST; // NES reset signal input wire [13:0] P_A; // PPU A0-13 (only A10/11 used) output reg [6:0] a53prg; // output PRG ROM (A14-A20 on ROM) output reg [1:0] a53chr; // output CHR RAM (A13-A14 on RAM) output reg a53mir; // CIRAM A10 reg [3:0] inner; // "inner" bank at 01h reg [5:0] mode; // mode register at 80h reg [5:0] outer; // "outer" bank at 81h reg [1:0] selreg; // selector register always @ (posedge CLK0) begin if ((C_A[15:12] == 4'h5) & C_WR) selreg <= {C_D[7], C_D[0]}; // select register if (RST) begin mode[5:2] <= 0; // NROM mode, 32K mode outer[5:0] <= 6'h3f; // last bank end else if (C_A[15] & C_WR) begin case (selreg) 2'h0: {mode[0], a53chr} <= {((mode[1]) ? mode[0] : C_D[4]), C_D[1:0]}; // CHR RAM bank 2'h1: {mode[0], inner} <= {((mode[1]) ? mode[0] : C_D[4]), C_D[3:0]}; // "inner" bank 2'h2: {mode} <= {C_D[5:0]}; // mode register 2'h3: {outer} <= {C_D[5:0]}; // "outer" bank endcase end end always begin // mirroring mode casex(mode[1:0]) 2'b0x : a53mir <= {mode[0]}; // 1 screen lower 2'b10 : a53mir <= {P_A[10]}; // vertical 2'b11 : a53mir <= {P_A[11]}; // horizontal endcase // PRG ROM bank size select casex({mode[5:2], C_A[14]}) 5'b00_0x_x : a53prg <= {outer[5:0], C_A[14]}; // 32K banks, (B)NROM mode 5'b01_0x_x : a53prg <= {outer[5:1], inner[0], C_A[14]}; // 64K banks, (B)NROM mode 5'b10_0x_x : a53prg <= {outer[5:2], inner[1:0], C_A[14]}; // 128K banks, (B)NROM mode 5'b11_0x_x : a53prg <= {outer[5:3], inner[2:0], C_A[14]}; // 256K banks, (B)NROM mode 5'b00_10_1, 5'b00_11_0 : a53prg <= {outer[5:0], inner[0]}; // 32K banks, UNROM mode 5'b01_10_1, 5'b01_11_0 : a53prg <= {outer[5:1], inner[1:0]}; // 64K banks, UNROM mode 5'b10_10_1, 5'b10_11_0 : a53prg <= {outer[5:2], inner[2:0]}; // 128K banks, UNROM mode 5'b11_10_1, 5'b11_11_0 : a53prg <= {outer[5:3], inner[3:0]}; // 256K banks, UNROM mode default : a53prg <= {outer[5:0], C_A[14]}; // 16K fixed bank endcase end endmodule