Чтение пакетов USB из UFM Flash

//
//this module allows USB CORE read predefined USB packets bytes
//

module pkt_reader(
    input wire reset,
    input wire clk,
    input wire [8:0]addr,
    input wire addr_wr,
    input wire addr_inc,

    //UFM addr control
    output wire ar_clk_ena,
    output wire ar_shift,
    output wire ar_out,

    //UFM data control
    input  wire dr_in,
    output wire dr_shift,
    output wire ready,
    output reg [15:0]dr,

    //Altera CPLD UFM data has 16 bit, but we convert interface to 8 bits
    //result is 8-bit interface and packet byte ready flag and sign about last byte in packet
    output reg [7:0]pkt_byte,
    output reg pkt_byte_ready,
    output wire last_pkt_byte
);

//count bits of UFM access (including address and data bits)
reg [4:0]counter;
always @(posedge clk)
begin
    if(addr_wr)
        counter <= 0;
    else
    if(addr_inc & addr_odd)
        counter <= 5'd10;
    else
    if(counter<27)
        counter <= counter + 1'b1;
end

//when data read from UFM we set ready
assign ready = (counter==5'd26);

//UFM address is shifted out when early counting
assign ar_shift = (counter < 5'd9);

//UFM enable clock for address shifting and address auto-increment
assign ar_clk_ena = ar_shift | (counter==5'd10);

//define when we need to read next word from UFM
wire need_next_word; assign need_next_word = addr_odd & addr_inc;

//UFM address shift out register
reg [8:0]addr_shift_reg;
assign ar_out = addr_shift_reg[8];
reg addr_odd;
reg first_pkt_byte;

always @(posedge clk)
begin
    if(addr_wr)
    begin
        addr_shift_reg <= addr;
        addr_odd <= 1'b0;
    end
    else
    begin
        addr_shift_reg <= {addr_shift_reg[7:0],1'b0};
        
        if(addr_inc)
            addr_odd <= addr_odd ^ 1'b1;
    end
end

//return packet byte ready signal
always @(posedge clk)
    pkt_byte_ready <= ready | (addr_inc & (~addr_odd));

//load length of packet from 1st byte read
reg [3:0]pkt_num_bytes;
always @(posedge clk)
begin
    if(addr_wr)
        pkt_num_bytes <= 0;
    else
        //get number of bytes in packet from 1st read byte of packet
        //this 1st byte will be replaced by SYNC==8'h80
        if( (pkt_num_bytes==0) & ready)
            pkt_num_bytes <= dr[3:0];
end

//count bytes passed to core
reg [3:0]bytes_cnt;
always @(posedge clk)
begin
    if(addr_wr)
        bytes_cnt <= 0;
    else
    if( pkt_byte_ready)
        bytes_cnt <= bytes_cnt + 1'b1;
end

//decide about last byte in packet if length read from 1st byte is equal to num bytes already passed
assign last_pkt_byte = (bytes_cnt == pkt_num_bytes) & (|pkt_num_bytes);

//shift in UFM data
assign dr_shift = (counter>5'd9) && (counter<5'd26);
always @(posedge clk)
begin
    if(dr_shift)
        dr <= {dr[14:0],dr_in};
end

always @*
begin
    if(bytes_cnt==0 || bytes_cnt==1)
        pkt_byte[3:0] = 4'h0;
    else
    if(addr_odd)
        pkt_byte[3:0] = dr[11:8];
    else
        pkt_byte[3:0] = dr[3:0];
end

always @*
begin
    if(addr_odd)
        pkt_byte[7:4] = dr[15:12];
    else
        pkt_byte[7:4] = dr[7:4];
end

endmodule