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

Reply via email to