blob: a8f3d2c8b9079ca93418a3be116d21835ba04338 [file] [log] [blame] [edit]
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