EIE4-FYP/rtl/can.sv

140 lines
4.8 KiB
Systemverilog
Raw Permalink Normal View History

`default_nettype none
module can
( input var i_clk
, input var i_rst_n
, input var [10:0] i_id
, input var [10:0] i_mask
, input var i_rx
, output var o_tx
, output var [10:0] o_id
, output var [ 7:0] o_data0
, output var [ 7:0] o_data1
, output var [ 7:0] o_data2
, output var [ 7:0] o_data3
, output var [ 7:0] o_data4
, output var [ 7:0] o_data5
, output var [ 7:0] o_data6
, output var [ 7:0] o_data7
, output var o_pulse
);
logic rx;
always_ff @(posedge i_clk) // Capture i_rx on rising edge of i_clk
rx <= i_rx;
logic rx_p;
always_ff @(posedge i_clk) // Store previous value of i_rx
rx_p <= rx;
logic rx_r;
always_comb rx_r = rx && !rx_p; // Detect rising edge of rx
logic [8:0] div_1m;
always_ff @(posedge i_clk)
if (!i_rst_n) div_1m <= 9'd0; // Reset
else if (rx_r) div_1m <= 9'd1; // Align to 1 -> 0 transition
else if (div_1m == 9'd383) div_1m <= 9'd0; // Wrap at 384
else div_1m <= div_1m + 1; // Increment
logic bit_t_75;
always_ff @(posedge i_clk) bit_t_75 <= (div_1m == 9'd287); // 75% of bit time
logic eof;
logic stuff_bit;
logic [2:0] stuff_count;
logic [98:0] rx_shift;
always_ff @(posedge i_clk) // Store incoming bits in a shift register
if (!i_rst_n || eof) rx_shift <= '1; // Reset or End-of-Frame
else if (bit_t_75 && !stuff_bit) rx_shift <= {rx_shift[97:0], rx};
// Shift in next bit at 75% of bit time if not a stuff bit
always_comb stuff_bit = (stuff_count == 3'd4); // Detect bit stuffing
logic rx_prev;
always_ff @(posedge i_clk) if (bit_t_75) rx_prev <= rx;
always_ff @(posedge i_clk)
if (!i_rst_n) stuff_count <= 3'd0; // Reset
else if (bit_t_75 && stuff_bit) stuff_count <= 3'd0; // Stuffed bit
else if (bit_t_75 && (rx_prev == rx)) stuff_count <= stuff_count + 1; // Same bit, increment count
else if (bit_t_75) stuff_count <= 3'd0; // Different bit, reset count
logic [6:0] det_eof;
always_ff @(posedge i_clk)
if (!i_rst_n) det_eof <= 7'd0; // Reset
else if (bit_t_75) det_eof <= {det_eof[5:0], rx}; // Shift in next bit at 75% of bit time
always_ff @(posedge i_clk) eof <= &{det_eof}; // Detect EOF (7 consecutive recessive/1 bits)
// Break out rx_shift into individual signals
logic b_sof;
logic [10:0] b_id;
logic b_rtr;
logic b_ide;
logic b_r0;
logic [ 3:0] b_dlc;
logic [63:0] b_data;
logic [14:0] b_crc;
logic b_crc_del;
always_comb b_sof = rx_shift[98];
always_comb b_id = rx_shift[97:87];
always_comb b_rtr = rx_shift[86];
always_comb b_ide = rx_shift[85];
always_comb b_r0 = rx_shift[84];
always_comb b_dlc = rx_shift[83:80];
always_comb b_data = rx_shift[79:16];
always_comb b_crc = rx_shift[15:1];
always_comb b_crc_del = rx_shift[0];
logic id_match;
always_ff @(posedge i_clk) id_match <= ((i_id & i_mask) == (b_id & i_mask)); // Check if CAN ID matches
logic dlc_match;
always_ff @(posedge i_clk) dlc_match <= (b_dlc == 4'd8); // Check if DLC is 8 (Hardcoded in Stacksynth)
logic crc_match;
always_ff @(posedge i_clk) crc_match <= 1'b1; // TODO: Implement CRC checking
logic msg_valid; // Check if message is valid
always_ff @(posedge i_clk) msg_valid <= &{id_match, !b_rtr, !b_ide, !b_r0, dlc_match, crc_match, b_crc_del};
always_ff @(posedge i_clk)
if (!i_rst_n) o_tx <= 1'b1; // Reset
else if (div_1m == 9'd1) o_tx <= !msg_valid; // Output dominant (0) if message valid, at start of bit time
always_ff @(posedge i_clk)
if (!i_rst_n) o_id <= 11'd0; // Reset
else if (div_1m == 9'd1 && msg_valid) o_id <= b_id; // Update received ID if valid, at start of bit time
logic [63:0] data;
always_ff @(posedge i_clk)
if (!i_rst_n) data <= 64'd0; // Reset
else if (div_1m == 9'd1 && msg_valid) data <= b_data; // Update data if valid, at start of bit time
always_ff @(posedge i_clk)
if (!i_rst_n) o_pulse <= 1'b0; // Reset
else if (div_1m == 9'd1) o_pulse <= msg_valid; // Output pulse if message valid, at start of bit time
else o_pulse <= 1'b0; // Clear pulse after 1 cycle (48MHz)
// Output data as individual bytes
always_comb o_data0 = data[63:56];
always_comb o_data1 = data[55:48];
always_comb o_data2 = data[47:40];
always_comb o_data3 = data[39:32];
always_comb o_data4 = data[31:24];
always_comb o_data5 = data[23:16];
always_comb o_data6 = data[15:8];
always_comb o_data7 = data[7:0];
endmodule
/* CRC Formula from BOSCH CAN Specification
crc_rg = '0; // Initialise shift register
repeat {
crcnxt = nxtbit ^ crc_rg[14];
crc_rg = {crc_rg[13:0], 1'b0}; // Shift left by 1
if (crcnxt) crc_rg = crc_rg ^ 15'h4599; // XOR with 15'h4599
} until (input runs out)
*/