Untitled
Anonymous
plain_text
05/01/2026 2:24 AM
11.1 KB
14
Indexable
`timescale 1ns / 1ps
module I2C_RECEIVER (
input wire CLK,
input wire RSTN,
input wire I2C_SCL,
input wire I2C_SDA,
input wire TRIG,
output reg VALID,
output reg [2:0] IDX0,
output reg [2:0] IDX1,
output reg [3:0] NUM0,
output reg [3:0] NUM1,
output reg EMPTY
);
// =========================================================
// Synchronize SCL/SDA into CLK domain
// Use negedge CLK to avoid post-synthesis timing issue
// when TB changes I2C_SCL/I2C_SDA near posedge CLK.
// =========================================================
(* DONT_TOUCH = "true" *) reg scl_d0, scl_d1;
(* DONT_TOUCH = "true" *) reg sda_d0, sda_d1;
wire scl_edge;
assign scl_edge = (scl_d0 ^ scl_d1);
// negedge input sampler
always @(negedge CLK or negedge RSTN) begin
if (!RSTN) begin
scl_d0 <= 1'b0;
scl_d1 <= 1'b0;
sda_d0 <= 1'b0;
sda_d1 <= 1'b0;
end
else begin
scl_d0 <= I2C_SCL;
scl_d1 <= scl_d0;
sda_d0 <= I2C_SDA;
sda_d1 <= sda_d0;
end
end
// =========================================================
// Delay sampling by one CLK after SCL edge
// This avoids SDA glitch around SCL toggle
// =========================================================
reg sample_pending;
// =========================================================
// Receive 8-bit frame
// frame = {header[3:0], data[3:0]}, MSB first
// =========================================================
reg [7:0] shift_reg;
reg [2:0] bit_cnt;
reg [7:0] frame_now;
reg [3:0] header_now;
reg signed [3:0] data_now;
// =========================================================
// Address list
// header == 0000 means data is device ID
// =========================================================
reg [3:0] addr_list [0:3];
reg [2:0] addr_cnt;
// =========================================================
// Number count
// =========================================================
reg [3:0] num_cnt;
// =========================================================
// Top-2 signed number
// =========================================================
reg signed [3:0] max0_num;
reg signed [3:0] max1_num;
reg [2:0] max0_idx;
reg [2:0] max1_idx;
reg has0;
reg has1;
reg signed [3:0] new_num;
reg [2:0] new_idx;
reg match_addr;
reg valid_hold;
integer i;
// =========================================================
// Main sequential logic
// =========================================================
always @(posedge CLK or negedge RSTN) begin
if (!RSTN) begin
sample_pending <= 1'b0;
shift_reg <= 8'd0;
bit_cnt <= 3'd0;
frame_now <= 8'd0;
header_now <= 4'd0;
data_now <= 4'sd0;
addr_cnt <= 3'd0;
num_cnt <= 4'd0;
for (i = 0; i < 4; i = i + 1) begin
addr_list[i] <= 4'd0;
end
max0_num <= 4'sd0;
max1_num <= 4'sd0;
max0_idx <= 3'd0;
max1_idx <= 3'd0;
has0 <= 1'b0;
has1 <= 1'b0;
VALID <= 1'b0;
valid_hold <= 1'b0;
IDX0 <= 3'd0;
IDX1 <= 3'd0;
NUM0 <= 4'd0;
NUM1 <= 4'd0;
EMPTY <= 1'b1;
end
else begin
// -------------------------------------------------
// VALID behavior
// Keep same as your behavior-correct version.
// -------------------------------------------------
VALID <= 1'b0;
if (TRIG) begin
VALID <= 1'b1;
valid_hold <= 1'b1;
end
else if (valid_hold) begin
VALID <= 1'b1;
valid_hold <= 1'b0;
end
// -------------------------------------------------
// Detect SCL toggle first.
// Do not sample immediately.
// Sample SDA one CLK later.
// -------------------------------------------------
if (scl_edge) begin
sample_pending <= 1'b1;
end
else if (sample_pending) begin
sample_pending <= 1'b0;
// =================================================
// Receive one stable SDA bit
// =================================================
shift_reg <= {shift_reg[6:0], sda_d1};
if (bit_cnt == 3'd7) begin
bit_cnt <= 3'd0;
frame_now = {shift_reg[6:0], sda_d1};
header_now = frame_now[7:4];
data_now = frame_now[3:0];
// ---------------------------------------------
// Address frame
// header == 0000
// ---------------------------------------------
if (header_now == 4'b0000) begin
if (addr_cnt < 3'd4) begin
addr_list[addr_cnt] <= data_now[3:0];
addr_cnt <= addr_cnt + 3'd1;
end
end
// ---------------------------------------------
// Data frame
// header must match address list
// ---------------------------------------------
else begin
match_addr = 1'b0;
for (i = 0; i < 4; i = i + 1) begin
if ((i < addr_cnt) && (header_now == addr_list[i])) begin
match_addr = 1'b1;
end
end
if (match_addr && (num_cnt < 4'd8)) begin
new_num = data_now;
new_idx = num_cnt[2:0];
num_cnt <= num_cnt + 4'd1;
// signed comparison
// equal value does not replace,
// because smaller index wins.
if ((!has0) || (new_num > max0_num)) begin
max1_num <= max0_num;
max1_idx <= max0_idx;
has1 <= has0;
max0_num <= new_num;
max0_idx <= new_idx;
has0 <= 1'b1;
end
else if ((!has1) || (new_num > max1_num)) begin
max1_num <= new_num;
max1_idx <= new_idx;
has1 <= 1'b1;
end
end
end
end
else begin
bit_cnt <= bit_cnt + 3'd1;
end
end
// =================================================
// Keep result outputs updated continuously
// Same as behavior-correct version.
// =================================================
if (!has1) begin
EMPTY <= 1'b1;
if (has0) begin
IDX0 <= max0_idx;
NUM0 <= max0_num[3:0];
end
else begin
IDX0 <= 3'd0;
NUM0 <= 4'd0;
end
IDX1 <= 3'd0;
NUM1 <= 4'd0;
end
else begin
EMPTY <= 1'b0;
IDX0 <= max0_idx;
NUM0 <= max0_num[3:0];
IDX1 <= max1_idx;
NUM1 <= max1_num[3:0];
end
end
end
endmoduleEditor is loading...
Leave a Comment