From ee1f6c47e1eff920068f4bceaf604f9535a2e8a9 Mon Sep 17 00:00:00 2001 From: Wojciech Kosior Date: Tue, 1 Sep 2020 10:54:59 +0200 Subject: start anew --- models/slave.v | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 models/slave.v (limited to 'models/slave.v') diff --git a/models/slave.v b/models/slave.v new file mode 100644 index 0000000..bae3485 --- /dev/null +++ b/models/slave.v @@ -0,0 +1,146 @@ +/* A wishbone slave testing module (a "mock") */ +`default_nettype none + +`include "messages.vh" + +`ifndef SIMULATION + `error_SIMULATION_not_defined +; /* Cause syntax error */ +`else + +module memory_slave_model + #( + parameter SLAVE_NR = -1, + /* Changing the following 3 allows us to make it function as ROM */ + parameter WRITABLE = 1, + parameter WORDS_TO_INITIALIZE = 0, + parameter INITIAL_CONTENTS_FILE = "some_file.mem" + ) + ( + output wire ACK_O, + input wire CLK_I, + input wire [17:0] ADR_I, + input wire [15:0] DAT_I, + output wire [15:0] DAT_O, + input wire RST_I, + input wire STB_I, + input wire WE_I, + output wire STALL_O + ); + + /* + * A simple memory slave should be most useful for testing purposes; + * WARNING! The 'memory' variable might be referenced from outside the module + * by testbench code - be careful when changing or removing it + */ + reg [15:0] memory [2**18 - 1 : 0]; + + integer seed; /* For random stall times and acknowledge times */ + + parameter MAX_STALL_TIME = 7; + parameter MAX_ACK_WAIT_TIME = 7; + + reg [2:0] stall_time_left; + reg [2:0] acknowledge_time_left; + + /* + * Bit 34 contains latched WE_I; bits 33:16 contain latched ADR_I; + * bits 15:0 contain latched DAT_I + */ + reg [34:0] command_pipeline [15:0]; + reg [3:0] pipeline_oldest_element; + reg [4:0] pipeline_elements_count; + wire [3:0] pipeline_index_to_insert; + assign pipeline_index_to_insert = (pipeline_oldest_element + + pipeline_elements_count) % 16; + + reg stall; + + /* Those are irrelevant if RST_I is high */ + wire pipeline_space_left; + wire can_accept; + wire new_command_accepted; + wire command_available_for_acknowledging; + wire command_acknowledged; + wire [34:0] incoming_command; + wire [34:0] command_to_process; + + assign pipeline_space_left = pipeline_elements_count < 16; + assign can_accept = pipeline_space_left && stall_time_left == 0; + assign new_command_accepted = STB_I && can_accept; + assign command_available_for_acknowledging = pipeline_elements_count || + new_command_accepted; + assign command_acknowledged = acknowledge_time_left == 0 && + command_available_for_acknowledging; + assign incoming_command = STB_I ? {WE_I, ADR_I, DAT_I} : 35'bx; + assign command_to_process = pipeline_elements_count ? + command_pipeline[pipeline_oldest_element] : + incoming_command; + + /* Finally, drive the outputs */ + + /* + * command_to_process[34] is low when it's a read command; only drive data + * outputs for read commands + */ + assign DAT_O = (command_acknowledged && !command_to_process[34]) ? + memory[command_to_process[33:16]] : 16'bx; + + + assign STALL_O = !can_accept; + + assign ACK_O = command_acknowledged; + + initial begin + pipeline_oldest_element <= 0; + pipeline_elements_count <= 0; + seed <= SLAVE_NR; + stall_time_left <= 0; + acknowledge_time_left <= 0; + + if (WORDS_TO_INITIALIZE) + $readmemb(INITIAL_CONTENTS_FILE, memory, 0, WORDS_TO_INITIALIZE - 1); + end + + always @ (posedge CLK_I) begin + if (RST_I) begin + pipeline_oldest_element <= 0; + pipeline_elements_count <= 0; + end else begin + if (new_command_accepted) begin + stall_time_left <= $urandom(seed) % (MAX_STALL_TIME + 1); + command_pipeline[pipeline_index_to_insert] = incoming_command; + end else begin + if (stall_time_left) + stall_time_left <= stall_time_left - 1; + end + + if (command_acknowledged) begin + acknowledge_time_left <= $urandom(seed) % (MAX_ACK_WAIT_TIME + 1); + pipeline_oldest_element <= pipeline_oldest_element + 1; + + if (command_to_process[34]) begin /* Write command */ + if (WRITABLE) begin + memory[command_to_process[33:16]] <= command_to_process[15:0]; + `DBG(("Slave %0d: write of h%x at h%x", SLAVE_NR, + command_to_process[15:0], command_to_process[31:16])); + end else begin + `DBG(({"Slave %0d: error: write of h%x at h%x ", + "(read-only) memory"}, SLAVE_NR, + command_to_process[15:0], command_to_process[31:16])); + end + end else begin /* Read command */ + `DBG(("Slave %0d: read of h%x at h%x", SLAVE_NR, + DAT_O, command_to_process[31:16])); + end + end else if (command_available_for_acknowledging) begin + acknowledge_time_left <= acknowledge_time_left - 1; + end + + pipeline_elements_count <= pipeline_elements_count + + new_command_accepted - command_acknowledged; + end + end +endmodule // memory_slave_model + +`endif // !`ifndef SIMULATION -- cgit v1.2.3