-
Notifications
You must be signed in to change notification settings - Fork 50
/
new_usb_ohci.sv
200 lines (182 loc) · 6.82 KB
/
new_usb_ohci.sv
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Copyright 2024 ETH Zurich and University of Bologna.
// Solderpad Hardware License, Version 0.51, see LICENSE for details.
// SPDX-License-Identifier: SHL-0.51
//
// Fabian Hauser <[email protected]>
//
/// Main module for the direct SystemVerilog NewUSB OHCI, configured for AXI4 buses.
/// The config port is adapted to 32b Regbus, the DMA port to parametric AXI4.
/// The IOs are bundled into PULP structs and arrays to simplify connection.
// Todo: Clean up resets (every submodule).
module new_usb_ohci import new_usb_ohci_pkg::*; #(
/// DMA manager port parameters
parameter int unsigned AxiMaxReads = 0,
parameter int unsigned AxiAddrWidth = 0, // Todo: Ohci only laid out for 32 bit addresses think about 64 bit exensions
parameter int unsigned AxiDataWidth = 0, // 32|64|128 causes 4|2|1 stages in the dmaoutputqueueED
parameter int unsigned AxiIdWidth = 0,
parameter int unsigned AxiUserWidth = 0,
/// Default User and ID presented on DMA manager AR, AW, W channels.
/// In most systems, these can or should be left at '0.
parameter logic [AxiIdWidth-1:0] AxiId = '0,
parameter logic [AxiUserWidth-1:0] AxiUser = '0,
/// SoC interface types
parameter type reg_req_t = logic,
parameter type reg_rsp_t = logic,
parameter type axi_req_t = logic,
parameter type axi_rsp_t = logic
) (
/// SoC clock and reset
input logic soc_clk_i,
input logic soc_rst_ni,
/// Control subordinate port
input reg_req_t ctrl_req_i,
output reg_rsp_t ctrl_rsp_o,
/// DMA manager port
output axi_req_t dma_req_o,
input axi_rsp_t dma_rsp_i,
/// Interrupt
output logic intr_o,
/// PHY clock and reset
input logic phy_clk_i,
input logic phy_rst_ni,
/// PHY IO
input logic [NumPhyPorts-1:0] phy_dm_i,
output logic [NumPhyPorts-1:0] phy_dm_o,
output logic [NumPhyPorts-1:0] phy_dm_oe_o,
input logic [NumPhyPorts-1:0] phy_dp_i,
output logic [NumPhyPorts-1:0] phy_dp_o,
output logic [NumPhyPorts-1:0] phy_dp_oe_o
);
`include "axi/typedef.svh"
`include "common_cells/registers.svh"
logic clk_i;
logic rst_ni;
assign clk_i = soc_clk_i;
assign rst_ni = soc_rst_ni;
newusb_reg_pkg::newusb_hw2reg_t newusb_hw2reg;
newusb_reg_pkg::newusb_reg2hw_t newusb_reg2hw;
newusb_reg_top #(
.reg_req_t ( reg_req_t ),
.reg_rsp_t ( reg_rsp_t )
) i_newusb_regs (
.clk_i ( soc_clk_i ),
.rst_ni ( soc_rst_ni ),
.reg_req_i ( ctrl_req_i ), // SW HCD
.reg_rsp_o ( ctrl_rsp_o ), // SW HCD
.reg2hw ( newusb_reg2hw ), // HW HC to Reg
.hw2reg ( newusb_hw2reg ), // HW Reg to HC
.devmode_i ( 1'b1 )
);
// frame periodic/nonperiodic and its transition pulses
logic frame_periodic; // 0 if nonperiodic 1 if periodic
logic frame_periodic_prev;
logic context_switch_np2p;
logic context_switch_p2np;
`FF(frame_periodic_prev, frame_periodic, 1'b0)
assign context_switch_np2p = frame_periodic && ~frame_periodic_prev; // one cycle high nonperiodic to periodic
assign context_switch_n2np = ~frame_periodic && frame_periodic_prev; // one cyble high periodic to nonperiodic
// listservice
logic start; // start if USB goes to operational
logic counter_is_threshold;
logic nextis_valid;
logic nextis_ed;
channel nextis_type;
logic [27:0] nextis_address;
logic nextis_ready;
endpoint_descriptor processed;
logic processed_ed_store;
store_type processed_store_type;
logic [27:0] newcurrentED_o;
logic newcurrentED_valid_o;
logic id_valid;
logic [2:0] id_type;
logic sent_head;
new_usb_listservice i_listservice (
/// control
.clk_i(soc_clk_i),
.rst_ni(soc_rst_ni),
.start_i(start),
.frame_periodic_i(frame_periodic),
.counter_is_threshold_i(counter_is_threshold),
/// next ED or TD and one of the four channel types
.nextis_valid_i(nextis_valid),
.nextis_ed_i(nextis_ed),
.nextis_type_i(nextis_type),
.nextis_address_i(nextis_address),
.nextis_ready_o(nextis_ready),
/// processed
.processed,
.processed_ed_store_i(processed_ed_store), // store request
.processed_store_type_i(processed_store_type), // isochronousTD, generalTD, ED
/// newcurrentED
.newcurrentED_i(newcurrentED),
.newcurrentED_valid_i(newcurrentED_valid),
/// ID
.id_valid_o(id_valid),
.id_type_o(id_type),
/// registers
.controlbulkratio_q(reg2hw.hccontrol.cbsr.q),
.periodcurrent_ed_de_o(newusb_hw2reg.hcperiodcurrented.pced.de),
.periodcurrent_ed_d_o(newusb_hw2reg.hcperiodcurrented.pced.d),
.periodcurrent_ed_q_i(newusb_reg2hw.hcperiodcurrented.pced.q),
.controlcurrent_ed_de_o(newusb_hw2reg.hccontrolcurrented.cced.de),
.controlcurrent_ed_d_o(newusb_hw2reg.hccontrolcurrented.cced.d),
.controlcurrent_ed_q_i(newusb_reg2hw.hccontrolcurrented.cced.q),
.bulkcurrent_ed_de_o(newusb_hw2reg.hcbulkcurrented.bced.de),
.bulkcurrent_ed_d_o(newusb_hw2reg.hcbulkcurrented.bced.d),
.bulkcurrent_ed_q_i(newusb_reg2hw.hcbulkcurrented.bced.q),
.hcbulkhead_ed_de_o(newusb_hw2reg.hcbulkheaded.bhed.de),
.hcbulkhead_ed_d_o(newusb_hw2reg.hcbulkheaded.bhed.d) ,
.hcbulkhead_ed_q_i(newusb_reg2hw.hcbulkheaded.bhed.q),
.controlhead_ed_de_o(newusb_hw2reg.hccontrolheaded.ched.de),
.controlhead_ed_d_o(newusb_hw2reg.hccontrolheaded.ched.d) ,
.controlhead_ed_q_i(newusb_reg2hw.hccontrolheaded.ched.q),
/// send
.nextreadwriteaddress_o(),
.validdmaaccess_o(),
.current_type_o(),
.sent_head_o(sent_head)
);
new_usb_unpackdescriptors #(
.AxiDataWidth(AxiDataWidth)
) i_new_usb_unpackdescriptors (
/// control
.clk_i(soc_clk_i),
.rst_ni(soc_rst_ni),
.counter_is_threshold_o(counter_is_threshold),
.cbsr_i(reg2hw.hccontrol.cbsr.q),
/// nextis
.nextis_valid_o(nextis_valid), // needs to be one clock cycle
.nextis_ed_o(nextis_ed), // 0 if empty ed rerequest or td
.nextis_type_o(nextis_type),
.nextis_address_o(nextis_address),
.nextis_ready_i(nextis_ready),
/// processed
.processed,
.processed_ed_store_o(processed_ed_store), // store request
.processed_store_type_o(processed_store_type), // isochronousTD, generalTD, ED
/// newcurrentED
.newcurrentED_o(newcurrentED),
.newcurrentED_valid_o(newcurrentED_valid),
/// ID
.id_valid_i(id_valid),
.id_type_i(id_type),
/// DMA
.dma_data_i(),
.dma_valid_i(),
.dma_ready_o(),
/// periodic
.context_switch_np2p_i(context_switch_np2p),
.context_switch_p2np_i(context_switch_p2np),
/// head state
.sent_head_i(sent_head)
);
// Todo: insert DMA
assign dma_req_o = '0;
// IRQ tied-off
assign intr_o = '0;
assign phy_dm_o = '0;
assign phy_dm_oe_o = '0;
assign phy_dp_o = '0;
assign phy_dp_oe_o = '0;
endmodule