// EC533: Programmable Logic System Design
// Fall 2000
// Doering (Ed.Doering@Rose-Hulman.Edu)
//
// Testbench for 8031template.v

module Template_8031_SRAM_FPGA__testbench;

/* -----------------------------------------------------------------------------
	Declare identifiers
----------------------------------------------------------------------------- */

reg	I$_Reset;
reg	I$8031_to_FPGA_only$ALE;
reg	I$8031_to_FPGA_only$_PSEN;
reg	I$8031_to_FPGA_only$_RD;
reg	I$8031_to_FPGA_and_SRAM$_WR;
reg	[7:0]	I$8031_to_FPGA_and_SRAM$AddressHigh;
reg	I$Oscillator_to_FPGA$Clock;

wire	[7:0]	IO$8031_FPGA_SRAM$Data;

wire	[6:0]	O$LED;
wire	O$FPGA_to_8031$RST;
wire	O$FPGA_to_8031$XTAL1;
wire	O$FPGA_to_SRAM$_OE;
wire	O$FPGA_to_SRAM$_CE;
wire	[7:0]	O$FPGA_to_SRAM$AddressLow;

reg	r$DataBusIsOutput;
reg	[7:0]	r$DataBus;

reg	[7:0]	r$SRAM [0:32767];


/* -----------------------------------------------------------------------------
	Instantiate the DUT
----------------------------------------------------------------------------- */

Template_8031_SRAM_FPGA DUT (

	// User input/output signals for FPGA
	.I$_Reset			( I$_Reset ),
	.O$LED				( O$LED ),

	// From 8031 to FPGA only
	.I$8031_to_FPGA_only$ALE	( I$8031_to_FPGA_only$ALE ),
	.I$8031_to_FPGA_only$_PSEN	( I$8031_to_FPGA_only$_PSEN ),
	.I$8031_to_FPGA_only$_RD	( I$8031_to_FPGA_only$_RD ),

	// From 8031 to FPGA and SRAM
	.I$8031_to_FPGA_and_SRAM$_WR	( I$8031_to_FPGA_and_SRAM$_WR ),
	.I$8031_to_FPGA_and_SRAM$AddressHigh	( I$8031_to_FPGA_and_SRAM$AddressHigh ),
	
	// Shared bus between 8031, FPGA, and SRAM
	.IO$8031_FPGA_SRAM$Data		( IO$8031_FPGA_SRAM$Data ),

	// From FPGA to 8031
	.O$FPGA_to_8031$RST		( O$FPGA_to_8031$RST ),
	.O$FPGA_to_8031$XTAL1		( O$FPGA_to_8031$XTAL1 ),
	
	// From FPGA to SRAM
	.O$FPGA_to_SRAM$_OE		( O$FPGA_to_SRAM$_OE ),
	.O$FPGA_to_SRAM$_CE		( O$FPGA_to_SRAM$_CE ),
	.O$FPGA_to_SRAM$AddressLow	( O$FPGA_to_SRAM$AddressLow ),
	
	// From oscillator to FPGA
	.I$Oscillator_to_FPGA$Clock	( I$Oscillator_to_FPGA$Clock )
);	


/* -----------------------------------------------------------------------------
	Define test stimulus
----------------------------------------------------------------------------- */

parameter Tcp = 10;	// Clock period

initial begin
	I$Oscillator_to_FPGA$Clock = 0;
	r$DataBusIsOutput = 0;
	I$8031_to_FPGA_only$ALE = 0;
	I$8031_to_FPGA_only$_PSEN = 1;
	I$8031_to_FPGA_and_SRAM$_WR = 1;
	I$8031_to_FPGA_only$_RD = 1;
	I$_Reset = 0;
	
	// Take out of reset
