| 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 |