Action 53 mapper/Verilog: Difference between revisions
From NESdev Wiki
Jump to navigationJump to search
(split from User:Tepples/Multi-discrete mapper because it was getting long) |
(several bug fixes and notes added/modified post test28.nes of 21Oct12) |
||
Line 1: | Line 1: | ||
<pre> | <pre> | ||
//-------------------------------------------------------------------------------- | //-------------------------------------------------------------------------------- | ||
// | // INL-ROM Action53 Multi-discrete mapper | ||
// Designed for use with a multicart that supports many discrete mappers | // Designed for use with a multicart that supports many discrete mappers | ||
// such as NROM, AOROM, BNROM, CNROM, UxROM, UxROM variant #180 | // such as NROM, AOROM, BNROM, CNROM, UxROM, UxROM variant #180 | ||
Line 8: | Line 8: | ||
// verilog code by: infiniteneslives (paul@InfiniteNesLives.com) | // verilog code by: infiniteneslives (paul@InfiniteNesLives.com) | ||
// Created: 6 Oct 2012 | // Created: 6 Oct 2012 | ||
// Modified: | // Modified: 27 Oct 2012 | ||
// | // | ||
// Description: Designed to support 32KB of CHR-RAM, and 2MB PRG-ROM | // Description: Designed to support 32KB of CHR-RAM, and 2MB PRG-ROM | ||
Line 18: | Line 18: | ||
// Reduced mirror[0] freeing 1 Mcell (26/36 73%) | // Reduced mirror[0] freeing 1 Mcell (26/36 73%) | ||
// Corrected fixed banks for both UxROM versions (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. | |||
// | // | ||
// Options: | // Options: | ||
Line 23: | Line 27: | ||
// 2 pins for WRAM /CE and /WE. Leaving 27/34 pins used. | // 2 pins for WRAM /CE and /WE. Leaving 27/34 pins used. | ||
// 1MB PRG-ROM: shaving off PRG ROM A20 saves 1Mcell and 1pin. | // 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: | // Possible features with remaining logic: | ||
// Upto 32KB of WRAM and/or finer CHR bankswitching. | // Upto 32KB of WRAM and/or finer CHR bankswitching. | ||
// | // | ||
//-------------------------------------------------------------------------------- | //-------------------------------------------------------------------------------- | ||
module action53 ( | module action53 ( | ||
Line 37: | Line 40: | ||
input [7:0] data, //PRG Data bus input | input [7:0] data, //PRG Data bus input | ||
input [14:12] prg_addr, //PRG A14-12 input | input [14:12] prg_addr, //PRG A14-12 input | ||
input [11:10] chr_addr, //CHR A11-10 input | input [11:10] chr_addr, //CHR A11-10 input for mirroring | ||
output reg[20: | output reg[20:13] pa, //PRG ROM A20-14 outputs | ||
output reg[14:13] ca, //CHR RAM A14-13 outputs | output reg[14:13] ca, //CHR RAM A14-13 outputs | ||
output reg p_ce, //PRG-ROM /CE signal output | output reg p_ce, //PRG-ROM /CE signal output | ||
output reg ciram_a10, //CIRAM A10 output | output reg ciram_a10, //CIRAM A10 output | ||
output reg w_ce_n, //WRAM /CE signal output | output reg w_ce_n, //WRAM /CE signal output | ||
output reg w_we //WRAM /WE signal | output reg w_we //WRAM /WE signal output | ||
); | ); | ||
Line 51: | Line 53: | ||
//active high when writing to $5000->reg_sel, $8000->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_sel = (prg_addr[14] & ~prg_addr[13] & prg_addr[12] & m2 & prg_ce & ~prg_rw); | ||
assign write_reg_val = (~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) | reg [1:0] reg_sel; //register select S: supervisor=1/user=0 (D7), R: register select (D0) | ||
Line 65: | Line 67: | ||
//$80 Mode: used by multicart supervisor software | //$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_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 | 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 | 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 | //$81 Outer bank: sets the upper PRG ROM bits to select current game | ||
reg [5:0] prg_outer_bank; //sets PRG ROM A15-20 | reg [5:0] prg_outer_bank; //sets PRG ROM A15-20 | ||
//REGISTER SELECT: chooses which of the above registers is written to | //REGISTER SELECT: chooses which of the above registers is written to | ||
Line 81: | Line 85: | ||
always @ (negedge write_reg_val) | always @ (negedge write_reg_val) | ||
begin | 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) | if (reg_sel[1] == 0 & mirror[1] == 0) | ||
begin | |||
//$0x registers while in mirror mode 0 & 1 only | //$0x registers while in mirror mode 0 & 1 only | ||
mirror[0] <= data[4]; | mirror[0] <= data[4]; | ||
else if (reg_sel == 2) | end | ||
else if (reg_sel == 2) | |||
begin | |||
//$80 register | //$80 register | ||
mirror[0] <= data[0]; | mirror[0] <= data[0]; | ||
end | |||
end | end | ||
Line 105: | Line 111: | ||
always @ (m2, chr_bank, prg_ce, prg_rw, prg_inner_bank, prg_size, prg_mode, mirror, prg_outer_bank, chr_addr, prg_addr) | always @ (m2, chr_bank, prg_ce, prg_rw, prg_inner_bank, prg_size, prg_mode, mirror, prg_outer_bank, chr_addr, prg_addr) | ||
begin | begin | ||
//fix to 16KB PRG ROM banks | |||
pa[13] = prg_addr[13]; | |||
//wram control | //wram control | ||
Line 114: | Line 123: | ||
//wram write control | //wram write control | ||
w_we = prg_rw; | w_we = prg_rw; | ||
//prevent bus conflicts for writes to $8000-FFFF | //prevent bus conflicts for writes to $8000-FFFF | ||
Line 164: | Line 174: | ||
end | end | ||
else if (prg_mode == 2) // mode 2 | else if (prg_mode == 2) //mode 2 UNROM #180 variant first 16KB bank fixed to first bank | ||
begin | begin | ||
//32KB | //32KB | ||
Line 171: | Line 181: | ||
pa[17:15] = prg_outer_bank[2:0]; //set to 32KB | pa[17:15] = prg_outer_bank[2:0]; //set to 32KB | ||
if (prg_addr[14] == | if (prg_addr[14] == 1) //$C000-FFFF | ||
pa[14] = prg_inner_bank[0]; | pa[14] = prg_inner_bank[0]; | ||
else | else | ||
// | //first bank fixed to first bank | ||
pa[14] = 1' | pa[14] = 1'b0; | ||
end | end | ||
Line 183: | Line 193: | ||
pa[17:16] = prg_outer_bank[2:1]; //set to 64KB | pa[17:16] = prg_outer_bank[2:1]; //set to 64KB | ||
if (prg_addr[14] == | if (prg_addr[14] == 1) //$C000-FFFF | ||
pa[15:14] = prg_inner_bank[1:0]; | pa[15:14] = prg_inner_bank[1:0]; | ||
else | else | ||
// | //first bank fixed to first bank | ||
pa[15:14] = 2' | pa[15:14] = 2'b00; | ||
end | end | ||
Line 195: | Line 205: | ||
pa[17] = prg_outer_bank[2]; //set to 128KB | pa[17] = prg_outer_bank[2]; //set to 128KB | ||
if (prg_addr[14] == | if (prg_addr[14] == 1) //$C000-FFFF | ||
pa[16:14] = prg_inner_bank[2:0]; | pa[16:14] = prg_inner_bank[2:0]; | ||
else | else | ||
// | //first bank fixed to first bank | ||
pa[16:14] = 3' | pa[16:14] = 3'b000; | ||
end | end | ||
Line 205: | Line 215: | ||
else | else | ||
begin | begin | ||
if (prg_addr[14] == | if (prg_addr[14] == 1) //$C000-FFFF | ||
pa[17:14] = prg_inner_bank[3:0]; | pa[17:14] = prg_inner_bank[3:0]; | ||
else | else | ||
// | //first bank fixed to first bank | ||
pa[17:14] = 4' | pa[17:14] = 4'b0000; | ||
end | end | ||
end | end | ||
else //mode 3 UNROM | else // mode 3 standard UNROM 16KB banks last fixed | ||
begin | begin | ||
//32KB | //32KB | ||
Line 220: | Line 230: | ||
pa[17:15] = prg_outer_bank[2:0]; //set to 32KB | pa[17:15] = prg_outer_bank[2:0]; //set to 32KB | ||
if (prg_addr[14] == | if (prg_addr[14] == 0) //$8000-BFFF | ||
pa[14] = prg_inner_bank[0]; | pa[14] = prg_inner_bank[0]; | ||
else | else | ||
// | //last bank fixed to last bank | ||
pa[14] = 1' | pa[14] = 1'b1; | ||
end | end | ||
Line 232: | Line 242: | ||
pa[17:16] = prg_outer_bank[2:1]; //set to 64KB | pa[17:16] = prg_outer_bank[2:1]; //set to 64KB | ||
if (prg_addr[14] == | if (prg_addr[14] == 0) //$8000-BFFF | ||
pa[15:14] = prg_inner_bank[1:0]; | pa[15:14] = prg_inner_bank[1:0]; | ||
else | else | ||
// | //last bank fixed to last bank | ||
pa[15:14] = 2' | pa[15:14] = 2'b11; | ||
end | end | ||
Line 244: | Line 254: | ||
pa[17] = prg_outer_bank[2]; //set to 128KB | pa[17] = prg_outer_bank[2]; //set to 128KB | ||
if (prg_addr[14] == | if (prg_addr[14] == 0) //$8000-BFFF | ||
pa[16:14] = prg_inner_bank[2:0]; | pa[16:14] = prg_inner_bank[2:0]; | ||
else | else | ||
// | //last bank fixed to last bank | ||
pa[16:14] = 3' | pa[16:14] = 3'b111; | ||
end | end | ||
Line 254: | Line 264: | ||
else | else | ||
begin | begin | ||
if (prg_addr[14] == | if (prg_addr[14] == 0) //$8000-BFFF | ||
pa[17:14] = prg_inner_bank[3:0]; | pa[17:14] = prg_inner_bank[3:0]; | ||
else | else | ||
// | //last bank fixed to last bank | ||
pa[17:14] = 4' | pa[17:14] = 4'b1111; | ||
end | end | ||
end | end | ||
Line 264: | Line 274: | ||
end | end | ||
endmodule | endmodule | ||
</pre> | </pre> |
Revision as of 23:21, 27 October 2012
//-------------------------------------------------------------------------------- // 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 // // 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. // // 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-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 ); 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] = 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 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] = 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 end endmodule