#(2*Tcp)
	I$_Reset = 1;

	// Program fetch cycle
	Program_Fetch_Cycle(16'h1234);
	Data_Read_Cycle(16'h3009);
	Program_Fetch_Cycle(16'h4321);
	Data_Read_Cycle(16'h8CFE);
	Data_Read_Cycle(16'h9000);
	Data_Write_Cycle(16'h9000,8'h37);
	Data_Write_Cycle(16'hA000,8'hFA);
	Data_Write_Cycle(16'hA001,8'hCE);
	Data_Read_Cycle(16'h83BC);
	Data_Write_Cycle(16'h83BC,8'h59);
	Data_Read_Cycle(16'h83BC);
	Data_Read_Cycle(16'hB000);
	Data_Read_Cycle(16'hB001);
	
	// All done!
#(4*Tcp)
	$finish;
end

// Master clock
always #(Tcp/2) I$Oscillator_to_FPGA$Clock = ~I$Oscillator_to_FPGA$Clock;

// Tri-stateable driver for data bus (emulates 8031 data bus port and
// SRAM data bus port)
assign IO$8031_FPGA_SRAM$Data = (r$DataBusIsOutput) ? r$DataBus :
	(!O$FPGA_to_SRAM$_CE & !O$FPGA_to_SRAM$_OE) ?
	r$SRAM[{I$8031_to_FPGA_and_SRAM$AddressHigh[6:0],
	O$FPGA_to_SRAM$AddressLow}] : 8'hzz;

// Initialize selected portions of the SRAM emulator
initial begin
	r$SRAM[15'h1234] = 8'hED;
	r$SRAM[15'h3009] = 8'hC2;
end

// Task to emulate an 8031 program fetch cycle
task Program_Fetch_Cycle;
	input [15:0] Address;
	
	begin
		I$8031_to_FPGA_only$ALE = 1;
		I$8031_to_FPGA_only$_PSEN = 1;

	#(1*Tcp)	
		I$8031_to_FPGA_and_SRAM$AddressHigh = Address[15:8];
		r$DataBus = Address[7:0];
		r$DataBusIsOutput = 1;
	
	#(1*Tcp)	
		I$8031_to_FPGA_only$ALE = 0;

	#(1*Tcp)	
		I$8031_to_FPGA_only$_PSEN = 0;
		r$DataBusIsOutput = 0;

	#(3*Tcp)
		;	
	
	end
endtask

// Task to emulate an 8031 data read cycle
task Data_Read_Cycle;
	input [15:0] Address;
	
	begin
		I$8031_to_FPGA_only$ALE = 1;
		I$8031_to_FPGA_only$_PSEN = 1;
		I$8031_to_FPGA_only$_RD = 1;	

	#(1*Tcp)	
		I$8031_to_FPGA_and_SRAM$AddressHigh = Address[15:8];
		r$DataBus = Address[7:0];
		r$DataBusIsOutput = 1;
	
	#(1*Tcp)	
		I$8031_to_FPGA_only$ALE = 0;

	#(1*Tcp)	
		r$DataBusIsOutput = 0;

	#(2*Tcp)
		I$8031_to_FPGA_only$_RD = 0;	
	
	#(6*Tcp)
		I$8031_to_FPGA_only$_RD = 1;	

	#(1*Tcp)
		;	
	end
endtask

// Task to emulate an 8031 data write cycle
task Data_Write_Cycle;
	input [15:0] Address;
	input [7:0] Data;
	
	begin
		I$8031_to_FPGA_only$ALE = 1;
		I$8031_to_FPGA_only$_PSEN = 1;
		I$8031_to_FPGA_and_SRAM$_WR = 1;	

	#(1*Tcp)	
		I$8031_to_FPGA_and_SRAM$AddressHigh = Address[15:8];
		r$DataBus = Address[7:0];
		r$DataBusIsOutput = 1;
	
	#(1*Tcp)	
		I$8031_to_FPGA_only$ALE = 0;

	#(1*Tcp)	
		r$DataBus = Data;

	#(2*Tcp)
		I$8031_to_FPGA_and_SRAM$_WR = 0;	
	
	#(6*Tcp)
		I$8031_to_FPGA_and_SRAM$_WR = 1;	

	#(1*Tcp)
		;	
	end
endtask

endmodule