2024-12-29 05:18:37 +01:00
|
|
|
`default_nettype none
|
|
|
|
|
`timescale 1ns / 1ps
|
|
|
|
|
|
|
|
|
|
module spd_reader (
|
|
|
|
|
// clock and reset
|
|
|
|
|
input wire i_clk,
|
|
|
|
|
input wire i_rst_n,
|
|
|
|
|
// i2c interface
|
|
|
|
|
inout wire i2c_scl,
|
2024-12-29 07:47:57 +01:00
|
|
|
inout wire i2c_sda,
|
|
|
|
|
// state of spd reader
|
|
|
|
|
(* mark_debug = "true" *) output reg find_i2c_address_done,
|
|
|
|
|
(* mark_debug = "true" *) output reg read_spd_done
|
2024-12-29 05:18:37 +01:00
|
|
|
// uart interface
|
|
|
|
|
// input uart_rx,
|
|
|
|
|
// output uart_tx
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// byte 2: DRAM Device Type (DDR3 SDRAM = 0x0B)
|
|
|
|
|
// byte 3: Module Type (SO-DIMM = 0x03)
|
|
|
|
|
// byte 4: SDRAM Density and Banks ([6:4] = BA_BITS, [3:0] = SDRAM capacity)
|
|
|
|
|
// byte 5: SDRAM Addressing ([5:3] = Row Addr , [2:0] = Column Addr)
|
|
|
|
|
// byte 7: Module Organization ([5:3] = Ranks , Device Width = [2:0])
|
|
|
|
|
// byte 8: Module Memory Bus Width ([2:0] = Bus Width)
|
|
|
|
|
// byte 10,11: Medium Timebase (MTB) Dividend (0x01), Medium Timebase (MTB) Divisor (0x08 = 0.125ns , 0x10 = 0.0625ns) (tXX = tXX(MTB) * MTB)
|
|
|
|
|
// byte 12: SDRAM Minimum Cycle Time tCK
|
|
|
|
|
|
|
|
|
|
localparam I2C_ADDRESS = 7'h30;
|
|
|
|
|
localparam IDLE = 0,
|
|
|
|
|
READ_ADDRESS = 1,
|
2024-12-29 07:47:57 +01:00
|
|
|
READ_BYTE = 1,
|
2024-12-29 05:18:37 +01:00
|
|
|
WAIT_ACK = 2;
|
|
|
|
|
(* mark_debug = "true" *) reg[1:0] state_find_i2c_address;
|
|
|
|
|
(* mark_debug = "true" *) reg[6:0] i2c_address;
|
|
|
|
|
|
|
|
|
|
// i2c master interface
|
|
|
|
|
reg enable;
|
|
|
|
|
reg read_write;
|
|
|
|
|
reg[7:0] register_address;
|
|
|
|
|
reg[6:0] device_address;
|
|
|
|
|
wire[7:0] miso_data;
|
|
|
|
|
wire busy;
|
|
|
|
|
wire slave_nack;
|
2024-12-29 07:47:57 +01:00
|
|
|
(* mark_debug = "true" *) reg nack_unexpected_err;
|
|
|
|
|
(* mark_debug = "true" *) reg[2:0] state_read_spd;
|
|
|
|
|
(* mark_debug = "true" *) reg[5:0] byte_address; // read until byte 63
|
|
|
|
|
(* mark_debug = "true" *) reg[7:0] byte_data[63:0];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// initialize in case fpga starts with no reset
|
|
|
|
|
initial begin
|
|
|
|
|
state_find_i2c_address = IDLE;
|
|
|
|
|
find_i2c_address_done = 0;
|
|
|
|
|
enable = 1'b0;
|
|
|
|
|
read_write = 1'b0;
|
|
|
|
|
register_address = 8'd0;
|
|
|
|
|
i2c_address = 7'd0;
|
|
|
|
|
read_spd_done = 1'b0;
|
|
|
|
|
nack_unexpected_err = 1'b0;
|
|
|
|
|
state_read_spd = IDLE;
|
|
|
|
|
byte_address = 6'h00;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
// main FSM
|
2024-12-29 05:18:37 +01:00
|
|
|
always @(posedge i_clk, negedge i_rst_n) begin
|
|
|
|
|
if(!i_rst_n) begin
|
|
|
|
|
state_find_i2c_address <= IDLE;
|
|
|
|
|
find_i2c_address_done <= 0;
|
|
|
|
|
enable <= 1'b0;
|
|
|
|
|
read_write <= 1'b0;
|
|
|
|
|
register_address <= 8'd0;
|
|
|
|
|
i2c_address <= 7'd0;
|
2024-12-29 07:47:57 +01:00
|
|
|
read_spd_done <= 1'b0;
|
|
|
|
|
nack_unexpected_err <= 1'b0;
|
|
|
|
|
state_read_spd <= IDLE;
|
|
|
|
|
byte_address <= 6'h00;
|
2024-12-29 05:18:37 +01:00
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
// Find I2C Address of SPD
|
|
|
|
|
case(state_find_i2c_address)
|
|
|
|
|
IDLE: if(!find_i2c_address_done) begin
|
|
|
|
|
state_find_i2c_address <= READ_ADDRESS;
|
2024-12-29 07:47:57 +01:00
|
|
|
i2c_address <= 7'h01; // start brute force find i2c address from 1 (0 might be general call)
|
2024-12-29 05:18:37 +01:00
|
|
|
end
|
|
|
|
|
READ_ADDRESS: if(!busy) begin
|
|
|
|
|
enable <= 1'b1;
|
|
|
|
|
read_write <= 1'b1; // read i2c
|
|
|
|
|
register_address <= 8'h00; // just always read byte 0
|
|
|
|
|
device_address <= i2c_address;
|
|
|
|
|
state_find_i2c_address <= WAIT_ACK;
|
|
|
|
|
end
|
|
|
|
|
WAIT_ACK: if(!busy && !enable) begin
|
|
|
|
|
if(slave_nack) begin // if wrong i2c_address
|
|
|
|
|
i2c_address <= i2c_address + 1; // increment i2c address
|
|
|
|
|
state_find_i2c_address <= READ_ADDRESS;
|
|
|
|
|
end
|
|
|
|
|
else begin // I2C acks so i2c_address is correct!
|
|
|
|
|
state_find_i2c_address <= IDLE;
|
|
|
|
|
find_i2c_address_done <= 1'b1;
|
|
|
|
|
end
|
2024-12-29 07:47:57 +01:00
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
enable <= 1'b0;
|
|
|
|
|
end
|
|
|
|
|
default: state_find_i2c_address <= IDLE;
|
|
|
|
|
endcase
|
|
|
|
|
|
|
|
|
|
// read bytes from SPD
|
|
|
|
|
case(state_read_spd)
|
|
|
|
|
IDLE: if(find_i2c_address_done && !read_spd_done && !nack_unexpected_err) begin // start read SPD only once i2c address is found
|
|
|
|
|
state_read_spd <= READ_BYTE;
|
|
|
|
|
byte_address <= 6'h00; // start read from byte 0
|
2024-12-29 05:18:37 +01:00
|
|
|
end
|
2024-12-29 07:47:57 +01:00
|
|
|
READ_BYTE: if(!busy) begin // if not busy, send i2c read transaction
|
|
|
|
|
enable <= 1'b1;
|
|
|
|
|
read_write <= 1'b1; // read i2c
|
|
|
|
|
register_address <= {2'b00,byte_address};
|
|
|
|
|
device_address <= i2c_address;
|
|
|
|
|
state_read_spd <= WAIT_ACK;
|
2024-12-29 05:18:37 +01:00
|
|
|
end
|
2024-12-29 07:47:57 +01:00
|
|
|
WAIT_ACK: if(!busy && !enable) begin
|
|
|
|
|
if(slave_nack) begin // if i2c_address NACKS, then something is wrong, raise nack_unexpected_err
|
|
|
|
|
nack_unexpected_err <= 1'b1;
|
|
|
|
|
state_read_spd <= IDLE;
|
|
|
|
|
end
|
|
|
|
|
else begin // I2C acks so store the received byte
|
|
|
|
|
byte_data[byte_address] <= miso_data;
|
|
|
|
|
state_read_spd <= READ_BYTE;
|
|
|
|
|
byte_address <= byte_address + 1;
|
|
|
|
|
if(byte_address == 63) begin
|
|
|
|
|
read_spd_done <= 1'b1;
|
|
|
|
|
state_read_spd <= IDLE;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
else begin
|
|
|
|
|
enable <= 1'b0;
|
|
|
|
|
end
|
2024-12-29 05:18:37 +01:00
|
|
|
endcase
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
// module instantiations
|
|
|
|
|
i2c_master #(.DATA_WIDTH(8),.REGISTER_WIDTH(8),.ADDRESS_WIDTH(7))
|
|
|
|
|
i2c_master_inst(
|
|
|
|
|
.clock (i_clk),
|
|
|
|
|
.reset_n (i_rst_n),
|
|
|
|
|
.enable (enable),
|
|
|
|
|
.read_write (read_write),
|
|
|
|
|
.mosi_data (8'd0),
|
|
|
|
|
.register_address (register_address),
|
|
|
|
|
.device_address (device_address),
|
|
|
|
|
.divider (249), // 100MHz/(4*(249+1)) = 100KHz
|
|
|
|
|
|
|
|
|
|
.miso_data (miso_data),
|
|
|
|
|
.busy (busy),
|
|
|
|
|
|
|
|
|
|
.external_serial_data (i2c_sda),
|
|
|
|
|
.external_serial_clock (i2c_scl),
|
|
|
|
|
.slave_nack (slave_nack)
|
|
|
|
|
);
|
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
|
|
|