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>
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
// Tepples' Multi-discrete mapper
// 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: 6 Oct 2012  
// 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.
//
//
// NOTE:  BEWARE, This implementation is UNTESETED!
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------


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:14] pa, //PRG ROM A20-14 outputs
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
output  reg w_we //WRAM /WE signal output
// output reg debug //debug pin 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 standard, 3: UNROM #180
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
//if (reg_sel[1] == 0)
 
// M <= data[4]; //this is written to for both $0x registers
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
 
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
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 standard UNROM 16KB banks last fixed
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] == 0) //$8000-BFFF
if (prg_addr[14] == 1) //$C000-FFFF
pa[14] = prg_inner_bank[0];
pa[14] = prg_inner_bank[0];
else
else
//last bank fixed to last bank
//first bank fixed to first bank
pa[14] = 1'b1;
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] == 0) //$8000-BFFF
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
//last bank fixed to last bank
//first bank fixed to first bank
pa[15:14] = 2'b11;
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] == 0) //$8000-BFFF
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
//last bank fixed to last bank
//first bank fixed to first bank
pa[16:14] = 3'b111;
pa[16:14] = 3'b000;
end
end


Line 205: Line 215:
else  
else  
begin
begin
if (prg_addr[14] == 0) //$8000-BFFF
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
//last bank fixed to last bank
//first bank fixed to first bank
pa[17:14] = 4'b1111;
pa[17:14] = 4'b0000;
end
end
end
end
 
else //mode 3 UNROM #180 variant first 16KB bank fixed to first bank
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] == 1) //$C000-FFFF
if (prg_addr[14] == 0) //$8000-BFFF
pa[14] = prg_inner_bank[0];
pa[14] = prg_inner_bank[0];
else
else
//first bank fixed to first bank
//last bank fixed to last bank
pa[14] = 1'b0;
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] == 1) //$C000-FFFF
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
//first bank fixed to first bank
//last bank fixed to last bank
pa[15:14] = 2'b00;
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] == 1) //$C000-FFFF
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
//first bank fixed to first bank
//last bank fixed to last bank
pa[16:14] = 3'b000;
pa[16:14] = 3'b111;
end
end


Line 254: Line 264:
else  
else  
begin
begin
if (prg_addr[14] == 1) //$C000-FFFF
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
//first bank fixed to first bank
//last bank fixed to last bank
pa[17:14] = 4'b0000;
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