| module RAM_TEST #( |
| parameter ADDR_WIDTH = 6, |
| parameter DATA_WIDTH = 1, |
| parameter IS_DUAL_PORT = 1, |
| parameter RANDOM_ITERATION_PER_LOOP = 10, |
| parameter LFSR_WIDTH = 16, |
| parameter LFSR_POLY = 16'hD008, |
| // How much to increment the address to move 1 full data width. |
| parameter ADDRESS_STEP = 1, |
| // Max address for this memory |
| parameter MAX_ADDRESS = 63 |
| ) ( |
| input rst, |
| input clk, |
| // Memory connection |
| input [DATA_WIDTH-1:0] read_data, |
| output reg [DATA_WIDTH-1:0] write_data, |
| output reg write_enable, |
| output reg [ADDR_WIDTH-1:0] read_address, |
| output reg [ADDR_WIDTH-1:0] write_address, |
| // INIT ROM |
| // When the memory is first initialized, it is expected to match the ROM |
| // port. |
| input [DATA_WIDTH-1:0] rom_read_data, |
| output reg [ADDR_WIDTH-1:0] rom_read_address, |
| // When an iteration is complete, success will be 1 for 1 cycle |
| output reg loop_complete, |
| // If an error occurs during a test, error will be 1 for each cycle |
| // with an error. |
| output reg error, |
| // error_state will contain the state of test FSM when the error occured. |
| output reg [7:0] error_state, |
| // error_address will be the read address where the error occurred. |
| output reg [ADDR_WIDTH-1:0] error_address, |
| // expected_data will be the read value expected. |
| output reg [DATA_WIDTH-1:0] expected_data, |
| // actual_data will be the read value read. |
| output reg [DATA_WIDTH-1:0] actual_data |
| ); |
| reg [7:0] state; |
| reg [DATA_WIDTH-1:0] test_value; |
| |
| reg [$clog2(RANDOM_ITERATION_PER_LOOP)-1:0] rand_count; |
| |
| localparam START = 8'd1, |
| VERIFY_INIT = 8'd2, |
| WRITE_ZEROS = 8'd3, |
| VERIFY_ZEROS = 8'd4, |
| WRITE_ONES = 8'd5, |
| VERIFY_ONES = 8'd6, |
| WRITE_10 = 8'd7, |
| VERIFY_10 = 8'd8, |
| WRITE_01 = 8'd9, |
| VERIFY_01 = 8'd10, |
| WRITE_RANDOM = 8'd11, |
| VERIFY_RANDOM = 8'd12, |
| RESTART_LOOP = 8'd13; |
| |
| reg pause; |
| reg lfsr_reset; |
| reg wait_for_lfsr_reset; |
| reg [LFSR_WIDTH-1:0] lfsr_seed; |
| reg [LFSR_WIDTH-1:0] start_lfsr_seed; |
| wire [LFSR_WIDTH-1:0] rand_data; |
| |
| LFSR #( |
| .WIDTH(LFSR_WIDTH), |
| .POLY(LFSR_POLY) |
| ) lfsr ( |
| .rst(lfsr_reset), |
| .clk(clk), |
| .seed(lfsr_seed), |
| .r(rand_data) |
| ); |
| |
| always @(posedge clk) begin |
| if(rst) begin |
| state <= START; |
| error <= 0; |
| write_enable <= 0; |
| lfsr_reset <= 1; |
| lfsr_seed <= 1; |
| end else begin |
| case(state) |
| START: begin |
| lfsr_reset <= 0; |
| state <= VERIFY_INIT; |
| read_address <= 0; |
| rom_read_address <= 0; |
| write_enable <= 0; |
| error <= 0; |
| end |
| VERIFY_INIT: begin |
| if(rom_read_data != read_data) begin |
| error <= 1; |
| error_state <= state; |
| error_address <= read_address; |
| expected_data <= rom_read_data; |
| actual_data <= read_data; |
| end else begin |
| error <= 0; |
| end |
| |
| if(read_address + ADDRESS_STEP <= MAX_ADDRESS) begin |
| read_address <= read_address + ADDRESS_STEP; |
| rom_read_address <= rom_read_address + ADDRESS_STEP; |
| end else begin |
| read_address <= 0; |
| write_address <= 0; |
| write_enable <= 1; |
| write_data <= {DATA_WIDTH{1'b0}}; |
| state <= WRITE_ZEROS; |
| end |
| end |
| WRITE_ZEROS: begin |
| loop_complete <= 0; |
| if(write_address + ADDRESS_STEP <= MAX_ADDRESS) begin |
| write_address <= write_address + ADDRESS_STEP; |
| end else begin |
| read_address <= 0; |
| write_address <= 0; |
| write_enable <= 0; |
| pause <= 1; |
| state <= VERIFY_ZEROS; |
| end |
| end |
| VERIFY_ZEROS: begin |
| if(pause) begin |
| pause <= 0; |
| end else begin |
| if(read_data != {DATA_WIDTH{1'b0}}) begin |
| error <= 1; |
| error_state <= state; |
| error_address <= read_address; |
| expected_data <= {DATA_WIDTH{1'b0}}; |
| actual_data <= read_data; |
| end else begin |
| error <= 0; |
| end |
| |
| if(read_address + ADDRESS_STEP <= MAX_ADDRESS) begin |
| read_address <= read_address + ADDRESS_STEP; |
| end else begin |
| read_address <= 0; |
| write_address <= 0; |
| write_enable <= 1; |
| write_data <= {DATA_WIDTH{1'b1}}; |
| state <= WRITE_ONES; |
| end |
| end |
| end |
| WRITE_ONES: begin |
| // If dual port, data should still be zero. |
| if(IS_DUAL_PORT) begin |
| if(read_data != {DATA_WIDTH{1'b0}}) begin |
| error <= 1; |
| error_state <= state; |
| error_address <= read_address; |
| expected_data <= {DATA_WIDTH{1'b0}}; |
| actual_data <= read_data; |
| end else begin |
| error <= 0; |
| end |
| end else begin |
| if(read_data != {DATA_WIDTH{1'b1}}) begin |
| error <= 1; |
| error_state <= state; |
| error_address <= read_address; |
| expected_data <= {DATA_WIDTH{1'b1}}; |
| actual_data <= read_data; |
| end else begin |
| error <= 0; |
| end |
| end |
| |
| if(write_address + ADDRESS_STEP <= MAX_ADDRESS) begin |
| read_address <= read_address + ADDRESS_STEP; |
| write_address <= write_address + ADDRESS_STEP; |
| end else begin |
| read_address <= 0; |
| write_address <= 0; |
| write_enable <= 0; |
| state <= VERIFY_ONES; |
| pause <= 1; |
| end |
| end |
| VERIFY_ONES: begin |
| if(pause) begin |
| pause <= 0; |
| end else begin |
| if(read_data != {DATA_WIDTH{1'b1}}) begin |
| error <= 1; |
| error_state <= state; |
| error_address <= read_address; |
| expected_data <= {DATA_WIDTH{1'b1}}; |
| actual_data <= read_data; |
| end else begin |
| error <= 0; |
| end |
| |
| if(read_address + ADDRESS_STEP <= MAX_ADDRESS) begin |
| read_address <= read_address + ADDRESS_STEP; |
| end else begin |
| state <= WRITE_RANDOM; |
| write_enable <= 1; |
| write_address <= 0; |
| lfsr_seed <= rand_data; |
| write_data <= rand_data[DATA_WIDTH-1:0]; |
| read_address <= 0; |
| end |
| end |
| end |
| WRITE_RANDOM: begin |
| if(write_address + ADDRESS_STEP <= MAX_ADDRESS) begin |
| write_address <= write_address + ADDRESS_STEP; |
| write_data <= rand_data[DATA_WIDTH-1:0]; |
| end else begin |
| read_address <= 0; |
| write_address <= 0; |
| write_enable <= 0; |
| state <= VERIFY_RANDOM; |
| |
| // Return LFSR to state at beginning of WRITE_RANDOM. |
| lfsr_reset <= 1; |
| wait_for_lfsr_reset <= 1; |
| end |
| end |
| VERIFY_RANDOM: begin |
| if(wait_for_lfsr_reset) begin |
| wait_for_lfsr_reset <= 0; |
| lfsr_reset <= 1; |
| end else begin |
| lfsr_reset <= 0; |
| if(read_data != rand_data[DATA_WIDTH-1:0]) begin |
| error <= 1; |
| error_state <= state; |
| error_address <= read_address; |
| expected_data <= rand_data[DATA_WIDTH-1:0]; |
| actual_data <= read_data; |
| end else begin |
| error <= 0; |
| end |
| |
| if(read_address + ADDRESS_STEP <= MAX_ADDRESS) begin |
| read_address <= read_address + ADDRESS_STEP; |
| end else begin |
| state <= RESTART_LOOP; |
| end |
| end |
| end |
| RESTART_LOOP: begin |
| loop_complete <= 1; |
| error <= 0; |
| read_address <= 0; |
| write_address <= 0; |
| write_enable <= 1; |
| write_data <= {DATA_WIDTH{1'b0}}; |
| state <= WRITE_ZEROS; |
| end |
| default: begin |
| state <= START; |
| error <= 0; |
| end |
| endcase |
| |
| end |
| end |
| endmodule |