|
@@ -56,6 +56,8 @@
|
|
|
// 8 - receive FIFO not empty after two USB frames
|
|
|
// 9 - BREAK received (sticky, W1C)
|
|
|
// 10 - USB device configured
|
|
|
+// 11 - DTR input active
|
|
|
+// 12 - RTS input active
|
|
|
// 3 - RW - interrupt enable register
|
|
|
// 15:0 - mask of corresponding status bits
|
|
|
// 31:16 - invert polarity (0 = irq on status 1, 1 = irq on status 0)
|
|
@@ -68,26 +70,31 @@ module usb_cdc_channel
|
|
|
input rst_n,
|
|
|
input sys_clk,
|
|
|
input cpu_valid,
|
|
|
- input [1:0] cpu_addr,
|
|
|
+ input [1:0] cpu_addr,
|
|
|
output [31:0] cpu_rdata,
|
|
|
input [31:0] cpu_wdata,
|
|
|
- input [3:0] cpu_wstrb,
|
|
|
+ input [3:0] cpu_wstrb,
|
|
|
output irq,
|
|
|
|
|
|
// Core FIFO interface
|
|
|
input clk_i,
|
|
|
input rst_i,
|
|
|
- usb_endpoint.dstr data_ep,
|
|
|
- usb_endpoint.dstr intr_ep,
|
|
|
+ usb_endpoint.dstr data_ep,
|
|
|
+ usb_endpoint.dstr intr_ep,
|
|
|
|
|
|
// Control signals
|
|
|
- input recv_break_i,
|
|
|
- output recv_break_o, // sys_clk domain, reflects the status register
|
|
|
+ input recv_break_i, // in the USB clock domain
|
|
|
+ output recv_break_o, // sys_clk domain, reflects the status register
|
|
|
|
|
|
- // USB status
|
|
|
- input usb_configured,
|
|
|
+ // Control lines (RTS, DTR) in the USB clock domain
|
|
|
+ input set_control_line,
|
|
|
+ input [1:0] control_lines,
|
|
|
|
|
|
- // Top of frame strobe *in sys_clk domain*
|
|
|
+ // USB configuration status
|
|
|
+ input usb_configured, // in the USB clock domain
|
|
|
+ input usb_configured_s, // in the sys_clk domain
|
|
|
+
|
|
|
+ // Top of frame strobe *in the sys_clk domain*
|
|
|
input start_of_frame_s
|
|
|
);
|
|
|
|
|
@@ -199,7 +206,7 @@ module usb_cdc_channel
|
|
|
had_rxdata <= 2'b00;
|
|
|
end
|
|
|
|
|
|
- wire [15:0] status_mask = 16'b0000_0111_1111_1111; // Implemented bit mask
|
|
|
+ wire [15:0] status_mask = 16'b0001_1111_1111_1111; // Implemented bit mask
|
|
|
reg [15:0] irq_mask;
|
|
|
reg [15:0] irq_pol;
|
|
|
wire [ 3:0] water_mask = 4'b1111 << (4-water_bits);
|
|
@@ -208,9 +215,6 @@ module usb_cdc_channel
|
|
|
|
|
|
wire recv_break_s;
|
|
|
reg recv_break_q;
|
|
|
-
|
|
|
- assign irq = irq_q;
|
|
|
-
|
|
|
synchronizer #(.width(1)) break_synchro
|
|
|
(
|
|
|
.rst_n ( rst_n ),
|
|
@@ -219,6 +223,24 @@ module usb_cdc_channel
|
|
|
.q ( recv_break_s )
|
|
|
);
|
|
|
|
|
|
+ reg [1:0] control_lines_q;
|
|
|
+ wire [1:0] control_lines_s;
|
|
|
+ always @(posedge rst_i or posedge clk_i)
|
|
|
+ if (rst_i)
|
|
|
+ control_lines_q <= 2'b00;
|
|
|
+ else if (~usb_configured)
|
|
|
+ control_lines_q <= 2'b00;
|
|
|
+ else if (set_control_line)
|
|
|
+ control_lines_q <= control_lines;
|
|
|
+
|
|
|
+ synchronizer #(.width(2)) ctl_synchro
|
|
|
+ (
|
|
|
+ .rst_n ( rst_n ),
|
|
|
+ .clk ( sys_clk ),
|
|
|
+ .d ( control_lines_q ),
|
|
|
+ .q ( control_lines_s )
|
|
|
+ );
|
|
|
+
|
|
|
always @(negedge rst_n or posedge sys_clk)
|
|
|
if (~rst_n)
|
|
|
begin
|
|
@@ -263,19 +285,20 @@ module usb_cdc_channel
|
|
|
assign recv_break_o = recv_break_q; // Available to external logic
|
|
|
|
|
|
tri0 [15:0] status;
|
|
|
- assign status[0] = txempty;
|
|
|
- assign status[1] = txempty | (txused_msb <= water_ctl[3:4-water_bits]);
|
|
|
- assign status[2] = txfull | (txused_msb >= water_ctl[7:8-water_bits]);
|
|
|
- assign status[3] = txfull;
|
|
|
+ assign status[0] = txempty;
|
|
|
+ assign status[1] = txempty | (txused_msb <= water_ctl[3:4-water_bits]);
|
|
|
+ assign status[2] = txfull | (txused_msb >= water_ctl[7:8-water_bits]);
|
|
|
+ assign status[3] = txfull;
|
|
|
|
|
|
- assign status[4] = rxempty;
|
|
|
- assign status[5] = rxempty | (rxused_msb <= water_ctl[11:12-water_bits]);
|
|
|
- assign status[6] = rxfull | (rxused_msb >= water_ctl[15:16-water_bits]);
|
|
|
- assign status[7] = rxfull;
|
|
|
+ assign status[4] = rxempty;
|
|
|
+ assign status[5] = rxempty | (rxused_msb <= water_ctl[11:12-water_bits]);
|
|
|
+ assign status[6] = rxfull | (rxused_msb >= water_ctl[15:16-water_bits]);
|
|
|
+ assign status[7] = rxfull;
|
|
|
|
|
|
- assign status[8] = had_rxdata[1];
|
|
|
- assign status[9] = recv_break_q;
|
|
|
- assign status[10] = usb_configured;
|
|
|
+ assign status[8] = had_rxdata[1];
|
|
|
+ assign status[9] = recv_break_q;
|
|
|
+ assign status[10] = usb_configured_s;
|
|
|
+ assign status[12:11] = control_lines_s;
|
|
|
|
|
|
reg irq_q;
|
|
|
always @(negedge rst_n or posedge sys_clk)
|
|
@@ -815,7 +838,10 @@ module usb_cdc_core
|
|
|
reg [15:0] desc_base_addr_r;
|
|
|
reg [15:0] desc_len_r;
|
|
|
|
|
|
- reg [7:0] rx_break_r;
|
|
|
+ reg rx_break_r;
|
|
|
+ reg rx_set_control_line_r;
|
|
|
+ reg [1:0] rx_control_lines_r;
|
|
|
+ reg [2:0] rx_channel_r;
|
|
|
|
|
|
reg addressed_q;
|
|
|
reg addressed_r;
|
|
@@ -841,14 +867,17 @@ module usb_cdc_core
|
|
|
|
|
|
always @ *
|
|
|
begin
|
|
|
- ctrl_stall_r = 1'b0;
|
|
|
- ctrl_ack_r = 1'b0;
|
|
|
- ctrl_send_data_r = 1'b0;
|
|
|
- device_addr_r = device_addr_q;
|
|
|
- addressed_r = addressed_q;
|
|
|
- configured_r = configured_q;
|
|
|
- set_with_data_r = set_with_data_q;
|
|
|
- rx_break_r = 8'b0;
|
|
|
+ ctrl_stall_r = 1'b0;
|
|
|
+ ctrl_ack_r = 1'b0;
|
|
|
+ ctrl_send_data_r = 1'b0;
|
|
|
+ device_addr_r = device_addr_q;
|
|
|
+ addressed_r = addressed_q;
|
|
|
+ configured_r = configured_q;
|
|
|
+ set_with_data_r = set_with_data_q;
|
|
|
+ rx_break_r = 1'b0;
|
|
|
+ rx_set_control_line_r = 1'b0;
|
|
|
+ rx_channel_r = wIndex_w[3:1];
|
|
|
+ rx_control_lines_r = wValue_w[1:0];
|
|
|
|
|
|
if (setup_valid_q)
|
|
|
begin
|
|
@@ -932,7 +961,7 @@ module usb_cdc_core
|
|
|
ctrl_ack_r = setup_set_w && setup_no_data_w;
|
|
|
set_with_data_r = setup_set_w && !setup_no_data_w;
|
|
|
|
|
|
- case (bRequest_w)
|
|
|
+ case (bRequest_w & ~wIndex_w[0])
|
|
|
`CDC_GET_LINE_CODING:
|
|
|
begin
|
|
|
$display("CDC_GET_LINE_CODING");
|
|
@@ -940,10 +969,11 @@ module usb_cdc_core
|
|
|
end
|
|
|
`CDC_SEND_BREAK:
|
|
|
begin
|
|
|
- // The break index is based on interfaces,
|
|
|
- // which is 0, 2, 4, ... for the various
|
|
|
- // channels, not endpoints.
|
|
|
- rx_break_r[wIndex_w[3:1]] = |wValue_w;
|
|
|
+ rx_break_r = |wValue_w;
|
|
|
+ end
|
|
|
+ `CDC_SET_CONTROL_LINE_STATE:
|
|
|
+ begin
|
|
|
+ rx_set_control_line_r = 1'b1;
|
|
|
end
|
|
|
default:
|
|
|
begin
|
|
@@ -1234,24 +1264,30 @@ module usb_cdc_core
|
|
|
usb_cdc_channel #(.data_ep_num ( cn*2+1 ),
|
|
|
.intr_ep_num ( cn*2+2 ))
|
|
|
cchan (
|
|
|
- .rst_n ( rst_n ),
|
|
|
- .sys_clk ( sys_clk ),
|
|
|
- .cpu_valid ( cpu_valid_cdc & cpu_addr[6:4] == cn ),
|
|
|
- .cpu_addr ( cpu_addr[3:2] ),
|
|
|
- .cpu_rdata ( rdata_chan[cn] ),
|
|
|
- .cpu_wdata ( cpu_wdata ),
|
|
|
- .cpu_wstrb ( cpu_wstrb ),
|
|
|
- .irq ( irq[cn] ),
|
|
|
-
|
|
|
- .clk_i ( clk_i ),
|
|
|
- .rst_i ( rst_i ),
|
|
|
- .data_ep ( usb_ep[cn*2+1].dstr ),
|
|
|
- .intr_ep ( usb_ep[cn*2+2].dstr ),
|
|
|
-
|
|
|
- .usb_configured ( configured_s ),
|
|
|
-
|
|
|
- .recv_break_i ( rx_break_r[cn] ),
|
|
|
- .recv_break_o ( recv_break_o[cn] ),
|
|
|
+ .rst_n ( rst_n ),
|
|
|
+ .sys_clk ( sys_clk ),
|
|
|
+ .cpu_valid ( cpu_valid_cdc & (cpu_addr[6:4] == cn) ),
|
|
|
+ .cpu_addr ( cpu_addr[3:2] ),
|
|
|
+ .cpu_rdata ( rdata_chan[cn] ),
|
|
|
+ .cpu_wdata ( cpu_wdata ),
|
|
|
+ .cpu_wstrb ( cpu_wstrb ),
|
|
|
+ .irq ( irq[cn] ),
|
|
|
+
|
|
|
+ .clk_i ( clk_i ),
|
|
|
+ .rst_i ( rst_i ),
|
|
|
+ .data_ep ( usb_ep[cn*2+1].dstr ),
|
|
|
+ .intr_ep ( usb_ep[cn*2+2].dstr ),
|
|
|
+
|
|
|
+ .usb_configured ( configured_q ),
|
|
|
+ .usb_configured_s ( configured_s ),
|
|
|
+
|
|
|
+ .recv_break_i ( rx_break_r & (rx_channel_r == cn) ),
|
|
|
+ .recv_break_o ( recv_break_o[cn] ),
|
|
|
+
|
|
|
+ .set_control_line ( rx_set_control_line_r &
|
|
|
+ (rx_channel_r == cn) ),
|
|
|
+ .control_lines ( rx_control_lines_r ),
|
|
|
+
|
|
|
.start_of_frame_s ( start_of_frame_s )
|
|
|
);
|
|
|
end // block: chan
|