`timescale 1ns/1ns

module msp430_bfm (
	input		clock_i,
	inout [7:0]	ad_io,
	output reg	reset_n_o,
	output reg	as_n_o,
	output reg	rd_n_o,
	output reg	wr_n_o
);	

reg  [7:0]	outgoing_data; 
wire [7:0]	incoming_data;
reg			drive_bus;	  
integer		count;	
integer		errors;

task delay;
input [7:0] delay_in_clocks;
begin
	while (delay_in_clocks > 0) 
		begin									  
			@(posedge clock_i);
			delay_in_clocks = delay_in_clocks - 1;	
		end
end
endtask
					
task reset;
begin  	
	errors = 0;
	as_n_o <= 1'b1;
	rd_n_o <= 1'b1;
	wr_n_o <= 1'b1;	
  	reset_n_o <= 1'b0;
	delay(8'h10);
  	reset_n_o = 1'b1;					
end							
endtask				 

task float_dwarf_bus;
begin  
	drive_bus = 1'b0;
	@(posedge clock_i);	
	@(posedge clock_i);
end
endtask	

task drive_dwarf_bus;
begin  
	drive_bus = 1'b1;
	@(posedge clock_i);	
	@(posedge clock_i);
end
endtask

task set_dwarf_address;
  input [7:0] address;  		// local address
begin  
	outgoing_data = address;
	drive_dwarf_bus;
	as_n_o = 1'b0;
	@(posedge clock_i);	
	@(posedge clock_i);		
end
endtask			 

task refresh_dwarf_address;
  input [7:0] address;  		// local address
begin  
	outgoing_data = address; 
	drive_dwarf_bus;
	as_n_o = 1'b0;
	@(posedge clock_i);	
	@(posedge clock_i);		
end
endtask	 

task freeze_dwarf_address;
begin  
	as_n_o = 1'b1;
	@(posedge clock_i);	
	@(posedge clock_i);		
end
endtask

task read_dwarf_next;
begin	 
	rd_n_o = 1'b0;
	@(posedge clock_i);
	@(posedge clock_i);
	rd_n_o = 1'b1;
	@(posedge clock_i);
	@(posedge clock_i);
end 
endtask

task read_dwarf_last;
begin	 
	rd_n_o = 1'b0;
	@(posedge clock_i);
	@(posedge clock_i);
	rd_n_o = 1'b1; 
	as_n_o = 1'b1;
	@(posedge clock_i);
	@(posedge clock_i);
end 
endtask   

task read_dwarf_first;	
	input [7:0] read_address;
begin	   
	set_dwarf_address(read_address);
	float_dwarf_bus;
	read_dwarf_next;
end 
endtask					 

task read_dwarf;	
	input [7:0] read_address;
begin	   
	set_dwarf_address(read_address);
	float_dwarf_bus;
	read_dwarf_last;
end 
endtask				

task read_dwarf_and_check;	
	input [7:0] read_address;  
	input [7:0] data_expected;
begin	   
	set_dwarf_address(read_address);
	float_dwarf_bus;
	rd_n_o = 1'b0;
	@(posedge clock_i);
	@(posedge clock_i);
	if (incoming_data != data_expected)
		begin			  
			errors = errors + 1;   	
			$display("Dwarf Bus Read Error, expected %x, obtained %x at time %d", 
				data_expected, incoming_data, $time);
		end
	rd_n_o = 1'b1; 
	as_n_o = 1'b1;
	@(posedge clock_i);
	@(posedge clock_i);
end 
endtask

task write_dwarf_next;
  input [7:0] data;  // local write data
begin	
	outgoing_data = data; 
	@(posedge clock_i);	
	@(posedge clock_i);
	wr_n_o = 1'b0;
	@(posedge clock_i);
	@(posedge clock_i);
	wr_n_o = 1'b1;
	@(posedge clock_i);
	@(posedge clock_i);
end 
endtask // write	   

task write_dwarf_last;
  input [7:0] data;  // local write data
begin
	outgoing_data = data; 
	@(posedge clock_i);	
	@(posedge clock_i);
	wr_n_o = 1'b0;
	@(posedge clock_i);
	@(posedge clock_i);
	wr_n_o = 1'b1;	   
	as_n_o = 1'b1;
	@(posedge clock_i);
	@(posedge clock_i);
end 
endtask // write	  

task write_dwarf_first;
	input [7:0] write_address;
	input [7:0] data_to_write;
begin
	set_dwarf_address(write_address); 
	write_dwarf_next(data_to_write);
end 
endtask

task write_dwarf;
	input [7:0] write_address;
	input [7:0] data_to_write;
begin
	set_dwarf_address(write_address); 
	write_dwarf_last(data_to_write);
end 
endtask

task idle;
integer i;
begin
	as_n_o = 1'b1;
	rd_n_o = 1'b1;
	wr_n_o = 1'b1;
	for(i=0; i<=10; i=i+1)
    	@(posedge clock_i);
end
endtask // idle	 

assign ad_io = (drive_bus) ? outgoing_data : 8'bz;
assign incoming_data = ad_io;

endmodule
