Add a serial crc to the rx stage. The checksum is calculated while the packet is being received. Based on the PID either the CRC5 or CRC16 is calculated. After an EOP was received the error register can be checked for an CRC error.
Signed-off-by: Michael Walle <mich...@walle.cc> --- cores/softusb/rtl/softusb_crc.v | 69 ++++++++++++++++++++++++++++++++++ cores/softusb/rtl/softusb_phy.v | 9 ++++ cores/softusb/rtl/softusb_rx.v | 79 ++++++++++++++++++++++++++++++++++++++- cores/softusb/rtl/softusb_sie.v | 39 ++++++++++++++++--- 4 files changed, 189 insertions(+), 7 deletions(-) create mode 100644 cores/softusb/rtl/softusb_crc.v diff --git a/cores/softusb/rtl/softusb_crc.v b/cores/softusb/rtl/softusb_crc.v new file mode 100644 index 0000000..f595be7 --- /dev/null +++ b/cores/softusb/rtl/softusb_crc.v @@ -0,0 +1,69 @@ +/* + * Milkymist SoC + * Copyright (C) 2012 Michael Walle + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +module softusb_crc( + input usb_clk, + + input crc_reset, + input data, + input crc_ce, + + output reg [4:0] crc5, + output reg [15:0] crc16, + + output crc5_valid, + output crc16_valid +); + +always @(posedge usb_clk) begin + if(crc_reset) + crc5 <= 5'h1f; + else if (crc_ce) begin + crc5[0] <= data ^ crc5[4]; + crc5[1] <= crc5[0]; + crc5[2] <= crc5[1] ^ data ^ crc5[4]; + crc5[3] <= crc5[2]; + crc5[4] <= crc5[3]; + end +end +assign crc5_valid = (crc5 == 5'b01100); + +always @(posedge usb_clk) begin + if(crc_reset) + crc16 <= 16'hffff; + else if (crc_ce) begin + crc16[0] <= data ^ crc16[15]; + crc16[1] <= crc16[0]; + crc16[2] <= crc16[1] ^ data ^ crc16[15]; + crc16[3] <= crc16[2]; + crc16[4] <= crc16[3]; + crc16[5] <= crc16[4]; + crc16[6] <= crc16[5]; + crc16[7] <= crc16[6]; + crc16[8] <= crc16[7]; + crc16[9] <= crc16[8]; + crc16[10] <= crc16[9]; + crc16[11] <= crc16[10]; + crc16[12] <= crc16[11]; + crc16[13] <= crc16[12]; + crc16[14] <= crc16[13]; + crc16[15] <= crc16[14] ^ data ^ crc16[15]; + end +end +assign crc16_valid = (crc16 == 16'b1000000000001101); + +endmodule diff --git a/cores/softusb/rtl/softusb_phy.v b/cores/softusb/rtl/softusb_phy.v index 1be444c..43dc1e2 100644 --- a/cores/softusb/rtl/softusb_phy.v +++ b/cores/softusb/rtl/softusb_phy.v @@ -47,7 +47,12 @@ module softusb_phy( output [7:0] rx_data, output rx_valid, output rx_active, + output rx_sync, + output rx_eop, output rx_error, + output rx_pid_error, + output rx_crc_error, + output [7:0] pid, input tx_low_speed, input [1:0] low_speed, @@ -136,7 +141,11 @@ softusb_rx rx( .rx_data(rx_data), .rx_valid(rx_valid), .rx_active(rx_active), + .rx_sync(rx_sync), + .rx_eop(rx_eop), .rx_error(rx_error), + .rx_pid_error(rx_pid_error), + .rx_crc_error(rx_crc_error), .low_speed(port_sel_rx ? low_speed[1] : low_speed[0]) ); diff --git a/cores/softusb/rtl/softusb_rx.v b/cores/softusb/rtl/softusb_rx.v index 9867469..95c28aa 100644 --- a/cores/softusb/rtl/softusb_rx.v +++ b/cores/softusb/rtl/softusb_rx.v @@ -27,7 +27,12 @@ module softusb_rx( output reg [7:0] rx_data, output reg rx_valid, output reg rx_active, + output reg rx_sync, + output reg rx_eop, output reg rx_error, + /* only valid during rx_eop pulse */ + output rx_pid_error, + output rx_crc_error, input low_speed ); @@ -149,6 +154,7 @@ reg [2:0] bitcount; reg [2:0] onecount; reg lastrx; reg startrx; +reg rx_bit; always @(posedge usb_clk) begin if(rxreset) begin rx_active <= 1'b0; @@ -157,8 +163,13 @@ always @(posedge usb_clk) begin end else begin rx_valid <= 1'b0; rx_error <= 1'b0; - if(eop_detected) + rx_bit <= 1'b0; + rx_sync <= 1'b0; + rx_eop <= 1'b0; + if(eop_detected) begin + rx_eop <= 1'b1; rx_active <= 1'b0; + end else if(dpll_ce) begin if(rx_active & ~se0) begin if(onecount == 3'd6) begin @@ -167,6 +178,7 @@ always @(posedge usb_clk) begin if((lastrx & rx_corrected)|(~lastrx & ~rx_corrected)) begin /* no transition? bitstuff error */ rx_active <= 1'b0; + rx_eop <= 1'b1; rx_error <= 1'b1; end lastrx <= ~lastrx; @@ -178,6 +190,7 @@ always @(posedge usb_clk) begin else onecount <= 3'd0; lastrx <= 1'b1; + rx_bit <= 1'b1; end else begin rx_data <= {~lastrx, rx_data[7:1]}; if(~lastrx) @@ -185,12 +198,14 @@ always @(posedge usb_clk) begin else onecount <= 3'd0; lastrx <= 1'b0; + rx_bit <= 1'b1; end rx_valid <= bitcount == 3'd7; bitcount <= bitcount + 3'd1; end end else if(startrx) begin rx_active <= 1'b1; + rx_sync <= 1'b1; bitcount <= 3'd0; onecount <= 3'd1; lastrx <= 1'b0; @@ -199,6 +214,68 @@ always @(posedge usb_clk) begin end end +/* PID extracting & checking */ + +parameter PKT_NONE = 2'd0; +parameter PKT_PID = 2'd1; +parameter PKT_PAYLOAD = 2'd2; + +reg [1:0] pkt_state; +reg [1:0] pkt_next_state; + +always @(posedge usb_clk) begin + if(rxreset|eop_detected|fs_timeout) + pkt_state <= PKT_NONE; + else + pkt_state <= pkt_next_state; +end + +always @(*) begin + pkt_next_state = pkt_state; + + case(pkt_state) + PKT_NONE: if(rx_sync) + pkt_next_state = PKT_PID; + PKT_PID: if(rx_valid) + pkt_next_state = PKT_PAYLOAD; + endcase +end + +reg [7:0] pid; +always @(posedge usb_clk) begin + if(rxreset|startrx) + pid <= 8'h00; + else if(rx_valid & (pkt_state == PKT_PID)) + pid <= rx_data; +end + +assign rx_pid_error = pid[3:0] != ~pid[7:4]; + +/* Serial CRC checking */ + +wire crc_ce = (pkt_state == PKT_PAYLOAD) & rx_bit; +wire crc_reset = rxreset | rx_sync; + +wire crc5_valid; +wire crc16_valid; +softusb_crc crc( + .usb_clk(usb_clk), + + .crc_reset(crc_reset), + .crc_ce(crc_ce), + .data(rx_data[7]), + + .crc5(), + .crc16(), + + .crc5_valid(crc5_valid), + .crc16_valid(crc16_valid) +); + +wire token_packet = pid[7:6] == 2'b10; +wire data_packet = pid[7:6] == 2'b11; +assign rx_crc_error = (~crc5_valid & token_packet) | (~crc16_valid & data_packet); + /* Find sync pattern */ parameter FS_IDLE = 4'h0; diff --git a/cores/softusb/rtl/softusb_sie.v b/cores/softusb/rtl/softusb_sie.v index 531aea2..5186f0b 100644 --- a/cores/softusb/rtl/softusb_sie.v +++ b/cores/softusb/rtl/softusb_sie.v @@ -54,8 +54,14 @@ reg [1:0] generate_reset; wire [7:0] rx_data; wire rx_valid; wire rx_active; +wire rx_sync; +wire rx_eop; wire rx_error; -reg rx_error_pending; +wire rx_pid_error; +wire rx_crc_error; +reg [2:0] rx_error_pending; +reg rx_sync_pending; +reg rx_eop_pending; wire tx_busy; reg [7:0] data_in; @@ -71,7 +77,7 @@ always @(posedge usb_clk) begin tx_valid <= 1'b0; tx_pending <= 1'b0; generate_reset <= 2'd0; - rx_error_pending <= 1'b0; + rx_error_pending <= 3'b0; rx_pending <= 1'b0; tx_low_speed <= 1'b0; low_speed <= 2'b00; @@ -99,14 +105,26 @@ always @(posedge usb_clk) begin 6'h0a: io_do <= { rx_pending, rx_active }; 6'h0b: io_do <= rx_active; 6'h0c: begin - io_do <= rx_error_pending; + io_do <= rx_error_pending[0]; if(io_re) - rx_error_pending <= 1'b0; + rx_error_pending <= 3'b0; end 6'h0d: io_do <= tx_low_speed; 6'h0e: io_do <= low_speed; 6'h0f: io_do <= 8'hxx; + + /* below are the registers for new rx handling */ + 6'h10: begin + io_do <= rx_sync_pending; + if(io_re) + rx_sync_pending <= 1'b0; + end + 6'h11: begin + io_do <= {rx_eop_pending, rx_pending}; + if(io_re) + rx_eop_pending <= 1'b0; + end endcase if(io_we) begin $display("USB SIE W: a=%x dat=%x", io_a, io_di); @@ -131,8 +149,13 @@ always @(posedge usb_clk) begin data_in <= rx_data; rx_pending <= 1'b1; end - if(rx_error) - rx_error_pending <= 1'b1; + if(rx_sync) + rx_sync_pending <= 1'b1; + + if(rx_eop) begin + rx_eop_pending <= 1'b1; + rx_error_pending <= {rx_crc_error, rx_pid_error, rx_error}; + end if(io_re) // must be at the end because of the delay! #1 $display("USB SIE R: a=%x dat=%x", io_a, io_do); @@ -171,7 +194,11 @@ softusb_phy phy( .rx_data(rx_data), .rx_valid(rx_valid), .rx_active(rx_active), + .rx_sync(rx_sync), + .rx_eop(rx_eop), .rx_error(rx_error), + .rx_pid_error(rx_pid_error), + .rx_crc_error(rx_crc_error), .tx_low_speed(tx_low_speed), .low_speed(low_speed), -- 1.7.2.5 _______________________________________________ http://lists.milkymist.org/listinfo.cgi/devel-milkymist.org IRC: #milkymist@Freenode