PFGA与USB的通信实现,USB采用赛普拉斯的EZ-USB。程序包括两部分:发送和接收。每路都包括一个缓冲区和一个FIFO及校验计算逻辑。发送逻辑监控发送缓冲区的写入口地址总线,对偏移0xFF的操作,视为命令长度,并触发发送操作。命令发送时,首先发送到发送FIFO中,然后根据USB总线的忙闲状态,从FIFO中读取数据,并计算校验和,在达到命令长度后将校验和发送到USB上。接收逻辑监控USB总线,有数据时根据状态机工作。首先,读到包头后,就接受命令里指定长度的数据,然后进行校验计算,如果通过校验,就产生中断信号。
module usbctrl (nrst,
unrst, uclk, udata, uflaga, uflagb, uflagc, uncs, unrd, unwr, uaddr, upktend,
txdata, txaddr, txbsy, txlatch, txclk,
rxdata, rxaddr, rxlatch, rxclk, rxirq,
upktend_en
);
`include "REGADDRDEF.h"
input nrst, uclk, uflaga, uflagb, uflagc;
output uncs, unrd, unwr, upktend, unrst;
reg unwr;
//wire uncs;
output [1:0] uaddr;
reg [1:0] uaddr;
inout [15:0] udata;
input [15:0] txdata;
input [7:0] txaddr;
output txbsy;
//reg txbsy;
input txlatch, txclk;
output [15:0] rxdata;
input [7:0] rxaddr;
input rxlatch, rxclk;
output rxirq;
input upktend_en;
assign unrst = nrst;
//----------------------------------------------------------
// ARM Control Signal
reg rxcmdbuf_clear;
reg [2:0]rxcmdbuf_clear_cnt;
always @(posedge rxclk or negedge nrst)
if (~nrst)
rxcmdbuf_clear_cnt <= #REGOUT 3'hF;
else if (rxlatch)
rxcmdbuf_clear_cnt <= #REGOUT 3'h0;
else if (~&rxcmdbuf_clear_cnt)
rxcmdbuf_clear_cnt <= #REGOUT rxcmdbuf_clear_cnt + 1'b1;
always @(posedge rxclk or negedge nrst)
if (~nrst)
rxcmdbuf_clear <= #REGOUT 1'b0;
else // Edit the logic to clear the
rxcmdbuf_clear <= #REGOUT ~&rxcmdbuf_clear_cnt; // flag after read the command
//----------------------------------------------------------
// USB Bus Control
`define BUSST_IDLE 2'b00
`define BUSST_RD 2'b10
`define BUSST_WR 2'b11
wire rx_empty = ~uflagb;
wire tx_full = ~uflagc;
reg [1:0] bus_stm, bus_stm_next;
always @(posedge uclk or negedge nrst)
if (~nrst)
bus_stm <= #REGOUT 2'b00;
else
bus_stm <= #REGOUT bus_stm_next;
wire rxbufok, txbufok;
wire can_rx = ~rx_empty & rxbufok; // low assert
wire can_tx = ~tx_full & txbufok; // low assert
always @(bus_stm or can_rx or can_tx)
if (bus_stm == `BUSST_IDLE)
begin
if (can_rx)
bus_stm_next = `BUSST_RD;
else if (can_tx)
bus_stm_next = `BUSST_WR;
else
bus_stm_next = `BUSST_IDLE;
end
else if (bus_stm == `BUSST_RD)
begin
if (can_rx)
bus_stm_next = `BUSST_RD;
else
bus_stm_next = `BUSST_IDLE;
end
else if (bus_stm == `BUSST_WR)
begin
if (can_tx)
bus_stm_next = `BUSST_WR;
else
bus_stm_next = `BUSST_IDLE;
end
else
bus_stm_next = `BUSST_IDLE;
assign unrd = ~((bus_stm == `BUSST_RD) && can_rx);
//
// always @(posedge uclk)
// uncs <= #REGOUT ~bus_stm[1]; //unwr & unrd;
//
assign uncs = ~bus_stm[1]; //unwr & unrd;
reg [15:0] udatao;
assign udata = (unwr) ? 16'hZZZZ : udatao;
// reg unwr_r;
// wire txusbbuf_rd;
reg txusbbuf_rd;
always @(posedge uclk)
unwr <= #REGOUT ~txusbbuf_rd;
// assign unwr = ~((bus_stm == `BUSST_WR) && can_tx);
// always @(posedge uclk)
// unwr <= #REGOUT unwr_r;
always @(posedge uclk)
uaddr <= #REGOUT (bus_stm == `BUSST_WR) ? TXENDPOINT : RXENDPOINT;
// assign uaddr = (bus_stm == `BUSST_WR) ? TXENDPOINT : RXENDPOINT;
//----------------------------------------------------------
// rx logic
reg rxcmd_valid, rxcmd_invalid;
reg rx_stm, rx_stm_next;
wire usb_datain_buf_ren;
wire usb_datain_buf_rdempty;
wire [7:0] usb_datain_buf_dout;
wire usb_datain_buf_full;
assign rxbufok = ~usb_datain_buf_full;
reg usb_datain_buf_wrreq;
always @(posedge uclk)
usb_datain_buf_wrreq <= #REGOUT ~unrd;
fifo16_8 usb_datain_buf_inst(
.aclr(~nrst),
.data(udata),
.wrclk(uclk),
.wrreq(~unrd), //(usb_datain_buf_wrreq),
.wrfull(usb_datain_buf_full),
.rdclk(uclk),
.rdreq(usb_datain_buf_ren),
.rdempty(usb_datain_buf_rdempty),
.q(usb_datain_buf_dout)
);
reg rxcmdbuf_ok;
// indicated that the ARM has get the data
reg rxcmdbuf_clear_d;
always @(posedge uclk or negedge nrst)
if (~nrst)
begin
rxcmdbuf_clear_d <= #REGOUT 1'b0;
rxcmdbuf_ok <= #REGOUT 1'b1;
end
else
begin
rxcmdbuf_clear_d <= #REGOUT rxcmdbuf_clear;
if (rxcmdbuf_ok)
rxcmdbuf_ok <= #REGOUT ~rxcmd_valid;
else
rxcmdbuf_ok <= #REGOUT rxcmdbuf_clear_d;
end
assign usb_datain_buf_ren = ~usb_datain_buf_rdempty & rxcmdbuf_ok;
reg [8:0] rxcmdbuf_wraddr;
wire [7:0] rxcmdbuf_din = usb_datain_buf_dout;
wire rxcmdbuf_wrclk = uclk;
reg rxcmdbuf_wren;
wire [7:0] rxcmdbuf_rdaddr = rxaddr;
wire rxcmdbuf_rdclk = rxclk;
wire [15:0]rxcmdbuf_dout ;
assign rxdata = rxcmdbuf_dout;
always @(posedge uclk or negedge nrst)
if (~nrst)
rxcmdbuf_wren <= #REGOUT 1'b0;
else
rxcmdbuf_wren <= usb_datain_buf_ren && rx_stm_next == 1'b1;
rxcmdbuf rxcmdbuf_inst(
.data(rxcmdbuf_din),
.wraddress(rxcmdbuf_wraddr),
.wrclock(rxcmdbuf_wrclk),
.wren(rxcmdbuf_wren),
.rdaddress(rxcmdbuf_rdaddr),
.rdclock(rxcmdbuf_rdclk),
.q(rxcmdbuf_dout)
);
always @(posedge uclk or negedge nrst)
if (~nrst)
rx_stm <= #REGOUT 1'b0;
else
rx_stm <= #REGOUT rx_stm_next;
wire rst_rxstm;
always @(rx_stm or rxcmd_invalid or rxcmd_valid or usb_datain_buf_dout or usb_datain_buf_ren or rst_rxstm)
if (rst_rxstm)
rx_stm_next = 1'b0;
else if (rx_stm == 1'b0)
begin
if (usb_datain_buf_dout == USBRXCMDHEAD && usb_datain_buf_ren)
rx_stm_next = 1'b1;
else
rx_stm_next = 1'b0;
end
else
begin
if (rxcmd_valid || rxcmd_invalid)
rx_stm_next = 1'b0;
else
rx_stm_next = 1'b1;
end
reg [15:0] rxcmd_len;
reg [7:0] rxcmd_chksum;
assign rst_rxstm = rxcmdbuf_wraddr > 2 && rxcmd_len > 64 && ~&rxcmd_len;
always @(posedge uclk or negedge nrst)
if (~nrst)
rxcmd_len <= #REGOUT 16'hFFFF;
else if (rxcmdbuf_wraddr == 9'h001)
rxcmd_len[7:0] <= #REGOUT rxcmdbuf_din; //{8'h00, rxcmdbuf_din + 1'b1};
else if (rxcmdbuf_wraddr == 9'h002)
rxcmd_len[15:8] <= #REGOUT rxcmdbuf_din; //{rxcmdbuf_din, 8'h00} + rxcmd_len;
else if (rx_stm == 1'b0)
rxcmd_len <= #REGOUT 16'hFFFF;
always @(posedge uclk or negedge nrst)
if (~nrst)
rxcmdbuf_wraddr <= #REGOUT {9{1'b0}};
else if (rxcmdbuf_wren && rxcmdbuf_ok)
rxcmdbuf_wraddr <= #REGOUT rxcmdbuf_wraddr + 1'b1;
else if (~rx_stm | ~rxcmdbuf_ok)
rxcmdbuf_wraddr <= #REGOUT {9{1'b0}};
always @(posedge uclk or negedge nrst)
if (~nrst)
rxcmd_chksum <= #REGOUT 8'h00;
else if (~rx_stm)
rxcmd_chksum <= #REGOUT USBRXCMDHEAD;
else if (rxcmdbuf_wren) ////****
rxcmd_chksum <= #REGOUT rxcmd_chksum + rxcmdbuf_din;
wire cmp_r = rxcmd_chksum == usb_datain_buf_dout;
always @(posedge uclk or negedge nrst)
if (~nrst)
rxcmd_invalid <= #REGOUT 1'b0;
else if (rxcmd_len + 2 == {7'h00,rxcmdbuf_wraddr})
rxcmd_invalid <= #REGOUT ~cmp_r;
else if (~rx_stm)
rxcmd_invalid <= #REGOUT 1'b0;
always @(posedge uclk or negedge nrst)
if (~nrst)
rxcmd_valid <= #REGOUT 1'b0;
else if (rxcmd_len + 2 == {7'h00,rxcmdbuf_wraddr})
rxcmd_valid <= #REGOUT cmp_r;
else if (~rx_stm)
rxcmd_valid <= #REGOUT 1'b0;
reg [1:0] rxirq_cnt;
always @(posedge rxclk or negedge nrst or posedge rxcmd_valid)
if (~nrst)
rxirq_cnt <= #REGOUT 2'b11;
else if (rxcmd_valid)
rxirq_cnt <= #REGOUT 2'b00;
else if (~&rxirq_cnt)
rxirq_cnt <= #REGOUT rxirq_cnt + 1'b1;
assign rxirq = ~&rxirq_cnt;
//----------------------------------------------------------
// Tx logic
reg [8:0] txcmdbuf_rdaddr;
wire [7:0] txcmdbuf_dout;
wire [15:0] txcmdbuf_dout_16;
reg [8:0] txcmdlen, txcmdlen_u, txcmdlen_ur;
reg txcmdbuf_ok, txcmdbuf_ok_r, txcmdbuf_ok_rr;
txcmdbuf txcmdbuf_inst(
.data (txdata),
.wraddress (txaddr[7:0]),
.wrclock (txclk),
.wren (txlatch),
.rdaddress (txcmdbuf_rdaddr[8:1]),
.rdclock (uclk),
.q (txcmdbuf_dout_16)
);
assign txcmdbuf_dout = (~txcmdbuf_rdaddr[0]) ? txcmdbuf_dout_16[15:8] : txcmdbuf_dout_16[7:0];
wire txcmd_over_rst = (txcmdbuf_rdaddr >= txcmdlen);
reg txcmd_over_rst_r, txcmd_over_rst_rr;
always @(posedge txclk)
begin
txcmd_over_rst_r <= #REGOUT txcmd_over_rst;
txcmd_over_rst_rr <= #REGOUT txcmd_over_rst_r;
end
reg [3:0] txcmd_over_cnt;
always @(posedge txclk or posedge txcmd_over_rst_rr)
if (txcmd_over_rst_rr)
txcmd_over_cnt <= #REGOUT 4'b0000;
else if (~&txcmd_over_cnt)
txcmd_over_cnt <= #REGOUT txcmd_over_cnt + 1'b1;
wire txcmd_over = ~&txcmd_over_cnt;
always @(posedge txclk or negedge nrst)
if (~nrst)
begin
txcmdlen <= #REGOUT 9'hFFF;
txcmdbuf_ok_r <= #REGOUT 1'b0;
end
else if (txlatch == 1'b1 && txaddr == 8'hFF) //**METASTEABILITY
begin
txcmdlen <= #REGOUT txdata[8:0];
txcmdbuf_ok_r <= #REGOUT 1'b1;
end
else if (txcmd_over)
begin
txcmdlen <= #REGOUT 9'hFFF;
txcmdbuf_ok_r <= #REGOUT 1'b0;
end
always @(posedge uclk or negedge nrst)
if (~nrst)
begin
txcmdlen_u <= #REGOUT 9'h000;
txcmdlen_ur <= #REGOUT 9'h000;
end
else
begin
txcmdlen_u <= #REGOUT txcmdlen;
txcmdlen_ur <= #REGOUT txcmdlen_u;
end
always @(posedge uclk or negedge nrst)
if (~nrst)
begin
txcmdbuf_ok_rr <= #REGOUT 1'b0;
txcmdbuf_ok <= #REGOUT 1'b0;
end
else
begin
txcmdbuf_ok_rr <= #REGOUT txcmdbuf_ok_r;
txcmdbuf_ok <= #REGOUT txcmdbuf_ok_rr;
end
wire [8:0] txusbbuf_din;
wire [17:0] fifo_out;
reg txusbbuf_wren;
reg txusbbuf_latch;
wire txusbbuf_wrfull, txusbbuf_rdempty;
always @(posedge uclk or negedge nrst)
if (~nrst)
txcmdbuf_rdaddr <= #REGOUT 9'h000;
else if (txusbbuf_latch && txcmdbuf_rdaddr <= txcmdlen_ur)
txcmdbuf_rdaddr <= #REGOUT txcmdbuf_rdaddr + 1'b1;
else if (~txcmdbuf_ok)
txcmdbuf_rdaddr <= #REGOUT 9'h000;
fifo8_16 usb_dataout_buf_inst(
.data (txusbbuf_din),
.wrclk (uclk),
.wrreq (txusbbuf_wren),
.wrfull (txusbbuf_wrfull),
.rdempty (txusbbuf_rdempty),
.rdclk (uclk),
.rdreq (txusbbuf_rd),
.q (fifo_out)
);
reg [2:0] cnt;
always @(posedge uclk or negedge nrst)
if (~nrst)
begin
txusbbuf_latch <= #REGOUT 1'b0;
cnt <= #REGOUT 3'b111;
end
else if (~txcmdbuf_ok)
begin
txusbbuf_latch <= #REGOUT 1'b0;
cnt <= #REGOUT 3'b111;
end
else if (txcmdbuf_rdaddr == txcmdlen_ur)
begin
txusbbuf_latch <= #REGOUT 1'b0;
cnt <= #REGOUT 3'b000;
end
else if (txcmdbuf_ok && &cnt && ~txusbbuf_wrfull)
txusbbuf_latch <= #REGOUT 1'b1;
else if (~&cnt) //if (~txusbbuf_wrfull)
cnt <= #REGOUT cnt + 1'b1;
reg txusbbuf_latch_d, txusbbuf_latch_dd;
always @(posedge uclk)
begin
txusbbuf_latch_d <= #REGOUT txusbbuf_latch;
txusbbuf_latch_dd <= #REGOUT txusbbuf_latch_d;
end
wire txusbbuf_latch_dp = ~txusbbuf_latch_d & txusbbuf_latch_dd;
reg latch_dd;
reg[2:0] latch_dd_cnt;
always @(posedge uclk or negedge nrst)
if (~nrst)
latch_dd_cnt <= #REGOUT 3'b111;
else if (txusbbuf_latch_dp)
latch_dd_cnt <= #REGOUT 3'b000;
else if (~&latch_dd_cnt)
latch_dd_cnt <= #REGOUT latch_dd_cnt+1'b1;
always @(posedge uclk or negedge nrst)
if (~nrst)
txusbbuf_wren <= #REGOUT 1'b0;
else
txusbbuf_wren <= #REGOUT txusbbuf_latch | (~&latch_dd_cnt);
reg [7:0] txcmd_chksum;
always @(posedge uclk or negedge nrst)
if (~nrst)
txcmd_chksum <= #REGOUT 8'h00;
else if (txusbbuf_wren)
txcmd_chksum <= #REGOUT txcmd_chksum + txcmdbuf_dout;
else
txcmd_chksum <= #REGOUT 8'h00;
assign txusbbuf_din = (~&latch_dd_cnt) ? 17'h00000 : (txcmdbuf_rdaddr == txcmdlen_ur) ? {1'b1, txcmd_chksum} : {1'b0, txcmdbuf_dout};
assign txbufok = ~txusbbuf_rdempty;
// assign txusbbuf_rd = (bus_stm == `BUSST_WR) && txbufok && can_tx;
reg [2:0] cnt_d;
always @(posedge uclk or negedge nrst)
if (~nrst)
begin
cnt_d <= 3'h0;
txusbbuf_rd <= 1'b0;
end
else if (txusbbuf_rd)
begin
txusbbuf_rd <= 1'b0;
cnt_d <= 3'h0;
end
else if (cnt_d==3'h1)
begin
txusbbuf_rd <= (bus_stm == `BUSST_WR) && txbufok && can_tx;
end
else if (cnt_d < 3'h1)
cnt_d <= cnt_d + 1'b1;
always @(posedge uclk)
udatao <= #REGOUT {fifo_out[16:9], fifo_out[7:0]};
reg upktend_r;
reg [2:0] end_cnt;
always @(posedge uclk or negedge nrst)
if (~nrst)
end_cnt <= 3'hf;
else if(txusbbuf_rd && (fifo_out[17] || fifo_out[8]))
end_cnt <= 3'h0;
else if (~&end_cnt)
end_cnt <= end_cnt + 1'b1;
//
// assign upktend = ~(txusbbuf_rd && (fifo_out[17] || fifo_out[8]));
// assign upktend = upktend_r;
assign upktend = (end_cnt==3'b101) | upktend_en;
assign txbsy = txcmdbuf_ok_r;
endmodule |