aboutsummaryrefslogtreecommitdiff
path: root/models
diff options
context:
space:
mode:
authorWojciech Kosior <kwojtus@protonmail.com>2020-09-01 10:54:59 +0200
committerWojciech Kosior <kwojtus@protonmail.com>2020-09-01 11:04:22 +0200
commitee1f6c47e1eff920068f4bceaf604f9535a2e8a9 (patch)
tree580eb001a72601d254bb29cc348a529490f84808 /models
parentcd02ddff8886aa1db29f80d3cc5cf99a349d8258 (diff)
downloadAGH-engineering-thesis-ee1f6c47e1eff920068f4bceaf604f9535a2e8a9.tar.gz
AGH-engineering-thesis-ee1f6c47e1eff920068f4bceaf604f9535a2e8a9.zip
start anew
Diffstat (limited to 'models')
-rw-r--r--models/master.v223
-rw-r--r--models/slave.v146
-rw-r--r--models/vga_display.v203
3 files changed, 572 insertions, 0 deletions
diff --git a/models/master.v b/models/master.v
new file mode 100644
index 0000000..b728bda
--- /dev/null
+++ b/models/master.v
@@ -0,0 +1,223 @@
+/* A wishbone slave testing module (a "mock") */
+`default_nettype none
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`else
+
+module master_model
+ #(
+ parameter MASTER_NR = -1,
+ parameter OPERATIONS_FILE = "master_operations.mem",
+ parameter OPERATIONS_COUNT = 10
+ )
+ (
+ input wire ACK_I,
+ input wire CLK_I,
+ output wire [19:0] ADR_O,
+ input wire [15:0] DAT_I,
+ output wire [15:0] DAT_O,
+ input wire RST_I,
+ output wire STB_O,
+ output wire CYC_O,
+ output wire WE_O,
+ input wire STALL_I,
+
+ /* Non-wishbone */
+ output wire finished
+ );
+
+ parameter
+ OP_READ = 0,
+ OP_WRITE = 1,
+ OP_WAIT = 2, /* Keep CYC_O high, but STB_O low for 1 tick */
+ OP_DESELECT = 3; /* Drive CYC_O low for one tick */
+
+ /*
+ * Bits 39:36 specify type of the operation; bits 35:16 contain the
+ * address for read wnd write operations (may contain garbage otherwise);
+ * bits 15:0 contain data to write (for write operation) or expected data
+ * (for read operation) or are irrelevant (for other operations)
+ */
+ reg [39:0] operations [OPERATIONS_COUNT - 1 : 0];
+ /*
+ * This will allow us to check whether read operation returned proper data;
+ * bit 16 tells us whether the corresponding command was a read; if not,
+ * bits 15:0 don't matter; if yes bits 15:0 contain the data we should
+ * receive from that read operation
+ */
+ reg [16:0] expected_results [OPERATIONS_COUNT - 1 : 0];
+
+ integer i, j;
+
+ initial begin
+ $readmemh(OPERATIONS_FILE, operations, 0, OPERATIONS_COUNT - 1);
+
+ j = 0;
+ for (i = 0; i < OPERATIONS_COUNT; i++) begin
+ if (operations[i][39:36] == OP_READ ||
+ operations[i][39:36] == OP_WRITE) begin
+ if (operations[i][39:36] == OP_READ)
+ expected_results[j] <= {1'b1, operations[i][15:0]};
+ else
+ expected_results[j] <= {1'b0, 16'bx};
+
+ j++;
+ end
+ end
+ end
+
+ reg [31:0] operations_performed;
+ reg [31:0] commands_sent;
+ reg [31:0] commands_acknowledged;
+
+ /* Those are irrelevant if RST_I is high */
+ wire command_successful;
+ wire wait_successful;
+ wire deselect_successful;
+ wire [2:0] current_operation_type;
+ wire operation_successful;
+ wire [31:0] operations_performed_next_tick;
+ wire [39:0] operation_to_perform;
+ wire acknowledgement_successful;
+ wire [31:0] commands_sent_next_tick;
+ wire [31:0] commands_acknowledged_next_tick;
+ wire [31:0] acknowledgements_needed;
+
+ assign command_successful = CYC_O && STB_O && !STALL_I;
+ assign wait_successful = !STB_O && !STALL_I;
+ assign deselect_successful = !CYC_O;
+ assign current_operation_type = operations[operations_performed][39:36];
+ assign operation_successful
+ = operations_performed < OPERATIONS_COUNT &&
+ ((current_operation_type == OP_READ && command_successful) ||
+ (current_operation_type == OP_WRITE && command_successful) ||
+ (current_operation_type == OP_WAIT && wait_successful) ||
+ (current_operation_type == OP_DESELECT && deselect_successful));
+ assign operations_performed_next_tick
+ = operations_performed + operation_successful;
+ assign operation_to_perform = operations[operations_performed_next_tick];
+
+ assign commands_sent_next_tick = commands_sent + command_successful;
+ assign acknowledgement_successful
+ = CYC_O && ACK_I && commands_sent_next_tick > commands_acknowledged;
+ assign commands_acknowledged_next_tick
+ = commands_acknowledged + acknowledgement_successful;
+ assign acknowledgements_needed
+ = commands_sent_next_tick - commands_acknowledged_next_tick;
+
+ reg strobe;
+ assign STB_O = strobe;
+
+ reg cycle;
+ assign CYC_O = cycle;
+
+ reg write_enable;
+ assign WE_O = write_enable;
+
+ reg [15:0] output_data;
+ assign DAT_O = output_data;
+
+ reg [19:0] addr;
+ assign ADR_O = addr;
+
+ reg done;
+ assign finished = done;
+
+ initial begin
+ strobe <= 0;
+ cycle <= 0;
+ operations_performed <= 0;
+ commands_sent <= 0;
+ commands_acknowledged <= 0;
+ done <= 0;
+ end
+
+ always @ (posedge CLK_I) begin
+ if (RST_I) begin
+ strobe <= 0;
+ cycle <= 0;
+ operations_performed <= 0;
+ commands_sent <= 0;
+ commands_acknowledged <= 0;
+ done <= 0;
+ end else begin
+ /* debug messages */
+ if (command_successful) begin
+ case (current_operation_type)
+ OP_READ : begin
+ `DBG(("Master %0d: sent read command at h%x", MASTER_NR,
+ operations[operations_performed][35:16]));
+ end
+ OP_WRITE : begin
+ `DBG(("Master %0d: sent write command of h%x at h%x",
+ MASTER_NR, operations[operations_performed][15:0],
+ operations[operations_performed][35:16]));
+ end
+ default :
+ `MSG(("Master %0d: error: bug in test bench", MASTER_NR));
+ endcase // case (current_operation_type)
+ end // if (command_successful)
+
+ if (acknowledgement_successful) begin
+ if (expected_results[commands_acknowledged][16])
+ `DBG(("Master %0d: acknowledged read of h%x", MASTER_NR, DAT_I));
+ else
+ `DBG(("Master %0d: acknowledged write", MASTER_NR));
+ end
+
+ operations_performed <= operations_performed_next_tick;
+ commands_sent <= commands_sent_next_tick;
+ commands_acknowledged <= commands_acknowledged_next_tick;
+
+ if (operations_performed_next_tick == OPERATIONS_COUNT) begin
+ strobe <= 0;
+
+ if (acknowledgements_needed == 0) begin
+ cycle <= 0;
+ done <= 1;
+ end
+ end else begin
+ operations_performed <= operations_performed_next_tick;
+
+ case (operation_to_perform[39:36])
+ OP_READ : begin
+ cycle <= 1;
+ strobe <= 1;
+ write_enable <= 0;
+ addr <= operation_to_perform[35:16];
+ end
+ OP_WRITE : begin
+ cycle <= 1;
+ strobe <= 1;
+ write_enable <= 1;
+ addr <= operation_to_perform[35:16];
+ output_data <= operation_to_perform[15:0];
+ end
+ OP_WAIT : begin
+ cycle <= 1;
+ strobe <= 0;
+ end
+ OP_DESELECT : begin
+ cycle <= acknowledgements_needed > 0;
+ strobe <= 0;
+ end
+ endcase // case (operation_to_perform[39:36])
+ end // else: !if(operations_performed_next_tick == OPERATIONS_COUNT)
+
+ if (acknowledgement_successful) begin
+ if (expected_results[commands_acknowledged][15:0] !== DAT_I &&
+ expected_results[commands_acknowledged][16]) begin
+ `MSG(("Master %0d: error: read h%x instead of h%x",
+ MASTER_NR, DAT_I,
+ expected_results[commands_acknowledged][15:0]));
+ end
+ end
+ end // else: !if(RST_I)
+ end // always @ (posedge CLK_I)
+endmodule // master_model
+
+`endif // !`ifndef SIMULATION
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
diff --git a/models/vga_display.v b/models/vga_display.v
new file mode 100644
index 0000000..bb683e2
--- /dev/null
+++ b/models/vga_display.v
@@ -0,0 +1,203 @@
+`default_nettype none
+`timescale 1ns/1ns
+
+`include "messages.vh"
+
+`ifndef SIMULATION
+ `error_SIMULATION_not_defined
+; /* Cause syntax error */
+`endif
+
+module VGA_640_480_60Hz(
+ input wire horizontal_sync,
+ input wire vertical_sync,
+
+ input wire [2:0] red,
+ input wire [2:0] green,
+ input wire [2:0] blue,
+
+ output reg [9:0] image_writes
+ );
+ initial
+ image_writes <= 0;
+
+ parameter FRONT_PORCH = 0;
+ parameter SYNC_PULSE = 1;
+ parameter BACK_PORCH = 2;
+ parameter ACTIVE_VIDEO = 3;
+ parameter UNKNOWN_STATE = 4;
+
+ integer h_state;
+ integer v_state;
+ initial begin
+ h_state <= UNKNOWN_STATE;
+ v_state <= UNKNOWN_STATE;
+ end
+
+ parameter H_SYNC_POLARITY = 1'b0;
+ parameter H_FRONT_PORCH_LENGTH = 16;
+ parameter H_SYNC_PULSE_LENGTH = 96;
+ parameter H_BACK_PORCH_LENGTH = 48;
+ parameter H_ACTIVE_VIDEO_LENGTH = 640;
+
+ parameter V_SYNC_POLARITY = 1'b1;
+ parameter V_FRONT_PORCH_LENGTH = 10;
+ parameter V_SYNC_PULSE_LENGTH = 2;
+ parameter V_BACK_PORCH_LENGTH = 33;
+ parameter V_ACTIVE_VIDEO_LENGTH = 480;
+
+ reg [8:0] picture
+ [V_ACTIVE_VIDEO_LENGTH - 1 : 0]
+ [H_ACTIVE_VIDEO_LENGTH - 1 : 0];
+
+ integer h_counter, v_counter;
+
+ reg error;
+
+ wire unexpected_h_sync_pulse;
+ wire missing_h_sync_pulse;
+ assign unexpected_h_sync_pulse = horizontal_sync == H_SYNC_POLARITY &&
+ h_state != SYNC_PULSE;
+ assign missing_h_sync_pulse = horizontal_sync != H_SYNC_POLARITY &&
+ h_state == SYNC_PULSE;
+
+ wire unexpected_v_sync_pulse;
+ wire missing_v_sync_pulse;
+ assign unexpected_v_sync_pulse = vertical_sync == V_SYNC_POLARITY &&
+ v_state != SYNC_PULSE;
+ assign missing_v_sync_pulse = vertical_sync != V_SYNC_POLARITY &&
+ v_state == SYNC_PULSE;
+
+ wire new_line;
+ assign new_line = h_state == BACK_PORCH &&
+ h_counter + 1 == H_BACK_PORCH_LENGTH;
+
+ wire new_screen;
+ assign new_screen = v_state == BACK_PORCH &&
+ v_counter + 1 == V_BACK_PORCH_LENGTH && new_line;
+
+ always #40 begin
+ /* First, horizontal stuff */
+ if (unexpected_h_sync_pulse) begin
+ h_state <= SYNC_PULSE;
+ h_counter <= 1;
+
+ if (h_state != UNKNOWN_STATE) begin
+ `MSG(({"VGA: error: unexpected horizontal sync pulse signal ",
+ "(tick %0d; state %0d)"}, h_counter, h_state));
+ end
+ end else if (missing_h_sync_pulse) begin
+ h_state <= BACK_PORCH;
+ h_counter <= 1;
+
+ `MSG(({"VGA: error: missing expected horizontal sync pulse signal ",
+ "(tick %0d of sync pulse)"}, h_counter));
+ end else begin
+ case (h_state)
+ FRONT_PORCH : begin
+ if (h_counter + 1 != H_FRONT_PORCH_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= SYNC_PULSE;
+ h_counter <= 0;
+ end
+ end
+ SYNC_PULSE : begin
+ if (h_counter + 1 != H_SYNC_PULSE_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= BACK_PORCH;
+ h_counter <= 0;
+ end
+ end
+ BACK_PORCH : begin
+ if (h_counter + 1 != H_BACK_PORCH_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= ACTIVE_VIDEO;
+ h_counter <= 0;
+ end
+ end
+ ACTIVE_VIDEO : begin
+ if (v_state == ACTIVE_VIDEO) begin
+ picture[v_counter][h_counter] <= {red, green, blue};
+ end
+
+ if (h_counter + 1 != H_ACTIVE_VIDEO_LENGTH) begin
+ h_counter <= h_counter + 1;
+ end else begin
+ h_state <= FRONT_PORCH;
+ h_counter <= 0;
+ end
+ end // case: ACTIVE_VIDEO
+ endcase // case (h_state)
+ end // else: !if(missing_h_sync_pulse)
+
+
+ /* Vertical stuff is almost entirely the same as horizontal */
+ if (new_line) begin
+ if (unexpected_v_sync_pulse) begin
+ v_state <= SYNC_PULSE;
+ v_counter <= 1;
+
+ if (v_state != UNKNOWN_STATE) begin
+ `MSG(({"VGA: error: unexpected vertical sync pulse signal ",
+ "(line %0d; state %0d)"}, v_counter, v_state));
+ end
+ end else if (missing_v_sync_pulse) begin
+ v_state <= BACK_PORCH;
+ v_counter <= 1;
+
+ `MSG(({"VGA: error: missing expected vertical sync pulse signal ",
+ "(line %0d of sync pulse)"}, v_counter));
+ end else begin
+ case (v_state)
+ FRONT_PORCH : begin
+ if (v_counter + 1 != V_FRONT_PORCH_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= SYNC_PULSE;
+ v_counter <= 0;
+ end
+ end
+ SYNC_PULSE : begin
+ if (v_counter + 1 != V_SYNC_PULSE_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= BACK_PORCH;
+ v_counter <= 0;
+ end
+ end
+ BACK_PORCH : begin
+ if (v_counter + 1 != V_BACK_PORCH_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= ACTIVE_VIDEO;
+ v_counter <= 0;
+ end
+ end
+ ACTIVE_VIDEO : begin
+ if (v_counter + 1 != V_ACTIVE_VIDEO_LENGTH) begin
+ v_counter <= v_counter + 1;
+ end else begin
+ v_state <= FRONT_PORCH;
+ v_counter <= 0;
+
+ if (!error) begin
+ $writememb("VGAdump.mem", picture);
+ `DBG(("VGA: written VGAdump.mem"));
+ image_writes <= image_writes + 1;
+ end
+ end // else: !if(v_counter + 1 != V_ACTIVE_VIDEO_LENGTH)
+ end // case: ACTIVE_VIDEO
+ endcase // case (v_state)
+ end // else: !if(missing_v_sync_pulse)
+ end // if (new_line)
+
+ if (unexpected_h_sync_pulse || unexpected_h_sync_pulse ||
+ ((unexpected_v_sync_pulse || missing_v_sync_pulse) && new_line))
+ error <= 1;
+ else if (new_screen)
+ error <= 0;
+ end // always #40
+endmodule // VGA_640_480_60Hz