URL
https://opencores.org/ocsvn/ps2/ps2/trunk
Subversion Repositories ps2
Compare Revisions
- This comparison shows the changes necessary to convert path
/ps2/trunk/bench/verilog
- from Rev 33 to Rev 51
- ↔ Reverse comparison
Rev 33 → Rev 51
/ps2_test_bench.v
0,0 → 1,1670
////////////////////////////////////////////////////////////////////// |
//// //// |
//// ps2_test_bench.v //// |
//// //// |
//// This file is part of the "ps2" project //// |
//// http://www.opencores.org/cores/ps2/ //// |
//// //// |
//// Author(s): //// |
//// - mihad@opencores.org //// |
//// - Miha Dolenc //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.7 2003/10/03 10:16:50 primozs |
// support for configurable devider added |
// |
// Revision 1.6 2003/05/28 16:26:51 simons |
// Change the address width. |
// |
// Revision 1.5 2002/04/09 13:17:03 mihad |
// Mouse interface testcases added |
// |
// Revision 1.4 2002/02/20 16:35:34 mihad |
// Little/big endian changes continued |
// |
// Revision 1.3 2002/02/20 15:20:02 mihad |
// Little/big endian changes incorporated |
// |
// Revision 1.2 2002/02/18 18:08:31 mihad |
// One bug fixed |
// |
// Revision 1.1.1.1 2002/02/18 16:16:55 mihad |
// Initial project import - working |
// |
// |
|
`include "timescale.v" |
`include "ps2_testbench_defines.v" |
`include "ps2_defines.v" |
|
`define KBD_STATUS_REG 32'h64 |
`define KBD_CNTL_REG 32'h64 |
`define KBD_DATA_REG 32'h60 |
/* |
* controller commands |
*/ |
`define KBD_READ_MODE 32'h20_00_00_00 |
`define KBD_WRITE_MODE 32'h60_00_00_00 |
`define KBD_SELF_TEST 32'hAA_00_00_00 |
`define KBD_SELF_TEST2 32'hAB_00_00_00 |
`define KBD_CNTL_ENABLE 32'hAE_00_00_00 |
/* |
* keyboard commands |
*/ |
`define KBD_ENABLE 32'hF4_00_00_00 |
`define KBD_DISABLE 32'hF5_00_00_00 |
`define KBD_RESET 32'hFF_00_00_00 |
/* |
* keyboard replies |
*/ |
`define KBD_ACK 32'hFA |
`define KBD_POR 32'hAA |
/* |
* status register bits |
*/ |
`define KBD_OBF 32'h01 |
`define KBD_IBF 32'h02 |
`define KBD_GTO 32'h40 |
`define KBD_PERR 32'h80 |
/* |
* keyboard controller mode register bits |
*/ |
`define KBD_EKI 32'h01_00_00_00 |
`define KBD_SYS 32'h04_00_00_00 |
`define KBD_DMS 32'h20_00_00_00 |
`define KBD_KCC 32'h40_00_00_00 |
`define KBD_DISABLE_COMMAND 32'h10_00_00_00 |
`define AUX_OBUF_FULL 8'h20 /* output buffer (from device) full */ |
`define AUX_INTERRUPT_ON 32'h02_000000 /* enable controller interrupts */ |
|
`ifdef PS2_AUX |
`define AUX_ENABLE 32'ha8_000000 /* enable aux */ |
`define AUX_DISABLE 32'ha7_000000 /* disable aux */ |
`define AUX_MAGIC_WRITE 32'hd4_000000 /* value to send aux device data */ |
`define AUX_SET_SAMPLE 32'hf3_000000 /* set sample rate */ |
`define AUX_SET_RES 32'he8_000000 /* set resolution */ |
`define AUX_SET_SCALE21 32'he7_000000 /* set 2:1 scaling */ |
`define AUX_INTS_OFF 32'h65_000000 /* disable controller interrupts */ |
`define AUX_INTS_ON 32'h47_000000 /* enable controller interrupts */ |
`define AUX_ENABLE_DEV 32'hf4_000000 /* enable aux device */ |
`endif |
|
module ps2_test_bench() ; |
|
parameter [31:0] MAX_SEQUENCE_LENGTH = 10 ; |
wire kbd_clk_cable ; |
wire kbd_data_cable ; |
|
pullup(kbd_clk_cable) ; |
pullup(kbd_data_cable) ; |
|
`ifdef PS2_AUX |
pullup(aux_clk_cable) ; |
pullup(aux_data_cable) ; |
wire wb_intb ; |
reg stop_mouse_tests ; |
`endif |
|
reg wb_clock ; |
reg wb_reset ; |
|
wire [7:0] received_char ; |
wire char_valid ; |
|
reg error ; |
|
`ifdef XILINX |
assign glbl.GSR = wb_reset ; |
`endif |
ps2_keyboard_model i_ps2_keyboard_model |
( |
.kbd_clk_io (kbd_clk_cable), |
.kbd_data_io (kbd_data_cable), |
.last_char_received_o (received_char), |
.char_valid_o (char_valid) |
) ; |
|
`ifdef PS2_AUX |
wire [7:0] aux_received_char ; |
ps2_keyboard_model i_ps2_mouse_model |
( |
.kbd_clk_io (aux_clk_cable), |
.kbd_data_io (aux_data_cable), |
.last_char_received_o (aux_received_char), |
.char_valid_o (aux_char_valid) |
) ; |
`endif |
|
reg ok ; |
reg error1 ; |
|
reg ok_o; |
|
integer rem; |
integer wb_period; |
reg wb_rem; |
reg [15:0] wb_dev_data; |
|
|
integer watchdog_timer ; |
reg watchdog_reset ; |
reg watchdog_reset_previous ; |
|
reg [7:0] normal_scancode_set2_mem [0:`PS2_NUM_OF_NORMAL_SCANCODES - 1] ; |
reg [7:0] normal_scancode_set1_mem [0:`PS2_NUM_OF_NORMAL_SCANCODES - 1] ; |
reg [7:0] extended_scancode_set2_mem [0:`PS2_NUM_OF_EXTENDED_SCANCODES - 1] ; |
reg [7:0] extended_scancode_set1_mem [0:`PS2_NUM_OF_EXTENDED_SCANCODES - 1] ; |
|
`define WB_PERIOD (1/`WB_FREQ) |
initial |
begin |
|
|
$readmemh("../../../bench/data/normal_scancodes_set2.hex", normal_scancode_set2_mem) ; |
$readmemh("../../../bench/data/normal_scancodes_set1.hex", normal_scancode_set1_mem) ; |
$readmemh("../../../bench/data/extended_scancodes_set2.hex", extended_scancode_set2_mem) ; |
$readmemh("../../../bench/data/extended_scancodes_set1.hex", extended_scancode_set1_mem) ; |
|
|
wb_period =50; |
wb_rem = 1'b0; |
rem =0; |
|
error1 = 1'b0 ; |
|
watchdog_timer = 32'h1000_0000 ; |
watchdog_reset = 0 ; |
watchdog_reset_previous = 0 ; |
|
wb_clock = 1'b1 ; |
wb_reset = 1'b1 ; |
|
#100 ; |
|
repeat ( 10 ) |
@(posedge wb_clock) ; |
|
wb_reset <= 1'b0 ; |
|
repeat(6) |
|
begin |
@(posedge wb_clock) |
begin |
rem = 5000 % wb_period; |
|
if (rem > 0) |
begin |
wb_rem = 1'b1; |
|
end |
else |
begin |
wb_rem = 1'b0; |
|
end |
end |
|
begin |
devider_write(4'h8,5000/wb_period + wb_rem ,ok_o); |
|
|
@(posedge wb_clock) ; |
#1 initialize_controler ; |
|
test_scan_code_receiving ; |
|
`ifdef PS2_AUX |
fork |
begin |
`endif |
test_normal_scancodes ; |
|
test_extended_scancodes ; |
|
test_print_screen_and_pause_scancodes ; |
`ifdef PS2_AUX |
stop_mouse_tests = 1'b1 ; |
end |
begin |
stop_mouse_tests = 0 ; |
receive_mouse_movement ; |
end |
join |
`endif |
|
test_keyboard_inhibit ; |
wb_period = wb_period + 10 ; |
|
end |
end |
$display("\n\nstatus: Testbench done"); |
if ( error1 == 0 ) |
begin |
$display ("report (%h)", 32'hdeaddead ) ; |
$display ("exit (00000000)" ) ; |
end |
else |
begin |
$display ("report (%h)", 32'heeeeeeee ) ; |
$display ("exit (00000000)" ) ; |
end |
|
$finish(0); |
|
|
//$display("end simulation"); |
// |
end |
|
always |
#(wb_period/2.0) wb_clock = !wb_clock ; |
|
wire wb_cyc, |
wb_stb, |
wb_we, |
wb_ack, |
wb_rty, |
wb_int ; |
|
wire [3:0] wb_sel ; |
|
wire [31:0] wb_adr, wb_dat_m_s, wb_dat_s_m ; |
|
ps2_sim_top |
i_ps2_top |
( |
.wb_clk_i (wb_clock), |
.wb_rst_i (wb_reset), |
.wb_cyc_i (wb_cyc), |
.wb_stb_i (wb_stb), |
.wb_we_i (wb_we), |
.wb_sel_i (wb_sel), |
.wb_adr_i (wb_adr[3:0]), |
.wb_dat_i (wb_dat_m_s), |
.wb_dat_o (wb_dat_s_m), |
.wb_ack_o (wb_ack), |
|
.wb_int_o (wb_int), |
|
.ps2_kbd_clk_io (kbd_clk_cable), |
.ps2_kbd_data_io (kbd_data_cable) |
`ifdef PS2_AUX |
, |
.wb_intb_o(wb_intb), |
|
.ps2_aux_clk_io(aux_clk_cable), |
.ps2_aux_data_io(aux_data_cable) |
`endif |
) ; |
|
WB_MASTER_BEHAVIORAL i_wb_master |
( |
.CLK_I (wb_clock), |
.RST_I (wb_reset), |
.TAG_I (1'b0), |
.TAG_O (), |
.ACK_I (wb_ack), |
.ADR_O (wb_adr), |
.CYC_O (wb_cyc), |
.DAT_I (wb_dat_s_m), |
.DAT_O (wb_dat_m_s), |
.ERR_I (1'b0), |
.RTY_I (1'b0), |
.SEL_O (wb_sel), |
.STB_O (wb_stb), |
.WE_O (wb_we), |
.CAB_O () |
); |
|
always@(posedge wb_clock) |
begin |
if ( watchdog_timer === 0 ) |
begin |
$display("Warning! Simulation watchdog timer has expired!") ; |
watchdog_timer = 32'hFFFF_FFFF ; |
end |
else if ( watchdog_reset !== watchdog_reset_previous ) |
watchdog_timer = 32'hFFFF_FFFF ; |
|
watchdog_reset_previous = watchdog_reset ; |
|
end |
|
task initialize_controler ; |
reg [7:0] data ; |
reg status ; |
begin:main |
|
// simulate keyboard driver's behaviour |
data = `KBD_OBF ; |
status = 1 ; |
while ( data & `KBD_OBF ) |
begin |
read_status_reg(data, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
if ( data & `KBD_OBF ) |
begin |
read_data_reg(data, status) ; |
data = `KBD_OBF ; |
end |
|
if ( status !== 1 ) |
#1 disable main ; |
|
end |
|
kbd_write(`KBD_CNTL_REG, `KBD_SELF_TEST, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
// command sent - wait for commands output to be ready |
data = 0 ; |
while( !( data & `KBD_OBF ) ) |
begin |
read_status_reg(data, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
end |
|
read_data_reg( data, status ) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
if ( data !== 8'h55 ) |
begin |
$display("Error! Keyboard controler should respond to self test command with hard coded value 0x55! ") ; |
error1 = 1'b1 ; |
|
end |
|
// perform self test 2 |
kbd_write(`KBD_CNTL_REG, `KBD_SELF_TEST2, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
// command sent - wait for commands output to be ready |
data = 0 ; |
while( status && !( data & `KBD_OBF ) ) |
read_status_reg(data, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
read_data_reg( data, status ) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
if ( data !== 8'h00 ) |
begin |
$display("Error! Keyboard controler should respond to self test command 2 with hard coded value 0x00! ") ; |
error1 = 1'b1 ; |
|
end |
|
kbd_write(`KBD_CNTL_REG, `KBD_CNTL_ENABLE, status); |
|
if ( status !== 1 ) |
#1 disable main ; |
|
// send reset command to keyboard |
kbd_write(`KBD_DATA_REG, `KBD_RESET, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
fork |
begin |
// wait for keyboard to respond with acknowledge |
data = 0 ; |
while( status && !( data & `KBD_OBF ) ) |
read_status_reg(data, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
read_data_reg( data, status ) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
if ( data !== `KBD_ACK ) |
begin |
$display("Error! Expected character from keyboard was 0x%h, actualy received 0x%h!", `KBD_ACK, data ) ; |
error1 = 1'b1 ; |
|
end |
|
// wait for keyboard to respond with BAT status |
data = 0 ; |
while( status && !( data & `KBD_OBF ) ) |
read_status_reg(data, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
read_data_reg( data, status ) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
if ( data !== `KBD_POR ) |
begin |
$display("Error! Expected character from keyboard was 0x%h, actualy received 0x%h!", `KBD_POR, data ) ; |
error1 = 1'b1 ; |
|
end |
|
// send disable command to keyboard |
kbd_write(`KBD_DATA_REG, `KBD_DISABLE, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
// wait for keyboard to respond with acknowledge |
data = 0 ; |
while( status && !( data & `KBD_OBF ) ) |
read_status_reg(data, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
read_data_reg( data, status ) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
if ( data !== `KBD_ACK ) |
begin |
$display("Error! Expected character from keyboard was 0x%h, actualy received 0x%h!", `KBD_ACK, data ) ; |
error1 = 1'b1 ; |
|
end |
|
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, status); |
if ( status !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`KBD_DMS|`KBD_KCC, status); |
if ( status !== 1 ) |
#1 disable main ; |
|
// send disable command to keyboard |
kbd_write(`KBD_DATA_REG, `KBD_ENABLE, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
// wait for keyboard to respond with acknowledge |
data = 0 ; |
while( status && !( data & `KBD_OBF ) ) |
read_status_reg(data, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
read_data_reg( data, status ) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
if ( data !== `KBD_ACK ) |
begin |
$display("Error! Expected character from keyboard was 0x%h, actualy received 0x%h!", `KBD_ACK, data ) ; |
error1 = 1'b1 ; |
|
end |
|
// now check if command byte is as expected |
kbd_write(`KBD_CNTL_REG, `KBD_READ_MODE, status); |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 0 ; |
while( status && !( data & `KBD_OBF ) ) |
read_status_reg(data, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
read_data_reg(data, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
if ( ({data, 24'h0} & (`KBD_EKI|`KBD_SYS|`KBD_DMS|`KBD_KCC)) !== (`KBD_EKI|`KBD_SYS|`KBD_DMS|`KBD_KCC) ) |
begin |
$display("Error! Read command byte returned wrong value!") ; |
error1 = 1'b1 ; |
|
end |
end |
begin |
@(char_valid) ; |
if ( {received_char, 24'h0} !== `KBD_RESET ) |
begin |
$display("Error! Keyboard received invalid character/command") ; |
error1 = 1'b1 ; |
|
end |
|
i_ps2_keyboard_model.kbd_send_char |
( |
`KBD_ACK, |
ok, |
error |
) ; |
|
i_ps2_keyboard_model.kbd_send_char |
( |
`KBD_POR, |
ok, |
error |
) ; |
|
@(char_valid) ; |
if ( {received_char,24'h0} !== `KBD_DISABLE ) |
begin |
$display("Error! Keyboard received invalid character/command") ; |
error1 = 1'b1 ; |
|
end |
|
i_ps2_keyboard_model.kbd_send_char |
( |
`KBD_ACK, |
ok, |
error |
) ; |
|
@(char_valid) ; |
if ( {received_char,24'h0} !== `KBD_ENABLE ) |
begin |
$display("Error! Keyboard received invalid character/command") ; |
error1 = 1'b1 ; |
|
end |
|
i_ps2_keyboard_model.kbd_send_char |
( |
`KBD_ACK, |
ok, |
error |
) ; |
|
end |
join |
|
watchdog_reset = !watchdog_reset ; |
|
`ifdef PS2_AUX |
kbd_write(`KBD_CNTL_REG, `AUX_ENABLE, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
// simulate aux driver's behaviour |
data = 1 ; |
status = 1 ; |
|
kbd_write(`KBD_CNTL_REG, `AUX_MAGIC_WRITE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 1 ; |
|
kbd_write(`KBD_DATA_REG, `AUX_SET_SAMPLE, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
@(aux_char_valid) ; |
if ( {aux_received_char, 24'h000000} !== `AUX_SET_SAMPLE) |
begin |
$display("Time %t ", $time) ; |
$display("PS2 mouse didn't receive expected character! Expected %h, actual %h !", `AUX_SET_SAMPLE, aux_received_char ) ; |
end |
|
data = 1 ; |
status = 1 ; |
|
kbd_write(`KBD_CNTL_REG, `AUX_MAGIC_WRITE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 1 ; |
|
kbd_write(`KBD_DATA_REG, `AUX_SET_RES, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
|
@(aux_char_valid) ; |
if ( {aux_received_char, 24'h000000} !== `AUX_SET_RES ) |
begin |
$display("Time %t ", $time) ; |
$display("PS2 mouse didn't receive expected character! Expected %h, actual %h !", `AUX_SET_RES, aux_received_char ) ; |
end |
|
data = 1 ; |
status = 1 ; |
|
kbd_write(`KBD_CNTL_REG, `AUX_MAGIC_WRITE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 1 ; |
|
kbd_write(`KBD_DATA_REG, {8'd100, 24'h000000}, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
@(aux_char_valid) ; |
if ( aux_received_char !== 8'd100 ) |
begin |
$display("Time %t ", $time) ; |
$display("PS2 mouse didn't receive expected character! Expected %h, actual %h !", 100, aux_received_char ) ; |
end |
|
data = 1 ; |
status = 1 ; |
|
kbd_write(`KBD_CNTL_REG, `AUX_MAGIC_WRITE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 1 ; |
|
kbd_write(`KBD_DATA_REG, {8'd3, 24'h000000}, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
|
@(aux_char_valid) ; |
if ( aux_received_char !== 8'd3 ) |
begin |
$display("Time %t ", $time) ; |
$display("PS2 mouse didn't receive expected character! Expected %h, actual %h !", 3, aux_received_char ) ; |
end |
|
data = 1 ; |
status = 1 ; |
|
kbd_write(`KBD_CNTL_REG, `AUX_MAGIC_WRITE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 1 ; |
|
kbd_write(`KBD_DATA_REG, `AUX_SET_SCALE21, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
@(aux_char_valid) ; |
if ( {aux_received_char, 24'h000000} !== `AUX_SET_SCALE21) |
begin |
$display("Time %t ", $time) ; |
$display("PS2 mouse didn't receive expected character! Expected %h, actual %h !", `AUX_SET_SCALE21, aux_received_char ) ; |
end |
|
kbd_write(`KBD_CNTL_REG, `AUX_DISABLE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `AUX_INTS_OFF, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 1 ; |
|
kbd_write(`KBD_CNTL_REG, `AUX_ENABLE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_CNTL_REG, `AUX_MAGIC_WRITE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
data = 1 ; |
|
kbd_write(`KBD_DATA_REG, `AUX_ENABLE_DEV, status) ; |
|
if ( status !== 1 ) |
#1 disable main ; |
|
@(aux_char_valid) ; |
if ( {aux_received_char, 24'h000000} !== `AUX_ENABLE_DEV) |
begin |
$display("Time %t ", $time) ; |
$display("PS2 mouse didn't receive expected character! Expected %h, actual %h !", `AUX_ENABLE_DEV, aux_received_char ) ; |
end |
|
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `AUX_INTS_ON, status) ; |
if ( status !== 1 ) |
#1 disable main ; |
|
watchdog_reset = !watchdog_reset ; |
`endif |
|
end |
endtask // initialize_controler |
|
task read_data_reg ; |
output [7:0] return_byte_o ; |
output ok_o ; |
reg `READ_STIM_TYPE read_data ; |
reg `READ_RETURN_TYPE read_status ; |
reg `WB_TRANSFER_FLAGS flags ; |
reg in_use ; |
begin:main |
if ( in_use === 1 ) |
begin |
$display("Task read_data_reg re-entered! Time %t", $time) ; |
#1 disable main ; |
end |
else |
in_use = 1 ; |
|
ok_o = 1 ; |
flags`WB_TRANSFER_SIZE = 1 ; |
flags`WB_TRANSFER_AUTO_RTY = 0 ; |
flags`WB_TRANSFER_CAB = 0 ; |
flags`INIT_WAITS = 0 ; |
flags`SUBSEQ_WAITS = 0 ; |
|
read_data`READ_ADDRESS = `KBD_DATA_REG ; |
read_data`READ_SEL = 4'h8 ; |
|
read_status = 0 ; |
|
i_wb_master.wb_single_read( read_data, flags, read_status ) ; |
|
if ( read_status`CYC_ACK !== 1'b1 ) |
begin |
$display("Error! Keyboard controler didn't acknowledge single read access!") ; |
|
ok_o = 0 ; |
end |
else |
return_byte_o = read_status`READ_DATA ; |
|
in_use = 0 ; |
|
end |
endtask //read_data_reg |
|
task read_status_reg ; |
output [7:0] return_byte_o ; |
output ok_o ; |
reg `READ_STIM_TYPE read_data ; |
reg `READ_RETURN_TYPE read_status ; |
reg `WB_TRANSFER_FLAGS flags ; |
reg in_use ; |
begin:main |
if ( in_use === 1 ) |
begin |
$display("Task read_status_reg re-entered! Time %t !", $time) ; |
#1 disable main ; |
end |
else |
in_use = 1 ; |
|
ok_o = 1 ; |
flags`WB_TRANSFER_SIZE = 1 ; |
flags`WB_TRANSFER_AUTO_RTY = 0 ; |
flags`WB_TRANSFER_CAB = 0 ; |
flags`INIT_WAITS = 0 ; |
flags`SUBSEQ_WAITS = 0 ; |
|
read_data`READ_ADDRESS = `KBD_STATUS_REG ; |
read_data`READ_SEL = 4'h8 ; |
|
read_status = 0 ; |
|
i_wb_master.wb_single_read( read_data, flags, read_status ) ; |
|
if ( read_status`CYC_ACK !== 1'b1 ) |
begin |
$display("Error! Keyboard controler didn't acknowledge single read access!") ; |
error1 = 1'b1 ; |
|
ok_o = 0 ; |
end |
else |
return_byte_o = read_status`READ_DATA ; |
|
in_use = 0 ; |
end |
endtask // read_status_reg |
|
task kbd_write ; |
input [31:0] address_i ; |
input [31:0] data_i ; |
output ok_o ; |
|
reg `WRITE_STIM_TYPE write_data ; |
reg `WRITE_RETURN_TYPE write_status ; |
reg `WB_TRANSFER_FLAGS flags ; |
reg [7:0] kbd_status ; |
begin:main |
ok_o = 1 ; |
flags`WB_TRANSFER_SIZE = 1 ; |
flags`WB_TRANSFER_AUTO_RTY = 0 ; |
flags`WB_TRANSFER_CAB = 0 ; |
flags`INIT_WAITS = 0 ; |
flags`SUBSEQ_WAITS = 0 ; |
|
write_data`WRITE_ADDRESS = address_i ; |
write_data`WRITE_DATA = data_i ; |
write_data`WRITE_SEL = 4'h8 ; |
|
read_status_reg(kbd_status, ok_o) ; |
|
while( ok_o && ( kbd_status & `KBD_IBF )) |
begin |
read_status_reg(kbd_status, ok_o) ; |
end |
|
if ( ok_o !== 1 ) |
#1 disable main ; |
|
i_wb_master.wb_single_write( write_data, flags, write_status ) ; |
|
if ( write_status`CYC_ACK !== 1 ) |
begin |
$display("Error! Keyboard controller didn't acknowledge single write access") ; |
error1 = 1'b1 ; |
|
ok_o = 0 ; |
end |
end |
endtask // kbd_write |
|
task devider_write ; |
input [31:0] address_i ; |
input [31:16] data_i ; |
output ok_o ; |
|
reg `WRITE_STIM_TYPE write_data ; |
reg `WRITE_RETURN_TYPE write_status ; |
reg `WB_TRANSFER_FLAGS flags ; |
begin:main |
ok_o = 1 ; |
flags`WB_TRANSFER_SIZE = 1 ; |
flags`WB_TRANSFER_AUTO_RTY = 0 ; |
flags`WB_TRANSFER_CAB = 0 ; |
flags`INIT_WAITS = 0 ; |
flags`SUBSEQ_WAITS = 0 ; |
|
write_data`WRITE_ADDRESS = address_i ; |
write_data`WRITE_DATA = {2{data_i}}; |
write_data`WRITE_SEL = 4'hC ; |
|
i_wb_master.wb_single_write( write_data, flags, write_status ) ; |
|
if ( write_status`CYC_ACK !== 1 ) |
begin |
$display("Error! Keyboard controller didn't acknowledge single write access") ; |
error1 = 1'b1 ; |
|
ok_o = 0 ; |
end |
end |
endtask // devider_write |
|
task test_scan_code_receiving ; |
reg ok_keyboard ; |
reg ok_controler ; |
reg ok ; |
reg [7:0] data ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] keyboard_sequence ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] controler_sequence ; |
begin:main |
// prepare character sequence to send from keyboard to controler |
// L SHIFT make |
keyboard_sequence[7:0] = 8'h12 ; |
// A make |
keyboard_sequence[15:8] = 8'h1C ; |
// A break |
keyboard_sequence[23:16] = 8'hF0 ; |
keyboard_sequence[31:24] = 8'h1C ; |
// L SHIFT break |
keyboard_sequence[39:32] = 8'hF0 ; |
keyboard_sequence[47:40] = 8'h12 ; |
|
// prepare character sequence as it is received in scan code set 1 through the controler |
// L SHIFT make |
controler_sequence[7:0] = 8'h2A ; |
// A make |
controler_sequence[15:8] = 8'h1E ; |
// A break |
controler_sequence[23:16] = 8'h9E ; |
// L SHIFT break |
controler_sequence[31:24] = 8'hAA ; |
|
fork |
begin |
send_sequence( keyboard_sequence, 6, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
receive_sequence( controler_sequence, 4, ok_controler ) ; |
|
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
|
// test same thing with translation disabled! |
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
// since translation is disabled, controler sequence is the same as keyboard sequence |
controler_sequence = keyboard_sequence ; |
|
fork |
begin |
|
send_sequence( keyboard_sequence, 6, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
|
end |
begin |
receive_sequence( controler_sequence, 6, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
|
// turn translation on again |
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON|`KBD_KCC, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
// test extended character receiving - rctrl + s combination |
// prepare sequence to send from keyboard to controler |
// R CTRL make |
keyboard_sequence[7:0] = 8'hE0 ; |
keyboard_sequence[15:8] = 8'h14 ; |
// S make |
keyboard_sequence[23:16] = 8'h1B ; |
// S break |
keyboard_sequence[31:24] = 8'hF0 ; |
keyboard_sequence[39:32] = 8'h1B ; |
// R CTRL break |
keyboard_sequence[47:40] = 8'hE0 ; |
keyboard_sequence[55:48] = 8'hF0 ; |
keyboard_sequence[63:56] = 8'h14 ; |
|
// prepare sequence that should be received from the controler |
// R CTRL make |
controler_sequence[7:0] = 8'hE0 ; |
controler_sequence[15:8] = 8'h1D ; |
// S make |
controler_sequence[23:16] = 8'h1F ; |
// S break |
controler_sequence[31:24] = 8'h9F ; |
// R CTRL break |
controler_sequence[39:32] = 8'hE0 ; |
controler_sequence[47:40] = 8'h9D ; |
|
fork |
begin |
send_sequence( keyboard_sequence, 8, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
|
receive_sequence( controler_sequence, 6, ok_controler ) ; |
|
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
|
// test same thing with translation disabled! |
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
// since translation is disabled, controler sequence is the same as keyboard sequence |
controler_sequence = keyboard_sequence ; |
|
fork |
begin |
send_sequence( keyboard_sequence, 8, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
|
receive_sequence( controler_sequence, 8, ok_controler ) ; |
|
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
|
watchdog_reset = !watchdog_reset ; |
end |
endtask // test_scan_code_receiving |
|
task test_normal_scancodes ; |
reg ok ; |
reg ok_keyboard ; |
reg ok_controler ; |
integer i ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] keyboard_sequence ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] controler_sequence ; |
begin:main |
// turn translation on |
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON|`KBD_KCC, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
for ( i = 0 ; i < `PS2_NUM_OF_NORMAL_SCANCODES ; i = i + 1 ) |
begin |
keyboard_sequence[7:0] = normal_scancode_set2_mem[i] ; |
keyboard_sequence[15:8] = 8'hF0 ; |
keyboard_sequence[23:16] = normal_scancode_set2_mem[i] ; |
|
controler_sequence[7:0] = normal_scancode_set1_mem[i] ; |
controler_sequence[15:8] = normal_scancode_set1_mem[i] | 8'h80 ; |
fork |
begin |
send_sequence( keyboard_sequence, 3, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
receive_sequence( controler_sequence, 2, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
end |
|
watchdog_reset = !watchdog_reset ; |
|
end |
endtask // test_normal_scancodes |
|
task test_extended_scancodes ; |
reg ok ; |
reg ok_keyboard ; |
reg ok_controler ; |
integer i ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] keyboard_sequence ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] controler_sequence ; |
begin:main |
// turn translation on |
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON|`KBD_KCC, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
for ( i = 0 ; i < `PS2_NUM_OF_EXTENDED_SCANCODES ; i = i + 1 ) |
begin |
keyboard_sequence[7:0] = 8'hE0 ; |
keyboard_sequence[15:8] = extended_scancode_set2_mem[i] ; |
keyboard_sequence[23:16] = 8'hE0 ; |
keyboard_sequence[31:24] = 8'hF0 ; |
keyboard_sequence[39:32] = extended_scancode_set2_mem[i] ; |
|
controler_sequence[7:0] = 8'hE0 ; |
controler_sequence[15:8] = extended_scancode_set1_mem[i] ; |
controler_sequence[23:16] = 8'hE0 ; |
controler_sequence[31:24] = extended_scancode_set1_mem[i] | 8'h80 ; |
fork |
begin |
send_sequence( keyboard_sequence, 5, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
receive_sequence( controler_sequence, 4, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
end |
|
watchdog_reset = !watchdog_reset ; |
|
end |
endtask // test_extended_scancodes |
|
task return_scan_code_on_irq ; |
output [7:0] scan_code_o ; |
output ok_o ; |
reg [7:0] temp_data ; |
begin:main |
wait ( wb_int === 1 ) ; |
read_status_reg( temp_data, ok_o ) ; |
|
if ( ok_o !== 1'b1 ) |
#1 disable main ; |
|
if ( !( temp_data & `KBD_OBF ) ) |
begin |
$display("Error! Interrupt received from keyboard controler when OBF status not set!") ; |
error1 = 1'b1 ; |
|
end |
|
if ( temp_data & `AUX_OBUF_FULL ) |
begin |
$display("Error! Interrupt received from keyboard controler when AUX_OBUF_FULL status was set!") ; |
error1 = 1'b1 ; |
|
end |
|
read_data_reg( temp_data, ok_o ) ; |
|
if ( ok_o !== 1'b1 ) |
#1 disable main ; |
|
scan_code_o = temp_data ; |
end |
endtask // return_scan_code_on_irq |
|
task send_sequence ; |
input [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] sequence_i ; |
input [31:0] num_of_chars_i ; |
output ok_o ; |
reg [7:0] current_char ; |
integer i ; |
reg ok ; |
reg error ; |
begin:main |
|
error = 0 ; |
ok_o = 1 ; |
ok = 0 ; |
|
for( i = 0 ; i < num_of_chars_i ; i = i + 1 ) |
begin |
current_char = sequence_i[7:0] ; |
|
sequence_i = sequence_i >> 8 ; |
ok = 0 ; |
error = 0 ; |
while ( (ok !== 1) && (error === 0) ) |
begin |
i_ps2_keyboard_model.kbd_send_char |
( |
current_char, |
ok, |
error |
) ; |
end |
|
if ( error ) |
begin |
$display("Time %t", $time) ; |
$display("Keyboard model signaled an error!") ; |
ok_o = 0 ; |
#1 disable main ; |
end |
end |
end |
endtask // send_sequence |
|
task receive_sequence ; |
input [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] sequence_i ; |
input [31:0] num_of_chars_i ; |
output ok_o ; |
reg [7:0] current_char ; |
reg [7:0] data ; |
integer i ; |
begin:main |
|
ok_o = 1 ; |
|
for( i = 0 ; i < num_of_chars_i ; i = i + 1 ) |
begin |
current_char = sequence_i[7:0] ; |
|
sequence_i = sequence_i >> 8 ; |
|
return_scan_code_on_irq( data, ok_o ) ; |
|
if ( ok_o !== 1 ) |
#1 disable main ; |
|
if ( data !== current_char ) |
begin |
$display("Time %t", $time) ; |
$display("Error! Character received was wrong!") ; |
$display("Expected character: %h, received %h ", current_char, data ) ; |
end |
end |
end |
endtask // receive_seqence |
|
task test_keyboard_inhibit ; |
reg ok_controler ; |
reg ok_keyboard ; |
reg error ; |
reg [7:0] data ; |
begin:main |
// first test, if keyboard stays inhibited after character is received, but not read from the controler |
|
i_ps2_keyboard_model.kbd_send_char |
( |
8'hE0, |
ok_keyboard, |
error |
) ; |
|
if ( error ) |
begin |
$display("Error! Keyboard signaled an error while sending character!") ; |
#1 disable main ; |
end |
|
if ( !ok_keyboard ) |
begin |
$display("Something is wrong! Keyboard wasn't able to send a character!") ; |
#1 disable main ; |
end |
|
// wait 5 us to see, if keyboard is inhibited |
#60000 ; |
|
// now check, if clock line is low! |
if ( kbd_clk_cable !== 0 ) |
begin |
$display("Error! Keyboard wasn't inhibited when output buffer was filled!") ; |
#1 disable main ; |
end |
|
// now read the character from input buffer and check if clock was released |
return_scan_code_on_irq( data, ok_controler ) ; |
if ( ok_controler !== 1'b1 ) |
#1 disable main ; |
|
if ( data !== 8'hE0 ) |
begin |
$display("Time %t", $time) ; |
$display("Error! Character read from controler not as expected!") ; |
end |
|
fork |
begin |
repeat(10) |
@(posedge wb_clock) ; |
|
if ( kbd_clk_cable !== 1 ) |
begin |
$display("Error! Keyboard wasn't released from inhibited state when output buffer was read!") ; |
#1 disable main ; |
end |
end |
begin |
i_ps2_keyboard_model.kbd_send_char |
( |
8'h1C, |
ok_keyboard, |
error |
) ; |
if ( !ok_keyboard ) |
begin |
$display("Something is wrong! Keyboard wasn't able to send a character!") ; |
#1 disable main ; |
end |
end |
begin |
return_scan_code_on_irq( data, ok_controler ) ; |
if ( ok_controler !== 1'b1 ) |
#1 disable main ; |
|
if ( data !== 8'h1E ) |
begin |
$display("Time %t", $time) ; |
$display("Error! Character read from controler not as expected!") ; |
end |
end |
join |
|
// disable keyboard controler |
kbd_write( `KBD_CNTL_REG, `KBD_WRITE_MODE, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON|`KBD_KCC | `KBD_DISABLE_COMMAND, ok_controler); |
|
if ( ok_controler !== 1 ) |
#1 disable main ; |
|
repeat( 5 ) |
@(posedge wb_clock) ; |
|
// now check, if clock line is high! |
if ( kbd_clk_cable !== 1 ) |
begin |
$display("Error! Keyboard is not supposed to be inhibited when keyboard controler is disabled!") ; |
#1 disable main ; |
end |
|
// send character and enable keyboard controler at the same time |
fork |
begin |
i_ps2_keyboard_model.kbd_send_char |
( |
8'hE0, |
ok_keyboard, |
error |
) ; |
|
if ( !ok_keyboard ) |
begin |
$display("Something is wrong! Keyboard wasn't able to send a character!") ; |
#1 disable main ; |
end |
end |
begin |
// enable keyboard controler |
kbd_write( `KBD_CNTL_REG, `KBD_WRITE_MODE, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON|`KBD_KCC, ok_controler); |
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
begin |
return_scan_code_on_irq( data, ok_controler ) ; |
if ( ok_controler !== 1'b1 ) |
#1 disable main ; |
|
if ( data !== 8'hE0 ) |
begin |
$display("Time %t", $time) ; |
$display("Error! Character read from controler not as expected!") ; |
end |
end |
join |
|
// do D2 command, that copies parameter in input buffer to output buffer |
kbd_write( `KBD_CNTL_REG, 32'hD2_00_00_00, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, 32'h5555_5555, ok_controler) ; |
|
if ( ok_controler !== 1 ) |
#1 disable main ; |
|
return_scan_code_on_irq( data, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
|
if ( data !== 8'h55 ) |
begin |
$display("Error! D2 command doesn't work properly") ; |
end |
|
end |
endtask // test_keyboard_inhibit |
|
task test_print_screen_and_pause_scancodes ; |
reg ok ; |
reg ok_keyboard ; |
reg ok_controler ; |
integer i ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] keyboard_sequence ; |
reg [(MAX_SEQUENCE_LENGTH*8 - 1) : 0] controler_sequence ; |
begin:main |
// turn translation on |
kbd_write(`KBD_CNTL_REG, `KBD_WRITE_MODE, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
kbd_write(`KBD_DATA_REG, `KBD_EKI|`KBD_SYS|`AUX_INTERRUPT_ON|`KBD_KCC, ok); |
if ( ok !== 1 ) |
#1 disable main ; |
|
// prepare character sequence to send from keyboard to controler - pause |
keyboard_sequence[7:0] = 8'hE1 ; |
keyboard_sequence[15:8] = 8'h14 ; |
keyboard_sequence[23:16] = 8'h77 ; |
keyboard_sequence[31:24] = 8'hE1 ; |
keyboard_sequence[39:32] = 8'hF0 ; |
keyboard_sequence[47:40] = 8'h14 ; |
keyboard_sequence[55:48] = 8'hF0 ; |
keyboard_sequence[63:56] = 8'h77 ; |
|
// prepare character sequence as it is received in scan code set 1 through the controler |
controler_sequence[7:0] = 8'hE1 ; |
controler_sequence[15:8] = 8'h1D ; |
controler_sequence[23:16] = 8'h45 ; |
controler_sequence[31:24] = 8'hE1 ; |
controler_sequence[39:32] = 8'h9D ; |
controler_sequence[47:40] = 8'hC5 ; |
|
fork |
begin |
send_sequence( keyboard_sequence, 8, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
receive_sequence( controler_sequence, 6, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
|
// prepare character sequence to send from keyboard to controler - make print screen |
keyboard_sequence[7:0] = 8'hE0 ; |
keyboard_sequence[15:8] = 8'h12 ; |
keyboard_sequence[23:16] = 8'hE0 ; |
keyboard_sequence[31:24] = 8'h7C ; |
|
// prepare character sequence as it is received in scan code set 1 through the controler |
controler_sequence[7:0] = 8'hE0 ; |
controler_sequence[15:8] = 8'h2A ; |
controler_sequence[23:16] = 8'hE0 ; |
controler_sequence[31:24] = 8'h37 ; |
|
fork |
begin |
send_sequence( keyboard_sequence, 4, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
receive_sequence( controler_sequence, 4, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
|
// prepare character sequence to send from keyboard to controler - break print screen |
keyboard_sequence[7:0] = 8'hE0 ; |
keyboard_sequence[15:8] = 8'hF0 ; |
keyboard_sequence[23:16] = 8'h7C ; |
keyboard_sequence[31:24] = 8'hE0 ; |
keyboard_sequence[39:32] = 8'hF0 ; |
keyboard_sequence[47:40] = 8'h12 ; |
|
// prepare character sequence as it is received in scan code set 1 through the controler |
controler_sequence[7:0] = 8'hE0 ; |
controler_sequence[15:8] = 8'hB7 ; |
controler_sequence[23:16] = 8'hE0 ; |
controler_sequence[31:24] = 8'hAA ; |
|
fork |
begin |
send_sequence( keyboard_sequence, 6, ok_keyboard ) ; |
if ( ok_keyboard !== 1 ) |
#1 disable main ; |
end |
begin |
receive_sequence( controler_sequence, 4, ok_controler ) ; |
if ( ok_controler !== 1 ) |
#1 disable main ; |
end |
join |
end |
endtask // test_print_screen_and_pause_scancodes |
|
`ifdef PS2_AUX |
task receive_mouse_movement; |
reg [7:0] mouse_data_received ; |
reg ok_mouse ; |
reg ok_wb ; |
reg error ; |
integer num_of_mouse_data_sent ; |
begin:main |
error = 0 ; |
num_of_mouse_data_sent = 0 ; |
while ( !stop_mouse_tests ) |
begin |
fork |
begin |
ok_mouse = 0 ; |
while ( !ok_mouse && !error ) |
begin |
i_ps2_mouse_model.kbd_send_char |
( |
num_of_mouse_data_sent[7:0], |
ok_mouse, |
error |
) ; |
end |
if ( error ) |
begin |
$display("Mouse model signaled an error while transmiting data! Time %t", $time) ; |
#1 disable main ; |
end |
else |
num_of_mouse_data_sent = num_of_mouse_data_sent + 1 ; |
|
end |
begin |
return_mouse_data_on_irq( mouse_data_received, ok_wb ) ; |
if ( !ok_wb ) |
#1 disable main ; |
|
if ( mouse_data_received !== num_of_mouse_data_sent[7:0] ) |
begin |
$display("Time %t", $time) ; |
$display("Data received from mouse has unexpected value! Expected %h, actual %h", num_of_mouse_data_sent[7:0], mouse_data_received) ; |
end |
end |
join |
end |
|
$display("Number of chars received from mouse %d", num_of_mouse_data_sent) ; |
end |
endtask //receive_mouse_movement |
|
task return_mouse_data_on_irq ; |
output [7:0] mouse_data_o ; |
output ok_o ; |
reg [7:0] temp_data ; |
begin:main |
wait ( wb_intb === 1 ) ; |
|
wait ( ps2_test_bench.read_status_reg.in_use !== 1'b1 ); |
|
read_status_reg( temp_data, ok_o ) ; |
|
if ( ok_o !== 1'b1 ) |
#1 disable main ; |
|
if ( !( temp_data & `AUX_OBUF_FULL ) || !(temp_data & `KBD_OBF)) |
begin |
$display("Error! Interrupt b received from controler when AUX_OBF status or KBD_OBF statuses not set!") ; |
|
end |
|
wait ( ps2_test_bench.read_data_reg.in_use !== 1'b1 ); |
|
read_data_reg( temp_data, ok_o ) ; |
|
if ( ok_o !== 1'b1 ) |
#1 disable main ; |
|
mouse_data_o = temp_data ; |
end |
endtask // return_scan_code_on_irq |
`endif |
|
endmodule // ps2_test_bench |
/ps2_sim_top.v
0,0 → 1,163
////////////////////////////////////////////////////////////////////// |
//// //// |
//// ps2_sim_top.v //// |
//// //// |
//// This file is part of the "ps2" project //// |
//// http://www.opencores.org/cores/ps2/ //// |
//// //// |
//// Author(s): //// |
//// - mihad@opencores.org //// |
//// - Miha Dolenc //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.4 2003/07/01 12:33:45 mihad |
// Added an option to use constant values instead of RAM |
// in the translation table. |
// |
// Revision 1.3 2003/05/28 16:26:51 simons |
// Change the address width. |
// |
// Revision 1.2 2002/04/09 13:16:04 mihad |
// Mouse interface added |
// |
// Revision 1.1.1.1 2002/02/18 16:16:55 mihad |
// Initial project import - working |
// |
// |
|
`include "ps2_defines.v" |
module ps2_sim_top |
( |
wb_clk_i, |
wb_rst_i, |
wb_cyc_i, |
wb_stb_i, |
wb_we_i, |
wb_sel_i, |
wb_adr_i, |
wb_dat_i, |
wb_dat_o, |
wb_ack_o, |
|
wb_int_o, |
|
ps2_kbd_clk_io, |
ps2_kbd_data_io |
|
`ifdef PS2_AUX |
, |
wb_intb_o, |
|
ps2_aux_clk_io, |
ps2_aux_data_io |
`endif |
) ; |
|
input wb_clk_i, |
wb_rst_i, |
wb_cyc_i, |
wb_stb_i, |
wb_we_i ; |
|
input [3:0] wb_sel_i ; |
|
input [3:0] wb_adr_i ; |
input [31:0] wb_dat_i ; |
|
output [31:0] wb_dat_o ; |
|
output wb_ack_o, |
wb_int_o ; |
|
inout ps2_kbd_clk_io, |
ps2_kbd_data_io ; |
`ifdef PS2_AUX |
output wb_intb_o ; |
inout ps2_aux_clk_io ; |
inout ps2_aux_data_io ; |
`endif |
|
wire ps2_kbd_clk_pad_i = ps2_kbd_clk_io ; |
wire ps2_kbd_data_pad_i = ps2_kbd_data_io ; |
|
wire ps2_kbd_clk_pad_o, |
ps2_kbd_data_pad_o, |
ps2_kbd_clk_pad_oe_o, |
ps2_kbd_data_pad_oe_o ; |
|
ps2_top i_ps2_top |
( |
.wb_clk_i (wb_clk_i), |
.wb_rst_i (wb_rst_i), |
.wb_cyc_i (wb_cyc_i), |
.wb_stb_i (wb_stb_i), |
.wb_we_i (wb_we_i), |
.wb_sel_i (wb_sel_i), |
.wb_adr_i (wb_adr_i), |
.wb_dat_i (wb_dat_i), |
.wb_dat_o (wb_dat_o), |
.wb_ack_o (wb_ack_o), |
|
.wb_int_o (wb_int_o), |
|
.ps2_kbd_clk_pad_i (ps2_kbd_clk_pad_i), |
.ps2_kbd_data_pad_i (ps2_kbd_data_pad_i), |
.ps2_kbd_clk_pad_o (ps2_kbd_clk_pad_o), |
.ps2_kbd_data_pad_o (ps2_kbd_data_pad_o), |
.ps2_kbd_clk_pad_oe_o (ps2_kbd_clk_pad_oe_o), |
.ps2_kbd_data_pad_oe_o (ps2_kbd_data_pad_oe_o) |
|
`ifdef PS2_AUX |
, |
.wb_intb_o (wb_intb_o), |
|
.ps2_aux_clk_pad_i (ps2_aux_clk_io), |
.ps2_aux_data_pad_i (ps2_aux_data_io), |
.ps2_aux_clk_pad_o (ps2_aux_clk_pad_o), |
.ps2_aux_data_pad_o (ps2_aux_data_pad_o), |
.ps2_aux_clk_pad_oe_o (ps2_aux_clk_pad_oe_o), |
.ps2_aux_data_pad_oe_o (ps2_aux_data_pad_oe_o) |
`endif |
) ; |
|
assign ps2_kbd_clk_io = ps2_kbd_clk_pad_oe_o ? ps2_kbd_clk_pad_o : 1'bz ; |
assign ps2_kbd_data_io = ps2_kbd_data_pad_oe_o ? ps2_kbd_data_pad_o : 1'bz ; |
|
`ifdef PS2_AUX |
assign ps2_aux_clk_io = ps2_aux_clk_pad_oe_o ? ps2_aux_clk_pad_o : 1'bz ; |
assign ps2_aux_data_io = ps2_aux_data_pad_oe_o ? ps2_aux_data_pad_o : 1'bz ; |
`endif |
endmodule |
/ps2_testbench_defines.v
0,0 → 1,153
////////////////////////////////////////////////////////////////////// |
//// //// |
//// ps2_testbench_defines.v //// |
//// //// |
//// This file is part of the "ps2" project //// |
//// http://www.opencores.org/cores/ps2/ //// |
//// //// |
//// Author(s): //// |
//// - mihad@opencores.org //// |
//// - Miha Dolenc //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.2 2002/04/09 13:17:38 mihad |
// Mouse interface testcases added |
// |
// Revision 1.1.1.1 2002/02/18 16:16:56 mihad |
// Initial project import - working |
// |
// |
|
//=================================================================================== |
// User-unchangeable testbench defines (constants) |
//=================================================================================== |
|
// setup and hold time definitions for WISHBONE - used in BFMs for signal generation |
`define Tsetup 2 |
`define Thold 2 |
|
// how many clock cycles should model wait for design's response - integer 32 bit value |
`define WAIT_FOR_RESPONSE 6 |
|
// maximum number of transactions allowed in single call to block or cab transfer routines |
`define MAX_BLK_SIZE 8 |
|
// maximum retry terminations allows for WISHBONE master to repeat an access |
`define WB_TB_MAX_RTY 1000 |
|
|
// some common types and defines |
`define WB_ADDR_WIDTH 32 |
`define WB_DATA_WIDTH 32 |
`define WB_SEL_WIDTH `WB_DATA_WIDTH/8 |
`define WB_TAG_WIDTH 1 |
`define WB_ADDR_TYPE [(`WB_ADDR_WIDTH - 1):0] |
`define WB_DATA_TYPE [(`WB_DATA_WIDTH - 1):0] |
`define WB_SEL_TYPE [(`WB_SEL_WIDTH - 1):0] |
`define WB_TAG_TYPE [(`WB_TAG_WIDTH - 1):0] |
|
// definitions file only for testbench usage |
// wishbone master behavioral defines |
// flags type for wishbone cycle initialization |
`define CYC_FLAG_TYPE [0:0] |
// cab flag field in cycle initialization data |
`define CYC_CAB_FLAG [0] |
// read cycle stimulus - consists of: |
// - address field - which address read will be performed from |
// - sel field - what byte select value should be |
// - tag field - what tag values should be put on the bus |
`define READ_STIM_TYPE [(`WB_ADDR_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):0] |
`define READ_STIM_LENGTH (`WB_ADDR_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH) |
`define READ_ADDRESS [(`WB_ADDR_WIDTH - 1):0] |
`define READ_SEL [(`WB_ADDR_WIDTH + `WB_SEL_WIDTH - 1):`WB_ADDR_WIDTH] |
`define READ_TAG_STIM [(`WB_ADDR_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):(`WB_ADDR_WIDTH + `WB_SEL_WIDTH)] |
|
// read cycle return type consists of: |
// - read data field |
// - tag field received from WISHBONE |
// - wishbone slave response fields - ACK, ERR and RTY |
// - test bench error indicator (when testcase has not used wb master model properly) |
// - how much data was actually transfered |
`define READ_RETURN_TYPE [(32 + 4 + `WB_DATA_WIDTH + `WB_TAG_WIDTH - 1):0] |
`define READ_DATA [(32 + `WB_DATA_WIDTH + 4 - 1):32 + 4] |
`define READ_TAG_RET [(32 + 4 + `WB_DATA_WIDTH + `WB_TAG_WIDTH - 1):(`WB_DATA_WIDTH + 32 + 4)] |
`define READ_RETURN_LENGTH (32 + 4 + `WB_DATA_WIDTH + `WB_TAG_WIDTH - 1) |
|
// write cycle stimulus type consists of |
// - address field |
// - data field |
// - sel field |
// - tag field |
`define WRITE_STIM_TYPE [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):0] |
`define WRITE_ADDRESS [(`WB_ADDR_WIDTH - 1):0] |
`define WRITE_DATA [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH - 1):`WB_ADDR_WIDTH] |
`define WRITE_SEL [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH - 1):(`WB_ADDR_WIDTH + `WB_DATA_WIDTH)] |
`define WRITE_TAG_STIM [(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH - 1):(`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH)] |
|
// length of WRITE_STIMULUS |
`define WRITE_STIM_LENGTH (`WB_ADDR_WIDTH + `WB_DATA_WIDTH + `WB_SEL_WIDTH + `WB_TAG_WIDTH) |
|
// write cycle return type consists of: |
// - test bench error indicator (when testcase has not used wb master model properly) |
// - wishbone slave response fields - ACK, ERR and RTY |
// - tag field received from WISHBONE |
// - how much data was actually transfered |
`define WRITE_RETURN_TYPE [(32 + 4 + `WB_TAG_WIDTH - 1):0] |
`define WRITE_TAG_RET [(32 + 4 + `WB_TAG_WIDTH - 1):32 + 4] |
|
// this four fields are common to both read and write routines return values |
`define TB_ERROR_BIT [0] |
`define CYC_ACK [1] |
`define CYC_RTY [2] |
`define CYC_ERR [3] |
`define CYC_RESPONSE [3:1] |
`define CYC_ACTUAL_TRANSFER [35:4] |
|
// block transfer flags |
`define WB_TRANSFER_FLAGS [41:0] |
// consists of: |
// - number of transfer cycles to perform |
// - flag that enables retry termination handling - if disabled, block transfer routines will return on any termination other than acknowledge |
// - flag indicating CAB transfer is to be performed - ignored by all single transfer routines |
// - number of initial wait states to insert |
// - number of subsequent wait states to insert |
`define WB_TRANSFER_SIZE [41:10] |
`define WB_TRANSFER_AUTO_RTY [8] |
`define WB_TRANSFER_CAB [9] |
`define INIT_WAITS [3:0] |
`define SUBSEQ_WAITS [7:4] |
|
`define WB_FREQ 0.10 |
/ps2_keyboard_model.v
0,0 → 1,296
////////////////////////////////////////////////////////////////////// |
//// //// |
//// ps2_keyboard_model.v //// |
//// //// |
//// This file is part of the "ps2" project //// |
//// http://www.opencores.org/cores/ps2/ //// |
//// //// |
//// Author(s): //// |
//// - mihad@opencores.org //// |
//// - Miha Dolenc //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// Revision 1.2 2002/04/09 13:15:16 mihad |
// Wrong acknowledge generation during receiving repaired |
// |
// Revision 1.1.1.1 2002/02/18 16:16:55 mihad |
// Initial project import - working |
// |
// |
|
`include "timescale.v" |
|
module ps2_keyboard_model |
( |
kbd_clk_io, |
kbd_data_io, |
last_char_received_o, |
char_valid_o |
); |
|
parameter [31:0] kbd_clk_period = 50000; // chould be between 33 and 50 us to generate the clock between 30 and 20 kHz |
|
inout kbd_clk_io, |
kbd_data_io ; |
|
output [7:0] last_char_received_o ; |
reg [7:0] last_char_received_o ; |
|
output char_valid_o ; |
reg char_valid_o ; |
|
reg kbd_clk, |
kbd_data ; |
|
assign kbd_clk_io = kbd_clk ? 1'bz : 1'b0 ; |
assign kbd_data_io = kbd_data ? 1'bz : 1'b0 ; |
|
reg receiving ; |
initial |
begin |
kbd_clk = 1'b1 ; |
kbd_data = 1'b1 ; |
|
last_char_received_o = 0 ; |
char_valid_o = 0 ; |
|
receiving = 0 ; |
end |
|
always@(kbd_data_io or kbd_clk_io) |
begin |
// check if host is driving keyboard data low and doesn't drive clock |
if ( !kbd_data_io && kbd_data && kbd_clk_io) |
begin |
// wait for half of clock period |
#(kbd_clk_period/2) ; |
|
// state hasn't changed - host wishes to send data - go receiving |
if ( !kbd_data_io && kbd_data && kbd_clk_io) |
kbd_receive_char(last_char_received_o) ; |
end |
end |
|
task kbd_send_char ; |
input [7:0] char ; |
output transmited_ok ; |
output severe_error ; |
reg [10:0] tx_reg ; |
integer i ; |
begin:main |
severe_error = 1'b0 ; |
transmited_ok = 1'b0 ; |
|
wait ( !receiving ) ; |
|
tx_reg = { 1'b1, !(^char), char, 1'b0 } ; |
|
fork |
begin:wait_for_idle |
wait( (kbd_clk_io === 1'b1) && (kbd_data_io === 1'b1) ) ; |
// disable timeout ; |
end |
/*begin:timeout |
#(256 * kbd_clk_period) ; |
$display("Error! Keyboard bus did not go idle in 256 keyboard clock cycles time!") ; |
severe_error = 1'b1 ; |
transmited_ok = 1'b0 ; |
disable main ; |
end*/ |
join |
|
#(kbd_clk_period/2) ; |
if ( !kbd_clk_io ) |
begin |
transmited_ok = 1'b0 ; |
kbd_data = 1'b1 ; |
disable main ; |
end |
|
i = 0 ; |
while ( i < 11 ) |
begin |
kbd_data = tx_reg[i] ; |
|
#(kbd_clk_period/2) ; |
|
if ( !kbd_clk_io ) |
begin |
transmited_ok = 1'b0 ; |
kbd_data = 1'b1 ; |
disable main ; |
end |
|
kbd_clk = 1'b0 ; |
|
i = i + 1 ; |
|
#(kbd_clk_period/2) ; |
kbd_clk = 1'b1 ; |
end |
|
if ( i == 11 ) |
transmited_ok = 1'b1 ; |
end |
endtask // kbd_send_char |
|
task kbd_receive_char; |
output [7:0] char ; |
reg parity ; |
integer i ; |
reg stop_clocking ; |
begin:main |
i = 0 ; |
receiving = 1 ; |
stop_clocking = 1'b0 ; |
|
#(kbd_clk_period/2) ; |
|
while ( !stop_clocking ) |
begin |
|
if ( !kbd_clk_io ) |
begin |
receiving = 0 ; |
disable main ; |
end |
|
kbd_clk = 1'b0 ; |
|
#(kbd_clk_period/2) ; |
|
kbd_clk = 1'b1 ; |
|
if ( i > 0 ) |
begin |
if ( i <= 8 ) |
char[i - 1] = kbd_data_io ; |
else if ( i == 9 ) |
begin |
parity = kbd_data_io ; |
if ( parity !== ( !(^char) ) ) |
$display("Invalid parity bit received") ; |
end |
end |
|
i = i + 1 ; |
#(kbd_clk_period/4) ; |
if ( i > 9 ) |
begin |
if ( kbd_data_io === 1'b1 ) |
begin |
kbd_data <= 1'b0 ; |
stop_clocking = 1'b1 ; |
end |
end |
|
#(kbd_clk_period/4) ; |
end |
|
kbd_clk = 1'b0 ; |
|
#(kbd_clk_period/2) ; |
kbd_clk <= 1'b1 ; |
kbd_data <= 1'b1 ; |
|
receiving = 0 ; |
|
if ( i === 10 ) |
begin |
char_valid_o = !char_valid_o ; |
end |
end |
endtask // kbd_receive_char |
|
|
time last_clk_low; |
time last_clk_diference; |
|
|
|
initial |
begin |
last_clk_low =0; |
last_clk_diference =0; |
|
end |
|
always @(negedge kbd_clk_io) |
|
begin:low_time_check |
if (kbd_clk == 1) |
begin |
last_clk_low =$time; |
fork |
begin |
#61000 |
$display(" clock low more then 61us"); |
$display("Time %t", $time) ; |
#30000 |
$display("error clock low more then 90usec"); |
$display("Time %t", $time) ; |
$stop; |
end |
begin |
@(posedge kbd_clk_io); |
disable low_time_check; |
end |
join |
end |
end |
|
|
|
|
always @(posedge kbd_clk_io ) |
begin |
if (last_clk_low >0 ) |
begin |
last_clk_diference = $time - last_clk_low; |
if (last_clk_diference < 60000) |
begin |
$display("error time< 60u"); |
#100 $stop; |
end |
end |
end |
|
|
|
|
|
|
endmodule // ps2_keyboard_model |
/wb_master_behavioral.v
0,0 → 1,773
////////////////////////////////////////////////////////////////////// |
//// //// |
//// wb_master_behavioral.v //// |
//// //// |
//// This file is part of the "ps2" project //// |
//// http://www.opencores.org/cores/ps2/ //// |
//// //// |
//// Author(s): //// |
//// - mihad@opencores.org //// |
//// - Miha Dolenc //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// |
|
`include "ps2_testbench_defines.v" |
`include "timescale.v" |
module WB_MASTER_BEHAVIORAL |
( |
CLK_I, |
RST_I, |
TAG_I, |
TAG_O, |
ACK_I, |
ADR_O, |
CYC_O, |
DAT_I, |
DAT_O, |
ERR_I, |
RTY_I, |
SEL_O, |
STB_O, |
WE_O, |
CAB_O |
); |
|
input CLK_I; |
input RST_I; |
input `WB_TAG_TYPE TAG_I; |
output `WB_TAG_TYPE TAG_O; |
input ACK_I; |
output `WB_ADDR_TYPE ADR_O; |
output CYC_O; |
input `WB_DATA_TYPE DAT_I; |
output `WB_DATA_TYPE DAT_O; |
input ERR_I; |
input RTY_I; |
output `WB_SEL_TYPE SEL_O; |
output STB_O; |
output WE_O; |
output CAB_O; |
|
// instantiate low level master module |
WB_MASTER32 wbm_low_level |
( |
.CLK_I(CLK_I), |
.RST_I(RST_I), |
.TAG_I(TAG_I), |
.TAG_O(TAG_O), |
.ACK_I(ACK_I), |
.ADR_O(ADR_O), |
.CYC_O(CYC_O), |
.DAT_I(DAT_I), |
.DAT_O(DAT_O), |
.ERR_I(ERR_I), |
.RTY_I(RTY_I), |
.SEL_O(SEL_O), |
.STB_O(STB_O), |
.WE_O(WE_O), |
.CAB_O(CAB_O) |
) ; |
|
// block read and write buffers definition |
// single write buffer |
reg `WRITE_STIM_TYPE blk_write_data [0:(`MAX_BLK_SIZE - 1)] ; |
// read stimulus buffer - addresses, tags, selects etc. |
reg `READ_STIM_TYPE blk_read_data_in [0:(`MAX_BLK_SIZE - 1)] ; |
// read return buffer - data and tags received while performing block reads |
reg `READ_RETURN_TYPE blk_read_data_out [0:(`MAX_BLK_SIZE - 1)] ; |
|
// single write task |
task wb_single_write ; |
input `WRITE_STIM_TYPE write_data ; |
input `WB_TRANSFER_FLAGS write_flags ; |
inout `WRITE_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_single_write routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
@(posedge CLK_I) ; |
|
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_single_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = write_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_write(write_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && write_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_single_write, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
retry = 0 ; |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = write_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.end_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_single_write |
|
task wb_single_read ; |
input `READ_STIM_TYPE read_data ; |
input `WB_TRANSFER_FLAGS read_flags ; |
inout `READ_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
rty_count = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_single_read routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
@(posedge CLK_I) ; |
|
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_single_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = read_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_read(read_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && read_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_single_read, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
begin |
retry = 0 ; |
end |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = read_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.end_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_single_read |
|
task wb_RMW_read ; |
input `READ_STIM_TYPE read_data ; |
input `WB_TRANSFER_FLAGS read_flags ; |
inout `READ_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
rty_count = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_RMW_read routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
@(posedge CLK_I) ; |
|
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_RMW_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = read_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_read(read_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && read_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_RMW_read, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
begin |
retry = 0 ; |
end |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = read_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
if (retry === 1) |
wbm_low_level.end_cycle ; |
else |
wbm_low_level.modify_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_RMW_read |
|
task wb_RMW_write ; |
input `WRITE_STIM_TYPE write_data ; |
input `WB_TRANSFER_FLAGS write_flags ; |
inout `WRITE_RETURN_TYPE return ; |
reg in_use ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg retry ; |
begin:main |
|
return`TB_ERROR_BIT = 1'b0 ; |
cab = 0 ; |
return`CYC_ACTUAL_TRANSFER = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_RMW_write routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
|
retry = 1 ; |
|
while (retry === 1) |
begin |
// synchronize operation to clock |
@(posedge CLK_I) ; |
ok = 1 ; |
if (rty_count !== 0) |
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
|
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_single_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// first insert initial wait states |
cyc_count = write_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.wbm_write(write_data, return) ; |
|
if ( return`CYC_ERR === 0 && return`CYC_ACK === 0 && return`CYC_RTY === 1 && write_flags`WB_TRANSFER_AUTO_RTY === 1 && return`TB_ERROR_BIT === 0) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_single_write, Time %t ", $time) ; |
retry = 0 ; |
end |
else |
begin |
retry = 1 ; |
rty_count = rty_count + 1 ; |
end |
end |
else |
retry = 0 ; |
|
// if test bench error bit is set, there is no meaning in introducing subsequent wait states |
if ( return`TB_ERROR_BIT !== 0 ) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
cyc_count = write_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
wbm_low_level.end_cycle ; |
end |
|
in_use = 0 ; |
|
end //main |
endtask // wb_RMW_write |
|
task wb_block_write ; |
input `WB_TRANSFER_FLAGS write_flags ; |
inout `WRITE_RETURN_TYPE return ; |
|
reg in_use ; |
reg `WRITE_STIM_TYPE current_write ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg end_blk ; |
begin:main |
|
return`CYC_ACTUAL_TRANSFER = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_block_write routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if (write_flags`WB_TRANSFER_SIZE > `MAX_BLK_SIZE) |
begin |
$display("*E, number of transfers passed to wb_block_write routine exceeds defined maximum transaction length! Time %t", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
@(posedge CLK_I) ; |
cab = write_flags`WB_TRANSFER_CAB ; |
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// insert initial wait states |
cyc_count = write_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
end_blk = 0 ; |
while (end_blk === 0) |
begin |
// collect data for current data beat |
current_write = blk_write_data[return`CYC_ACTUAL_TRANSFER] ; |
wbm_low_level.wbm_write(current_write, return) ; |
|
// check result of write operation |
// check for severe test error |
if (return`TB_ERROR_BIT !== 0) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
// slave returned error or error signal had invalid value |
if (return`CYC_ERR !== 0) |
end_blk = 1 ; |
|
if ( |
(return`CYC_RTY !== 0) && (return`CYC_RTY !== 1) || |
(return`CYC_ACK !== 0) && (return`CYC_ACK !== 1) || |
(return`CYC_ERR !== 0) && (return`CYC_ERR !== 1) |
) |
begin |
end_blk = 1 ; |
$display("*E, at least one slave response signal was invalid when cycle finished! Routine wb_block_write, Time %t ", $time) ; |
$display("ACK = %b \t RTY_O = %b \t ERR_O = %b \t", return`CYC_ACK, return`CYC_RTY, return`CYC_ERR) ; |
end |
|
if ((return`CYC_RTY === 1) && (write_flags`WB_TRANSFER_AUTO_RTY !== 1)) |
end_blk = 1 ; |
|
if ((return`CYC_RTY === 1) && (write_flags`WB_TRANSFER_AUTO_RTY === 1)) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_block_write, Time %t ", $time) ; |
end_blk = 1 ; |
end |
else |
begin |
rty_count = rty_count + 1 ; |
end |
end |
else |
rty_count = 0 ; |
|
// check if slave responded at all |
if (return`CYC_RESPONSE === 0) |
end_blk = 1 ; |
|
// check if all intended data was transfered |
if (return`CYC_ACTUAL_TRANSFER === write_flags`WB_TRANSFER_SIZE) |
end_blk = 1 ; |
|
// insert subsequent wait cycles, if transfer is supposed to continue |
if ( end_blk === 0 ) |
begin |
cyc_count = write_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
end |
|
if ( (end_blk === 0) && (return`CYC_RTY === 1) ) |
begin |
wbm_low_level.end_cycle ; |
@(posedge CLK_I) ; |
wbm_low_level.start_cycle(cab, 1'b1, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_write, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
end_blk = 1 ; |
end |
end |
end //while |
|
wbm_low_level.end_cycle ; |
in_use = 0 ; |
end //main |
endtask //wb_block_write |
|
task wb_block_read ; |
input `WB_TRANSFER_FLAGS read_flags ; |
inout `READ_RETURN_TYPE return ; |
|
reg in_use ; |
reg `READ_STIM_TYPE current_read ; |
reg cab ; |
reg ok ; |
integer cyc_count ; |
integer rty_count ; |
reg end_blk ; |
integer transfered ; |
begin:main |
|
return`CYC_ACTUAL_TRANSFER = 0 ; |
transfered = 0 ; |
rty_count = 0 ; |
|
// check if task was called before previous call finished |
if ( in_use === 1 ) |
begin |
$display("*E, wb_block_read routine re-entered! Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if (read_flags`WB_TRANSFER_SIZE > `MAX_BLK_SIZE) |
begin |
$display("*E, number of transfers passed to wb_block_read routine exceeds defined maximum transaction length! Time %t", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
in_use = 1 ; |
@(posedge CLK_I) ; |
cab = read_flags`WB_TRANSFER_CAB ; |
|
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
|
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// insert initial wait states |
cyc_count = read_flags`INIT_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
|
end_blk = 0 ; |
while (end_blk === 0) |
begin |
// collect data for current data beat |
current_read = blk_read_data_in[return`CYC_ACTUAL_TRANSFER] ; |
|
wbm_low_level.wbm_read(current_read, return) ; |
|
if ( transfered !== return`CYC_ACTUAL_TRANSFER ) |
begin |
blk_read_data_out[transfered] = return ; |
transfered = return`CYC_ACTUAL_TRANSFER ; |
end |
|
// check result of read operation |
// check for severe test error |
if (return`TB_ERROR_BIT !== 0) |
begin |
@(posedge CLK_I) ; |
wbm_low_level.end_cycle ; |
disable main ; |
end |
|
// slave returned error or error signal had invalid value |
if (return`CYC_ERR !== 0) |
end_blk = 1 ; |
|
if ( |
(return`CYC_RTY !== 0) && (return`CYC_RTY !== 1) || |
(return`CYC_ACK !== 0) && (return`CYC_ACK !== 1) || |
(return`CYC_ERR !== 0) && (return`CYC_ERR !== 1) |
) |
begin |
end_blk = 1 ; |
$display("*E, at least one slave response signal was invalid when cycle finished! Routine wb_block_read, Time %t ", $time) ; |
$display("ACK = %b \t RTY_O = %b \t ERR_O = %b \t", return`CYC_ACK, return`CYC_RTY, return`CYC_ERR) ; |
end |
|
if ((return`CYC_RTY === 1) && (read_flags`WB_TRANSFER_AUTO_RTY !== 1)) |
end_blk = 1 ; |
|
if ((return`CYC_RTY === 1) && (read_flags`WB_TRANSFER_AUTO_RTY === 1)) |
begin |
if ( rty_count === `WB_TB_MAX_RTY ) |
begin |
$display("*E, maximum number of retries received - access will not be repeated anymore! Routine wb_block_read, Time %t ", $time) ; |
end_blk = 1 ; |
end |
else |
begin |
rty_count = rty_count + 1 ; |
end |
end |
else |
rty_count = 0 ; |
|
// check if slave responded at all |
if (return`CYC_RESPONSE === 0) |
end_blk = 1 ; |
|
// check if all intended data was transfered |
if (return`CYC_ACTUAL_TRANSFER === read_flags`WB_TRANSFER_SIZE) |
end_blk = 1 ; |
|
// insert subsequent wait cycles, if transfer is supposed to continue |
if ( end_blk === 0 ) |
begin |
cyc_count = read_flags`SUBSEQ_WAITS ; |
while ( cyc_count > 0 ) |
begin |
@(posedge CLK_I) ; |
cyc_count = cyc_count - 1 ; |
end |
end |
|
if ( (end_blk === 0) && (return`CYC_RTY === 1) ) |
begin |
wbm_low_level.end_cycle ; |
@(posedge CLK_I) ; |
wbm_low_level.start_cycle(cab, 1'b0, ok) ; |
if ( ok !== 1 ) |
begin |
$display("*E, Failed to initialize cycle! Routine wb_block_read, Time %t ", $time) ; |
return`TB_ERROR_BIT = 1'b1 ; |
end_blk = 1 ; |
end |
end |
end //while |
|
wbm_low_level.end_cycle ; |
in_use = 0 ; |
end //main |
endtask //wb_block_read |
|
endmodule |
|
/wb_master32.v
0,0 → 1,366
////////////////////////////////////////////////////////////////////// |
//// //// |
//// wb_master32.v //// |
//// //// |
//// This file is part of the "ps2" project //// |
//// http://www.opencores.org/cores/ps2/ //// |
//// //// |
//// Author(s): //// |
//// - mihad@opencores.org //// |
//// - Miha Dolenc //// |
//// //// |
//// All additional information is avaliable in the README.txt //// |
//// file. //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2000 Miha Dolenc, mihad@opencores.org //// |
//// //// |
//// This source file may be used and distributed without //// |
//// restriction provided that this copyright statement is not //// |
//// removed from the file and that any derivative work contains //// |
//// the original copyright notice and the associated disclaimer. //// |
//// //// |
//// This source file is free software; you can redistribute it //// |
//// and/or modify it under the terms of the GNU Lesser General //// |
//// Public License as published by the Free Software Foundation; //// |
//// either version 2.1 of the License, or (at your option) any //// |
//// later version. //// |
//// //// |
//// This source is distributed in the hope that it will be //// |
//// useful, but WITHOUT ANY WARRANTY; without even the implied //// |
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //// |
//// PURPOSE. See the GNU Lesser General Public License for more //// |
//// details. //// |
//// //// |
//// You should have received a copy of the GNU Lesser General //// |
//// Public License along with this source; if not, download it //// |
//// from http://www.opencores.org/lgpl.shtml //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
// |
// CVS Revision History |
// |
// $Log: not supported by cvs2svn $ |
// |
|
`include "ps2_testbench_defines.v" |
`include "timescale.v" |
module WB_MASTER32 |
( |
CLK_I, |
RST_I, |
TAG_I, |
TAG_O, |
ACK_I, |
ADR_O, |
CYC_O, |
DAT_I, |
DAT_O, |
ERR_I, |
RTY_I, |
SEL_O, |
STB_O, |
WE_O, |
CAB_O |
); |
|
input CLK_I; |
input RST_I; |
input `WB_TAG_TYPE TAG_I; |
output `WB_TAG_TYPE TAG_O; |
input ACK_I; |
output `WB_ADDR_TYPE ADR_O; |
output CYC_O; |
input `WB_DATA_TYPE DAT_I; |
output `WB_DATA_TYPE DAT_O; |
input ERR_I; |
input RTY_I; |
output `WB_SEL_TYPE SEL_O; |
output STB_O; |
output WE_O; |
output CAB_O ; |
|
// period length |
real Tp ; |
|
reg `WB_ADDR_TYPE ADR_O; |
reg `WB_SEL_TYPE SEL_O; |
reg `WB_TAG_TYPE TAG_O; |
reg CYC_O; |
reg WE_O; |
reg `WB_DATA_TYPE DAT_O; |
reg CAB_O ; |
reg STB_O ; |
|
// variable used for indication on whether cycle was already started |
reg in_use ; |
|
// because of non-blocking assignments CYC_O is not sufficient indicator for cycle starting - this var is used in its place |
reg cycle_in_progress ; |
|
// same goes for CAB_O signal |
reg cab ; |
|
reg we ; |
|
task start_cycle ; |
input is_cab ; |
input write ; |
output ok ; // ok indicates to the caller that cycle was started succesfully - if not, caller must take appropriate action |
begin:main |
|
ok = 1 ; |
|
// just check if valid value is provided for CAB_O signal (no x's or z's allowed) |
if ( (is_cab !== 1'b0) && (is_cab !== 1'b1) ) |
begin |
$display("*E, invalid CAB value for cycle! Requested CAB_O value = %b, Time %t ", is_cab, $time) ; |
ok = 0 ; |
disable main ; |
end |
|
if ( (cycle_in_progress === 1) || (CYC_O === 1)) |
begin |
// cycle was previously started - allow cycle to continue if CAB and WE values match |
$display("*W, cycle already in progress when start_cycle routine was called! Time %t ", $time) ; |
if ((CAB_O !== is_cab) || (WE_O !== write) ) |
begin |
ok = 0 ; |
if ( is_cab === 1 ) |
$display("*E, cab cycle start attempted when non-cab cycle was in progress! Time %t", $time) ; |
else |
$display("*E, non-cab cycle start attempted when cab cycle was in progress! Time %t", $time) ; |
|
if ( we === 1 ) |
$display("*E, write cycle start attempted when read cycle was in progress! Time %t", $time) ; |
else |
$display("*E, read cycle start attempted when write cycle was in progress! Time %t", $time) ; |
|
disable main ; |
end |
end |
|
CYC_O <= #(Tp - `Tsetup) 1'b1 ; |
CAB_O <= #(Tp - `Tsetup) is_cab ; |
WE_O <= #(Tp - `Tsetup) write ; |
|
// this non-blocking assignments are made to internal variables, so read and write tasks can be called immediately after cycle start task |
cycle_in_progress = 1'b1 ; |
cab = is_cab ; |
we = write ; |
end |
endtask //start_cycle |
|
task end_cycle ; |
begin |
if ( CYC_O !== 1'b1 ) |
$display("*W, end_cycle routine called when CYC_O value was %b! Time %t ", CYC_O, $time) ; |
|
CYC_O <= #`Thold 1'b0 ; |
CAB_O <= #`Thold 1'b0 ; |
cycle_in_progress = 1'b0 ; |
end |
endtask //end_cycle |
|
task modify_cycle ; |
begin |
if ( CYC_O !== 1'b1 ) |
$display("*W, modify_cycle routine called when CYC_O value was %b! Time %t ", CYC_O, $time) ; |
|
we = ~we ; |
WE_O <= #(Tp - `Tsetup) we ; |
end |
endtask //modify_cycle |
|
task wbm_read ; |
input `READ_STIM_TYPE input_data ; |
inout `READ_RETURN_TYPE output_data ; |
reg `WB_ADDR_TYPE address ; |
reg `WB_DATA_TYPE data ; |
reg `WB_SEL_TYPE sel ; |
reg `WB_TAG_TYPE tag ; |
integer num_of_cyc ; |
begin:main |
output_data`TB_ERROR_BIT = 1'b0 ; |
|
// check if task was called before previous call to read or write finished |
if ( in_use === 1 ) |
begin |
$display("*E, wbm_read routine re-entered or called concurently with write routine! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( cycle_in_progress !== 1 ) |
begin |
$display("*E, wbm_read routine called without start_cycle routine being called first! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( we !== 0 ) |
begin |
$display("*E, wbm_read routine called after write cycle was started! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// this branch contains timing controls - claim the use of WISHBONE |
in_use = 1 ; |
|
num_of_cyc = `WAIT_FOR_RESPONSE ; |
|
// assign data outputs |
ADR_O <= #(Tp - `Tsetup) input_data`READ_ADDRESS ; |
SEL_O <= #(Tp - `Tsetup) input_data`READ_SEL ; |
TAG_O <= #(Tp - `Tsetup) input_data`READ_TAG_STIM ; |
|
// assign control output |
STB_O <= #(Tp - `Tsetup) 1'b1 ; |
|
output_data`CYC_ACK = 0 ; |
output_data`CYC_RTY = 0 ; |
output_data`CYC_ERR = 0 ; |
|
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
|
while ( (num_of_cyc > 0) && (output_data`CYC_RESPONSE === 0) ) |
begin |
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
num_of_cyc = num_of_cyc - 1 ; |
end |
|
output_data`READ_DATA = DAT_I ; |
output_data`READ_TAG_RET = TAG_I ; |
|
if ( output_data`CYC_RESPONSE === 0 ) |
begin |
|
$display("*W, Terminating read cycle because no response was received in %d cycles! Time %t ", `WAIT_FOR_RESPONSE, $time) ; |
end |
|
if ( output_data`CYC_ACK === 1 && output_data`CYC_RTY === 0 && output_data`CYC_ERR === 0 ) |
output_data`CYC_ACTUAL_TRANSFER = output_data`CYC_ACTUAL_TRANSFER + 1 ; |
|
STB_O <= #`Thold 1'b0 ; |
ADR_O <= #`Thold {`WB_ADDR_WIDTH{1'bx}} ; |
SEL_O <= #`Thold {`WB_SEL_WIDTH{1'bx}} ; |
TAG_O <= #`Thold {`WB_TAG_WIDTH{1'bx}} ; |
|
in_use = 0 ; |
end |
endtask // wbm_read |
|
task wbm_write ; |
input `WRITE_STIM_TYPE input_data ; |
inout `WRITE_RETURN_TYPE output_data ; |
reg `WB_ADDR_TYPE address ; |
reg `WB_DATA_TYPE data ; |
reg `WB_SEL_TYPE sel ; |
reg `WB_TAG_TYPE tag ; |
integer num_of_cyc ; |
begin:main |
output_data`TB_ERROR_BIT = 1'b0 ; |
|
// check if task was called before previous call to read or write finished |
if ( in_use === 1 ) |
begin |
$display("*E, wbm_write routine re-entered or called concurently with read routine! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( cycle_in_progress !== 1 ) |
begin |
$display("*E, wbm_write routine called without start_cycle routine being called first! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
if ( we !== 1 ) |
begin |
$display("*E, wbm_write routine after read cycle was started! Time %t ", $time) ; |
output_data`TB_ERROR_BIT = 1'b1 ; |
disable main ; |
end |
|
// this branch contains timing controls - claim the use of WISHBONE |
in_use = 1 ; |
|
num_of_cyc = `WAIT_FOR_RESPONSE ; |
|
ADR_O <= #(Tp - `Tsetup) input_data`WRITE_ADDRESS ; |
DAT_O <= #(Tp - `Tsetup) input_data`WRITE_DATA ; |
SEL_O <= #(Tp - `Tsetup) input_data`WRITE_SEL ; |
TAG_O <= #(Tp - `Tsetup) input_data`WRITE_TAG_STIM ; |
|
STB_O <= #(Tp - `Tsetup) 1'b1 ; |
|
output_data`CYC_ACK = 0 ; |
output_data`CYC_RTY = 0 ; |
output_data`CYC_ERR = 0 ; |
|
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
|
while ( (num_of_cyc > 0) && (output_data`CYC_RESPONSE === 0) ) |
begin |
@(posedge CLK_I) ; |
output_data`CYC_ACK = ACK_I ; |
output_data`CYC_RTY = RTY_I ; |
output_data`CYC_ERR = ERR_I ; |
num_of_cyc = num_of_cyc - 1 ; |
end |
|
output_data`WRITE_TAG_RET = TAG_I ; |
if ( output_data`CYC_RESPONSE === 0 ) |
begin |
$display("*W, Terminating write cycle because no response was received in %d cycles! Time %t ", `WAIT_FOR_RESPONSE, $time) ; |
end |
|
if ( output_data`CYC_ACK === 1 && output_data`CYC_RTY === 0 && output_data`CYC_ERR === 0 ) |
output_data`CYC_ACTUAL_TRANSFER = output_data`CYC_ACTUAL_TRANSFER + 1 ; |
|
ADR_O <= #`Thold {`WB_ADDR_WIDTH{1'bx}} ; |
DAT_O <= #`Thold {`WB_DATA_WIDTH{1'bx}} ; |
SEL_O <= #`Thold {`WB_SEL_WIDTH{1'bx}} ; |
TAG_O <= #`Thold {`WB_TAG_WIDTH{1'bx}} ; |
|
STB_O <= #`Thold 1'b0 ; |
|
in_use = 0 ; |
end |
endtask //wbm_write |
|
initial |
begin |
Tp = 1 / `WB_FREQ ; |
in_use = 0 ; |
cycle_in_progress = 0 ; |
cab = 0 ; |
ADR_O <= {`WB_ADDR_WIDTH{1'bx}} ; |
DAT_O <= {`WB_DATA_WIDTH{1'bx}} ; |
SEL_O <= {`WB_SEL_WIDTH{1'bx}} ; |
TAG_O <= {`WB_TAG_WIDTH{1'bx}} ; |
CYC_O <= 1'b0 ; |
STB_O <= 1'b0 ; |
CAB_O <= 1'b0 ; |
WE_O <= 1'b0 ; |
if ( `Tsetup > Tp || `Thold >= Tp ) |
begin |
$display("Either Tsetup or Thold values for WISHBONE BFMs are too large!") ; |
$stop ; |
end |
end |
|
endmodule |