aboutsummaryrefslogtreecommitdiff
path: root/models/slave.v
diff options
context:
space:
mode:
Diffstat (limited to 'models/slave.v')
-rw-r--r--models/slave.v146
1 files changed, 146 insertions, 0 deletions
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