blob: 61054f3a03f7e59b9a7b79ee656e31330356af6c [file] [log] [blame]
// File name: RCU.sv
// Created: 12/1/2020
// Author: Zachary Ellis
// Version: 2.0 Extended Functionality
// Description: CAN receiver control unit
module RCU (
input clk,
input bitstrobe,
input nRST,
input CANRX,
input tx_busy,
input [1:0] error_state,
input CRC_err,
input enddata,
output reg endCRC,
output reg stopCRC,
output reg busy,
output Dataphase,
output reg bitstuff,
output reg bitstuff_error,
output reg form_error,
output reg [1:0] rx_err_code,
output reg [3:0] pkt_size,
output reg [28:0] msg_id,
output reg [7:0] payload,
output reg RTR,
output reg EXT,
output reg curr_sample,
output reg SOF,
output reg pkt_done,
output reg new_ID
);
wire nbitstrobe;
wire [17:0] rawchunks;
always_ff @(posedge bitstrobe) begin
curr_sample <= CANRX;
end
typedef enum logic [4:0]{
Idle,
getID,
SRRTR,
IDEverif,
SRRorRTR,
getIDext,
extRTR,
r1,
r0,
getpktsize,
dataphase,
crc,
crc_delim,
ack,
ack_delim,
EOF,
intermission,
ErrF,
ErrD,
OVD,
OVR
} statem_type;
typedef enum logic [3:0] {
Reset,
z1,
z2,
z3,
z4,
z5,
o1,
o2,
o3,
o4,
o5,
bso,
bsz,
error
} states_type;
statem_type statem, next_statem;
states_type states, next_states;
reg [4:0] bitcount, next_bitcount;
reg [28:0] next_msg_id;
reg [3:0] next_pkt_size;
reg next_RTR;
reg next_EXT;
reg [1:0] err_code, next_err_code;
reg bitstuff_error_delay;
reg [3:0] dcount, next_dcount;
always_ff @(posedge bitstrobe, negedge nRST) begin
if(nRST == 0) begin
statem <= Idle;
RTR <= '0;
EXT <= '0;
bitcount <= '0;
err_code <= '0;
dcount <= '0;
end
else begin
statem <= next_statem;
RTR <= next_RTR;
EXT <= next_EXT;
bitcount <= next_bitcount;
err_code <= next_err_code;
dcount <= next_dcount;
end
end
always_comb begin
next_statem = statem;
next_RTR = RTR;
next_EXT = EXT;
busy = 1'b1;
next_bitcount = bitcount + 1;
endCRC = 1'b0;
stopCRC = 1'b0;
SOF = 1'b0;
form_error = 1'b0;
next_err_code = err_code;
rx_err_code = 0;
next_dcount = 0;
new_ID = 1'b0;
pkt_done = 1'b0;
case(statem)
Idle: begin
if(curr_sample == 0) begin //weird corner case
next_statem = getID;
SOF = 1'b1;
end
busy = 1'b0;
next_RTR = 1'b0;
next_EXT = 1'b0;
end
getID: begin
if(bitcount == 5'd11 && ~bitstuff) begin
next_statem = SRRTR;
end
busy = 1'b0;
end
SRRTR: begin
if(~bitstuff) begin
if(curr_sample == 0) next_statem = IDEverif;
else next_statem = SRRorRTR;
end
busy = 1'b0;
end
IDEverif: begin
if(~bitstuff) begin
if(curr_sample == 0) next_statem = r0;
else begin
next_statem = ErrF;
form_error = 1'b1;
next_err_code = 1;
end
end
busy = 1'b0;
end
SRRorRTR: begin
if(~bitstuff) begin
if(curr_sample == 0) begin
next_statem = r0;
next_RTR = 1'b1;
end
else begin
next_statem = getIDext;
next_EXT = 1'b1;
end
end
busy = 1'b0;
end
getIDext: begin
if(bitcount == 5'd18 && ~bitstuff) next_statem = extRTR;
busy = 1'b0;
end
extRTR: begin
if(~bitstuff) begin
next_statem = r1;
if(curr_sample == 1) next_RTR = 1'b1;
end
busy = 1'b0;
end
r1: begin
if(~bitstuff) next_statem = r0;
end
r0: begin
if(~bitstuff) next_statem = getpktsize;
new_ID = 1'b1;
end
getpktsize: begin
if(bitcount == 5'd4 && ~bitstuff) begin
next_statem = dataphase;
if(next_pkt_size == 0 || RTR == 1'b1) next_statem = crc;
end
end
dataphase: if(enddata && ~bitstuff) next_statem = crc;
crc: begin
if(bitcount == 5'd15 && ~bitstuff) begin
next_statem = crc_delim;
endCRC = 1'b1;
end
end
crc_delim: begin
next_statem = ack;
if(curr_sample == 0) begin
form_error = 1'b1;
next_statem = ErrF;
next_err_code = 1;
end
end
ack: next_statem = ack_delim;
ack_delim: begin
next_statem = EOF;
if(curr_sample == 0) begin
form_error = 1'b1;
next_statem = ErrF;
next_err_code = 1;
end
end
EOF: begin
if(curr_sample == 0) begin
form_error = 1'b1;
next_statem = ErrF;
next_err_code = 1;
end
if(bitcount == 5'd7) begin
next_statem = intermission;
form_error = 1'b0;
next_err_code = 3;
pkt_done = 1'b1;
end
end
intermission: begin
if(curr_sample == 0) next_statem = OVD;
if(bitcount == 5'd3) next_statem = Idle;
rx_err_code = err_code;
next_err_code = 0;
busy = 1'b0;
end
ErrF: begin
if(bitcount == 5'd6) next_statem = ErrD;
stopCRC = 1;
if(error_state == 0 && curr_sample == 1'b1 && |err_code) rx_err_code = 2; //make sure rx is sending the flag
busy = 1'b0;
end
ErrD: begin
if(bitcount == 8) next_statem = intermission;
if(dcount == 8) rx_err_code = 2;
if(curr_sample == 0) begin
next_bitcount = bitcount;
next_dcount = dcount + 1;
case(dcount)
4'd0: rx_err_code = |err_code ? 2 : 0;
4'd8: begin
next_dcount = 1;
rx_err_code = 2;
end
endcase
end
busy = 1'b0;
end
OVD: begin
if(bitcount == 6) next_statem = OVR;
if(error_state == 0 && curr_sample == 1'b1) rx_err_code = 2;
end
OVR: begin
if(bitcount == 8) next_statem = intermission;
if(dcount == 8) rx_err_code = 2;
if(curr_sample == 0) begin
next_bitcount = bitcount;
next_dcount = dcount + 1;
if(dcount == 8) next_dcount = 1;
end
end
endcase
if(bitstuff) next_bitcount = bitcount;
if(bitstuff_error_delay) begin
next_statem = ErrF;
next_err_code = 1;
end
if(CRC_err) begin
next_statem = ErrF;
next_err_code = 1;
end
if(next_statem != statem) next_bitcount = 1;
if(tx_busy && (next_statem != ErrF && next_statem != ErrD)) begin
next_statem = intermission;
next_bitcount = 1;
end
end
always_ff @(posedge clk, negedge nRST) begin
if(nRST == 0) bitstuff_error_delay <= 1'b0;
else bitstuff_error_delay <= bitstuff_error;
end
assign Dataphase = (statem == dataphase);
assign nbitstrobe = ~bitstrobe;
always_ff @(posedge nbitstrobe, negedge nRST) begin
if(nRST == 0) begin
states <= Reset;
end
else begin
states <= next_states;
end
end
always_comb begin
bitstuff = 1'b0;
bitstuff_error = 1'b0;
next_states = states;
case(states)
Reset: begin
if(CANRX) next_states = o1;
else next_states = z1;
end
z1: begin
if(CANRX) next_states = o1;
else next_states = z2;
end
z2: begin
if(CANRX) next_states = o1;
else next_states = z3;
end
z3: begin
if(CANRX) next_states = o1;
else next_states = z4;
end
z4: begin
if(CANRX) next_states = o1;
else next_states = z5;
end
z5: begin
if(CANRX) begin
next_states = o1;
bitstuff = 1'b1;
end
else next_states = error;
end
o1: begin
if(CANRX) next_states = o2;
else next_states = z1;
end
o2: begin
if(CANRX) next_states = o3;
else next_states = z1;
end
o3: begin
if(CANRX) next_states = o4;
else next_states = z1;
end
o4: begin
if(CANRX) next_states = o5;
else next_states = z1;
end
o5: begin
if(CANRX) next_states = error;
else begin
next_states = z1;
bitstuff = 1'b1;
end
end
bso: begin
bitstuff = 1'b1;
if(CANRX) next_states = o2;
else next_states = z1;
end
bsz: begin
bitstuff = 1'b1;
if(CANRX) next_states = o1;
else next_states = z2;
end
error:begin
bitstuff_error = 1'b1;
if(CANRX) next_states = o1;
else next_states = z1;
end
endcase
if(next_statem == Idle || next_statem == crc_delim || next_statem == EOF || next_statem == ErrF || next_statem == ErrD || next_statem == intermission) next_states = Reset;
end
flex_stp_sr #(
.NUM_BITS(18)
)
PKTCUTTER(
.clk(bitstrobe),
.n_rst(nRST),
.shift_enable(~bitstuff),
.serial_in(CANRX),
.parallel_out(rawchunks)
);
always_ff @(posedge bitstrobe, negedge nRST) begin
if(nRST == 0) begin
msg_id <= '0;
pkt_size <= '0;
end
else begin
msg_id <= next_msg_id;
pkt_size <= next_pkt_size;
end
end
always_comb begin
next_msg_id = msg_id;
next_pkt_size = pkt_size;
payload = '0;
if(statem == getID) next_msg_id = {rawchunks[10:0], 18'd0};
else if(statem == getIDext) next_msg_id = {msg_id[28:18], rawchunks};
else if(statem == getpktsize) next_pkt_size = rawchunks[3:0];
else if(statem == dataphase) payload = rawchunks[7:0];
end
endmodule