/* * A wishbone slave testing module (a "mock") * * It performs a sequence of wishbone writes, reads and waits based on contents * of provided .mem file. It prints error messages whenever the value it reads * if different from the one it expects. * /* * A Wishbone SLAVE testing module (a "mock") * * | *WISHBONE DATASHEET* | * |---------------------------------------------------------------------------| * | *Description* | *Specification* | * |---------------------------------+-----------------------------------------| * | General description | mock MASTER model for test benches | * |---------------------------------+-----------------------------------------| * | Supported cycles | MASTER, pipelined READ/WRITE | * |---------------------------------+-----------------------------------------| * | Data port, size | parametrizable (WORD_SIZE bytes) | * | Data port, granularity | parametrizable | * | | (WORD_SIZE/SEL_LINES bytes) | * | Data port, maximum operand size | same as data port size | * | Data transfer ordering | Little endian | * | Data transfer ordering | Undefined | * | Address port, size | parametrizable (ADR_BITS bits) | * |---------------------------------+-----------------------------------------| * | Clock frequency constraints | NONE | * |---------------------------------+-----------------------------------------| * | | *Signal name* | *WISHBONE Equiv.* | * | |------------------+----------------------| * | | ACK_I | ACK_I | * | | ADR_O | ADR_O() | * | Supported signal list and cross | CLK_I | CLK_I | * | reference to equivalent | DAT_I | DAT_I() | * | WISHBONE signals | DAT_O | DAT_O() | * | | SEL_O | SEL_O | * | | STB_O | STB_O | * | | CYC_O | CYC_O | * | | WE_O | WE_O | * | | RST_I | RST_I | * | | STALL_I | STALL_I | * |---------------------------------+-----------------------------------------| * | Special requirements | Should only be used in simulation, | * | | not synthesizable. | */ `default_nettype none `include "messages.vh" `ifndef SIMULATION `error_SIMULATION_not_defined ; /* Cause syntax error */ `endif module master_model #( parameter MASTER_NR = -1, parameter WORD_SIZE = 2, /* in bytes */ parameter SEL_LINES = 1, parameter ADR_BITS = 20, parameter OPERATIONS_FILE = "master_operations.mem", parameter OPERATIONS_COUNT = 10 ) ( input wire ACK_I, input wire CLK_I, output wire [ADR_BITS - 1 : 0] ADR_O, input wire [8*WORD_SIZE - 1 : 0] DAT_I, output wire [8*WORD_SIZE - 1 : 0] DAT_O, output wire [SEL_LINES - 1 : 0] SEL_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 WORD_BITS = 8 * WORD_SIZE; parameter GRANULARITY = WORD_BITS / SEL_LINES; /* in bits */ 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 */ /* See below what we need this for */ parameter BIGGEST_WIDTH = ADR_BITS > WORD_BITS ? ADR_BITS : WORD_BITS; /* * Contents of this array determine, what this master will do. * Each (4*n)th element denotes type of operation number n. * (4*n+1)th element denotes address to use, (4*n+2)th element denotes * data to use and (4*n+3)th element denotes SEL_O mask to use. */ reg [BIGGEST_WIDTH - 1 : 0] operations [4*OPERATIONS_COUNT - 1 : 0]; /* Arrays used for verifying read reaults */ reg was_read [OPERATIONS_COUNT - 1 : 0]; reg [SEL_LINES - 1 : 0] SEL_mask [OPERATIONS_COUNT - 1 : 0]; reg [WORD_BITS - 1 : 0] expected_data [OPERATIONS_COUNT - 1 : 0]; integer i, j; initial begin $readmemh(OPERATIONS_FILE, operations, 0, 4*OPERATIONS_COUNT - 1); j = 0; for (i = 0; i < OPERATIONS_COUNT; i++) begin if (operations[4*i][1:0] == OP_READ) begin was_read[j] <= 1; expected_data[j] <= operations[4*i + 2][WORD_BITS - 1 : 0]; SEL_mask[j] <= operations[4*i + 3][SEL_LINES - 1 : 0]; j++; end if (operations[4*i][1:0] == OP_WRITE) begin was_read[j] <= 0; j++; end end // for (i = 0; i < OPERATIONS_COUNT; i++) end // initial begin 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 [1:0] current_op_type; wire [ADR_BITS - 1 : 0] current_op_adr; wire [WORD_BITS - 1 : 0] current_op_data; wire [SEL_LINES - 1 : 0] current_op_mask; wire operation_successful; wire [31:0] operations_performed_next_tick; 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_op_type = operations[4*operations_performed][1:0]; assign current_op_adr = operations[4*operations_performed + 1][ADR_BITS - 1 : 0]; assign current_op_data = operations[4*operations_performed + 2][WORD_BITS - 1 : 0]; assign current_op_mask = operations[4*operations_performed + 3][SEL_LINES - 1 : 0]; assign operation_successful = operations_performed < OPERATIONS_COUNT && ((current_op_type == OP_READ && command_successful) || (current_op_type == OP_WRITE && command_successful) || (current_op_type == OP_WAIT && wait_successful) || (current_op_type == OP_DESELECT && deselect_successful)); assign operations_performed_next_tick = operations_performed + operation_successful; 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; wire [31:0] idx_to_use; wire [1:0] next_op_type; wire [ADR_BITS - 1 : 0] next_op_adr; wire [WORD_BITS - 1 : 0] next_op_data; wire [SEL_LINES - 1 : 0] next_op_mask; assign idx_to_use = operations_performed_next_tick; assign next_op_type = operations[4*idx_to_use][1:0]; assign next_op_adr = operations[4*idx_to_use + 1][ADR_BITS - 1 : 0]; assign next_op_data = operations[4*idx_to_use + 2][WORD_BITS - 1 : 0]; assign next_op_mask = operations[4*idx_to_use + 3][SEL_LINES - 1 : 0]; /* Drive the outputs */ reg strobe; assign STB_O = strobe; reg cycle; assign CYC_O = cycle; reg write_enable; assign WE_O = write_enable; reg [WORD_BITS - 1 : 0] output_data; assign DAT_O = output_data; reg [SEL_LINES - 1 : 0] mask; assign SEL_O = mask; reg [ADR_BITS - 1 : 0] addr; assign ADR_O = addr; reg done; assign finished = done; reg error; 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_op_type) OP_READ : begin `DBG(("Master %0d: sent read command at h%x", MASTER_NR, current_op_adr)); end OP_WRITE : begin `DBG(("Master %0d: sent write command of h%x at h%x", MASTER_NR, current_op_data, current_op_adr)); end default : `MSG(("Master %0d: error: bug in test bench", MASTER_NR)); endcase // case (current_op_type) end // if (command_successful) if (acknowledgement_successful) begin if (was_read[commands_acknowledged]) `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 (next_op_type) OP_READ : begin cycle <= 1; strobe <= 1; write_enable <= 0; mask <= next_op_mask; addr <= next_op_adr; end OP_WRITE : begin cycle <= 1; strobe <= 1; write_enable <= 1; mask <= next_op_mask; addr <= next_op_adr; output_data <= next_op_data; end OP_WAIT : begin cycle <= 1; strobe <= 0; end OP_DESELECT : begin cycle <= acknowledgements_needed > 0; strobe <= 0; end endcase // case (next_op_type) end // else: !if(operations_performed_next_tick == OPERATIONS_COUNT) if (acknowledgement_successful && was_read[commands_acknowledged]) begin error = 0; for (i = 0; i < WORD_BITS; i++) begin if (SEL_mask[commands_acknowledged][i/GRANULARITY]) begin if (DAT_I[i] != expected_data[commands_acknowledged][i]) error = 1; end end if (error) begin `MSG(("Master %0d: error: read h%x instead of h%x (%b)", MASTER_NR, DAT_I, expected_data[commands_acknowledged], SEL_mask[commands_acknowledged])); end end // if (acknowledgement_successful &&... end // else: !if(RST_I) end // always @ (posedge CLK_I) endmodule // master_model