Action 53 mapper/Verilog
From NESdev Wiki
Jump to navigationJump to search
//-------------------------------------------------------------------------------- // Tepples' 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 // // verilog code by: infiniteneslives (paul@InfiniteNesLives.com) // Created: 6 Oct 2012 // Modified: 6 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%) // // 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. // // Possible features with remaining logic: // Upto 32KB of WRAM and/or finer CHR bankswitching. // // NOTE: BEWARE, This implementation is UNTESETED! //-------------------------------------------------------------------------------- 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 output reg[20:14] pa, //PRG ROM A20-14 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 // output reg debug //debug pin 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 standard, 3: UNROM #180 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 //if (reg_sel[1] == 0) // M <= data[4]; //this is written to for both $0x registers if (reg_sel[1] == 0 & mirror[1] == 0) //$0x registers while in mirror mode 0 & 1 only mirror[0] <= data[4]; else if (reg_sel == 2) //$80 register mirror[0] <= data[0]; 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]; //2: {prg_size, prg_mode, mirror} <= data[5:0]; 3: prg_outer_bank <= data[5:0]; endcase 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 //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 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] = 2'b11; 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] = 3'b111; 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] = 4'b1111; end end else //mode 3 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] = 2'b00; 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] = 3'b000; 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] = 4'b0000; end end end endmodule