Простая USB функция

//простейшая функция USB написанная на языке VERILOG

//дополнительно требуются USB передатчик и приемник

 //simplest low speed USB CORE function

module
ls_usb_core(
    //clock should be 5Mhz
   
input wire clk,

    input wire EOP,
    input wire [7:0]data,
    input wire wre,

    input wire [3:0]rbyte_cnt,

    input wire show_next,

    output reg [7:0]sbyte,
    output reg start_pkt,
    output reg last_pkt_byte,
    output reg [7:0]leds
);

//PIDs of last 2 received packets
reg [3:0]pid0;
reg [3:0]pid1;
reg [1:0]toggle;

always @(posedge clk)
begin
    if
( (rbyte_cnt==4'h1) & wre)
    begin
        pid1 <= pid0;
        pid0 <= data[3:0];
    end
end


reg [3:0]setup_req;
always @(posedge clk)
begin
    if
( (rbyte_cnt==4'h3) & wre & (pid1==4'hd) )
        setup_req <= data[3:0];
end

always @(posedge clk)
begin
    if
( (rbyte_cnt==4'h6) & wre & (pid1==4'hd) )
         leds <= data[7:0];
end

reg [3:0]setup_val;
always @(posedge clk)
begin
    if( (rbyte_cnt==4'h5) & wre & (pid1==4'hd) )
        setup_val <= data[3:0];
end

reg [3:0]setup_len;
always @(posedge clk)
begin
    if
( (rbyte_cnt==4'h8) & wre & (pid1==4'hd) )
        setup_len <= data[3:0];
end

//sending bytes table
reg [7:0]sptr;
reg [7:0]sb; //byte for send and flag for last packet

always @*
begin
case
(sptr)
    //ACK packet
    8'h00: sb = 8'h81;    //SYN    
    8'h01: sb = 8'hD2;    //last in packet
    8'h02: sb = 8'h00;
    8'h03: sb = 8'h00;
    8'h04: sb = 8'h00;
    8'h05: sb = 8'h00;
    8'h06: sb = 8'h00;
    8'h07: sb = 8'h00;
    8'h08: sb = 8'h00;
    8'h09: sb = 8'h00;
    8'h0a: sb = 8'h00;
    8'h0b: sb = 8'h00;
    8'h0c: sb = 8'h00;
    8'h0d: sb = 8'h00;
    8'h0e: sb = 8'h00;
    8'h0f: sb = 8'h00;

    //config descriptor

    8'h10: sb = 8'h8b; //SYN
    8'h11: sb = 8'h4B;
    8'h12: sb = 8'h12;    //12 01 00 01 FF 00 00 08 23 f3
    8'h13: sb = 8'h01;
    8'h14: sb = 8'h00;
    8'h15: sb = 8'h01;
    8'h16: sb = 8'hff;
    8'h17: sb = 8'h00;
    8'h18: sb = 8'h00;
    8'h19: sb = 8'h08;
    8'h1a: sb = 8'h23;
    8'h1b: sb = 8'hf3;    //last in packet
    8'h1c: sb = 8'h00;
    8'h1d: sb = 8'h00;
    8'h1e: sb = 8'h00;
    8'h1f: sb = 8'h00;

    //config descriptor continued
    8'h20: sb = 8'h8b;     //SYN
    8'h21: sb = 8'hC3;
    8'h22: sb = 8'hB9;    //B9 04 00 03 00 02 02 01 14 4a
    8'h23: sb = 8'h04;
    8'h24: sb = 8'h00;
    8'h25: sb = 8'h03;
    8'h26: sb = 8'h00;
    8'h27: sb = 8'h02;
    8'h28: sb = 8'h02;
    8'h29: sb = 8'h00;
    8'h2a: sb = 8'hd5;
    8'h2b: sb = 8'h8a;
    8'h2c: sb = 8'h00;
    8'h2d: sb = 8'h00;
    8'h2e: sb = 8'h00;
    8'h2f: sb = 8'h00;

    //config descriptor continued
    8'h30: sb = 8'h85;     //SYN
    8'h31: sb = 8'h4B;
    8'h32: sb = 8'h00;    //00 01 3f 8f
    8'h33: sb = 8'h01;
    8'h34: sb = 8'h3f;
    8'h35: sb = 8'h8f;
    8'h36: sb = 8'h00;
    8'h37: sb = 8'h00;
    8'h38: sb = 8'h00;
    8'h39: sb = 8'h00;
    8'h3a: sb = 8'h00;
    8'h3b: sb = 8'h00;
    8'h3c: sb = 8'h00;
    8'h3d: sb = 8'h00;
    8'h3e: sb = 8'h00;
    8'h3f: sb = 8'h00;

    //empty IN
    8'h40: sb = 8'h83;     //SYN
    8'h41: sb = 8'h4B;
    8'h42: sb = 8'h00;
    8'h43: sb = 8'h00;
    8'h44: sb = 8'h00;
    8'h45: sb = 8'h00;
    8'h46: sb = 8'h00;
    8'h47: sb = 8'h00;
    8'h48: sb = 8'h00;
    8'h49: sb = 8'h00;
    8'h4a: sb = 8'h00;
    8'h4b: sb = 8'h00;
    8'h4c: sb = 8'h00;
    8'h4d: sb = 8'h00;
    8'h4e: sb = 8'h00;
    8'h4f: sb = 8'h00;

    //config descriptor configuration
    8'h50: sb = 8'h8b;     //SYN
    8'h51: sb = 8'h4B;
    8'h52: sb = 8'h09;
    8'h53: sb = 8'h02;
    8'h54: sb = 8'h14;
    8'h55: sb = 8'h00;
    8'h56: sb = 8'h01;
    8'h57: sb = 8'h01;
    8'h58: sb = 8'h00;
    8'h59: sb = 8'h80;
    8'h5a: sb = 8'h0e;
    8'h5b: sb = 8'hd6;
    8'h5c: sb = 8'h00;
    8'h5d: sb = 8'h00;
    8'h5e: sb = 8'h00;
    8'h5f: sb = 8'h00;

    //config descriptor configuration continued
    8'h60: sb = 8'h84;     //SYN
    8'h61: sb = 8'hC3;
    8'h62: sb = 8'h0d;
    8'h63: sb = 8'h81;
    8'h64: sb = 8'h7a;
    8'h65: sb = 8'h00;
    8'h66: sb = 8'h00;
    8'h67: sb = 8'h00;
    8'h68: sb = 8'h00;
    8'h69: sb = 8'h00;
    8'h6a: sb = 8'h00;
    8'h6b: sb = 8'h00;
    8'h6c: sb = 8'h00;
    8'h6d: sb = 8'h00;
    8'h6e: sb = 8'h00;
    8'h6f: sb = 8'h00;

    //config descriptor configuration
    8'h70: sb = 8'h8b;     //SYN
    8'h71: sb = 8'h4B;
    8'h72: sb = 8'h09;
    8'h73: sb = 8'h02;
    8'h74: sb = 8'h14;
    8'h75: sb = 8'h00;
    8'h76: sb = 8'h01;
    8'h77: sb = 8'h01;
    8'h78: sb = 8'h00;
    8'h79: sb = 8'h80;
    8'h7a: sb = 8'h0e;
    8'h7b: sb = 8'hd6;
    8'h7c: sb = 8'h00;
    8'h7d: sb = 8'h00;
    8'h7e: sb = 8'h00;
    8'h7f: sb = 8'h00;

    //config descriptor configuration continued
    8'h80: sb = 8'h8b;     //SYN
    8'h81: sb = 8'hC3;
    8'h82: sb = 8'h0d;
    8'h83: sb = 8'h09;
    8'h84: sb = 8'h04;
    8'h85: sb = 8'h00;
    8'h86: sb = 8'h00;
    8'h87: sb = 8'h00;
    8'h88: sb = 8'hff;
    8'h89: sb = 8'h00;
    8'h8a: sb = 8'ha7;
    8'h8b: sb = 8'h19;
    8'h8c: sb = 8'h00;
    8'h8d: sb = 8'h00;
    8'h8e: sb = 8'h00;
    8'h8f: sb = 8'h00;

    //config descriptor configuration continued
    8'h90: sb = 8'h87;     //SYN
    8'h91: sb = 8'h4B;
    8'h92: sb = 8'h00;
    8'h93: sb = 8'h00;
    8'h94: sb = 8'h02;
    8'h95: sb = 8'h40;
    8'h96: sb = 8'hff;
    8'h97: sb = 8'h4b;
    8'h98: sb = 8'h00;
    8'h99: sb = 8'h00;
    8'h9a: sb = 8'h00;
    8'h9b: sb = 8'h00;
    8'h9c: sb = 8'h00;
    8'h9d: sb = 8'h00;
    8'h9e: sb = 8'h00;
    8'h9f: sb = 8'h00;

default:
    sb = 8'h00;
endcase
end


reg [1:0]state;
reg [3:0]pkt_len;

always @(posedge clk)
begin
    if(sptr[3:0]==4'h0)
        pkt_len <= sb[3:0];
end

always @*
begin
    if(sptr[3:0]==4'h0)    
        sbyte = {sb[7:4],4'b0000};
    else
        sbyte = sb;

    last_pkt_byte = (sptr[3:0]==pkt_len);
end

always @(posedge clk)
begin
    if
( (state==0) & (!EOP) )
    begin
        if(pid0==4'hd) //0x2D
            toggle <= 2'b00;
        else
        if(pid0==4'h9) //0x69
            toggle <= toggle + 1'b1;
    end
end


always @(posedge clk or posedge EOP)
begin
    if(EOP)
    begin
        //kind of reset
        start_pkt <= 1'b0;
        state <= 0;
        sptr  <= 8'h00;
    end
    else
    begin

        start_pkt <= (state==2'b10);

        case(state)
        0:
            begin
                //do nothing but just after EOP check last PIDs
                if( ((pid0==4'hb) | (pid0==4'h3)) & ((pid1==4'hd) | (pid1==4'h1)) ) // (0x4b or 0xc3) and (0x2d and 0xE1)
                begin
                    state <= 2;            //should send packet
                    sptr[7:4] <= 4'h0;    //packet will be ACK
                    sptr[3:0] <= 4'h0;
                end
                else

                if( (pid0==4'h9)&(setup_req==4'h6)&(setup_val==4'h1))
                begin
                    state <= 2;            //should send packet
                    sptr[7:4] <= 4'h1+toggle;    //packet will be config descriptor
                    sptr[3:0] <= 4'h0;
                end
                else
                if
( (pid0==4'h9)&(setup_req==4'h6)&(setup_val==4'h2)&(setup_len==4'h9))
                begin
                    state <= 2;            //should send packet
                    sptr[7:4] <= 4'h5+toggle;    //packet will be config descriptor configuration
                    sptr[3:0] <= 4'h0;
                end
                else

                if( (pid0==4'h9)&(setup_req==4'h6)&(setup_val==4'h2)&(setup_len!=4'h9))
                begin
                    state <= 2;            //should send packet
                    sptr[7:4] <= 4'h7+toggle;    //packet will be config descriptor configuration
                    sptr[3:0] <= 4'h0;
                end
                else
                if
(pid0==4'h9)
                begin
                    state <= 2;            //should send packet
                    sptr[7:4] <= 4'h4;    //empty IN
                    sptr[3:0] <= 4'h0;
                end
                else
                begin

                    state <= 1; //should do nothing
                    sptr<=8'h00;
                end
            end
        1:
            begin
                //do nothing
                state <= 1;
                sptr  <= 8'h00;
            end
        2:
            begin
                //initiate send packet
                state <= 3;
                sptr  <= sptr;
            end
        3:
            begin
                state <= 3;
                sptr[3:0] <= sptr[3:0] + show_next;
                sptr[7:4] <= sptr[7:4];
            end
        endcase
    end
end

endmodule