1 |
9 |
nuubik |
library ieee;
|
2 |
|
|
use ieee.std_logic_1164.all;
|
3 |
|
|
use IEEE.std_logic_unsigned.all;
|
4 |
|
|
use IEEE.std_logic_arith.all;
|
5 |
|
|
use work.serial_usb_package.all;
|
6 |
|
|
use work.dongle_arch.all;
|
7 |
|
|
|
8 |
|
|
|
9 |
|
|
entity serial_usb is
|
10 |
|
|
port(
|
11 |
|
|
clock : in std_logic;
|
12 |
|
|
reset_n : in std_logic;
|
13 |
|
|
--VCI Port
|
14 |
|
|
vci_in : in vci_slave_in;
|
15 |
|
|
vci_out : out vci_slave_out;
|
16 |
|
|
--FTDI fifo interface
|
17 |
|
|
uart_ena : in usbser_ctrl;
|
18 |
|
|
fifo_out : out usb_out;
|
19 |
|
|
fifo_in : in usb_in
|
20 |
|
|
);
|
21 |
|
|
end entity serial_usb;
|
22 |
|
|
|
23 |
|
|
architecture rtl of serial_usb is
|
24 |
|
|
|
25 |
|
|
type reg_type is
|
26 |
|
|
record
|
27 |
|
|
uart : uart_registers;
|
28 |
|
|
fifo : usb_out;
|
29 |
|
|
fifo_sync: usb_in;
|
30 |
|
|
vci : vci_slave_out;
|
31 |
|
|
pc_loop : boolean;
|
32 |
|
|
vci_write_pending : boolean;
|
33 |
|
|
vci_read_pending : boolean;
|
34 |
|
|
tx_timer : std_logic_vector(2 downto 0);
|
35 |
|
|
rx_timer : std_logic_vector(2 downto 0);
|
36 |
|
|
ftdi_precharge : std_logic_vector(2 downto 0); --time between cycles
|
37 |
|
|
end record;
|
38 |
|
|
|
39 |
|
|
signal reg, reg_in : reg_type;
|
40 |
|
|
|
41 |
|
|
begin
|
42 |
|
|
|
43 |
|
|
-- Design pattern process 1 Implementation
|
44 |
|
|
comb : process (vci_in,uart_ena,reg)
|
45 |
|
|
variable reg_v : reg_type;
|
46 |
|
|
begin
|
47 |
|
|
-- Design pattern
|
48 |
|
|
reg_v:=reg; --pre set default var state
|
49 |
|
|
|
50 |
|
|
|
51 |
|
|
--
|
52 |
|
|
--Debug code send repeating "0123456789" to UART
|
53 |
|
|
--
|
54 |
|
|
-- if reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH)='1' then
|
55 |
|
|
-- reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='0'; --set TX filled
|
56 |
|
|
-- reg_v.uart.txhold.reg(3 downto 0):= reg_v.uart.txhold.reg(3 downto 0)+1;
|
57 |
|
|
-- if reg_v.uart.txhold.reg(3 downto 0)=x"A" then
|
58 |
|
|
-- reg_v.uart.txhold.reg(3 downto 0):=x"0";
|
59 |
|
|
-- end if;
|
60 |
|
|
-- reg_v.uart.txhold.reg(7 downto 4):=x"3";
|
61 |
|
|
-- end if;
|
62 |
|
|
|
63 |
|
|
------------------------------------
|
64 |
|
|
--- <implementation> ---
|
65 |
|
|
------------------------------------
|
66 |
|
|
|
67 |
|
|
|
68 |
|
|
--reduce precharge counter always
|
69 |
|
|
if reg_v.ftdi_precharge>"000" then
|
70 |
|
|
reg_v.ftdi_precharge:=reg_v.ftdi_precharge - 1;
|
71 |
|
|
end if;
|
72 |
|
|
|
73 |
|
|
--VCI write access request
|
74 |
|
|
if vci_in.lpc_val='1' and vci_in.lpc_wr='1' and reg_v.vci.lpc_ack='0' then
|
75 |
|
|
reg_v.vci_write_pending:=true;
|
76 |
|
|
end if;
|
77 |
|
|
|
78 |
|
|
--VCI read access request
|
79 |
|
|
if vci_in.lpc_val='1' and vci_in.lpc_wr='0' and reg_v.vci.lpc_ack='0' then
|
80 |
|
|
reg_v.vci_read_pending:=true;
|
81 |
|
|
end if;
|
82 |
|
|
|
83 |
|
|
--Writable conf registers
|
84 |
|
|
if reg_v.vci_write_pending then --write decode
|
85 |
|
|
case vci_in.lpc_addr(2 downto 0) is
|
86 |
|
|
when "000" =>
|
87 |
|
|
--select DLAB or not
|
88 |
|
|
if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Line Control Register (LCR) SEL_LCR_DLAB
|
89 |
|
|
reg_v.uart.txhold.reg:=vci_in.lpc_data_o; --Transmitter Holding Buffer
|
90 |
|
|
clr_uart_tx_int(reg_v.uart); --clear tx on tx buff write
|
91 |
|
|
if reg_v.uart.mcr.reg(SEL_MCR_LOOP)='0' then --loop not endabled
|
92 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='0'; -- TX not empty
|
93 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_EMPTY_DH):='0'; -- TX not empty
|
94 |
|
|
else --do local loop
|
95 |
|
|
reg_v.uart.rxbuff.reg:=reg_v.uart.txhold.reg;
|
96 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_DATARDY):='1'; --set data ready in register
|
97 |
|
|
set_uart_rx_int(reg_v.uart);
|
98 |
|
|
end if;
|
99 |
|
|
else
|
100 |
|
|
reg_v.uart.div_low.reg:=vci_in.lpc_data_o; --Divisor Latch Low Byte
|
101 |
|
|
end if;
|
102 |
|
|
when "001" =>
|
103 |
|
|
--select DLAB or not
|
104 |
|
|
if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Line Control Register (LCR) SEL_LCR_DLAB
|
105 |
|
|
reg_v.uart.ier.reg:=vci_in.lpc_data_o; --Interrupt Enable Register
|
106 |
|
|
else
|
107 |
|
|
reg_v.uart.div_high.reg:=vci_in.lpc_data_o; --Divisor Latch High Byte
|
108 |
|
|
end if;
|
109 |
|
|
when "011" => -- +3
|
110 |
|
|
reg_v.uart.lcr.reg:=vci_in.lpc_data_o; --Line Control Register (don't care except DLA bit)
|
111 |
|
|
when "100" => -- +4
|
112 |
|
|
reg_v.uart.mcr.reg:=vci_in.lpc_data_o; --Modem Control Register (don't care except loopback)
|
113 |
|
|
reg_v.uart.mcr.reg(SEL_MCR_FLWCTRL):='0'; --this is not supported so auto clear
|
114 |
|
|
when "111" => -- +7
|
115 |
|
|
reg_v.uart.scr.reg:=vci_in.lpc_data_o;
|
116 |
|
|
when others =>
|
117 |
|
|
null;
|
118 |
|
|
end case;
|
119 |
|
|
--we must ack the write always
|
120 |
|
|
reg_v.vci_write_pending:= false;
|
121 |
|
|
reg_v.vci.lpc_ack:='1'; --ack all writes to non writable addresses for VCI to work
|
122 |
|
|
end if;
|
123 |
|
|
|
124 |
|
|
--Readable conf registers
|
125 |
|
|
if reg_v.vci_read_pending then --write decode
|
126 |
|
|
case vci_in.lpc_addr(2 downto 0) is
|
127 |
|
|
when "000" =>
|
128 |
|
|
--select DLAB or not
|
129 |
|
|
if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Line Control Register (LCR) SEL_LCR_DLAB
|
130 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.rxbuff.reg; --RX read data
|
131 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_DATARDY):='0'; --data has been read
|
132 |
|
|
clr_uart_rx_int(reg_v.uart);
|
133 |
|
|
else
|
134 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.div_low.reg;
|
135 |
|
|
end if;
|
136 |
|
|
when "001" =>
|
137 |
|
|
if reg_v.uart.lcr.reg(SEL_LCR_DLAB)='0' then --Interrupt Enable Register (IER) SEL_LCR_DLAB
|
138 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.ier.reg;
|
139 |
|
|
else --Divisor Latch High Byte
|
140 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.div_high.reg;
|
141 |
|
|
end if;
|
142 |
|
|
when "010" =>
|
143 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.iir.reg; -- Interrupt Identification Register(IIR)
|
144 |
|
|
clr_uart_tx_int(reg_v.uart); --clear tx on iir read
|
145 |
|
|
when "011" =>
|
146 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.lcr.reg;
|
147 |
|
|
when "100" =>
|
148 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.mcr.reg;
|
149 |
|
|
when "101" =>
|
150 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.lsr.reg;
|
151 |
|
|
when "110" =>
|
152 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.msr.reg;
|
153 |
|
|
when "111" =>
|
154 |
|
|
reg_v.vci.lpc_data_i:=reg_v.uart.scr.reg;
|
155 |
|
|
when others =>
|
156 |
|
|
reg_v.vci.lpc_data_i:=(others=>'0'); -- return 0
|
157 |
|
|
end case;
|
158 |
|
|
--we must ack the read always
|
159 |
|
|
reg_v.vci_read_pending:= false;
|
160 |
|
|
reg_v.vci.lpc_ack:='1'; --ack all reads to non readable addresses for VCI to work
|
161 |
|
|
end if;
|
162 |
|
|
|
163 |
|
|
--UART Register state change handling
|
164 |
|
|
--TX haldler
|
165 |
|
|
if reg_v.fifo.rx_oe_n='1' and reg_v.ftdi_precharge="000" and reg_v.fifo_sync.tx_empty_n='0' and reg_v.tx_timer="000" and reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH)='0' then --No ongoing read and can and has something to TX
|
166 |
|
|
reg_v.fifo.txdata:=reg_v.uart.txhold.reg;
|
167 |
|
|
reg_v.fifo.tx_wr:='1';
|
168 |
|
|
reg_v.tx_timer:="011"; --FDTI fifo timing 40 ns needed for write pulse high
|
169 |
|
|
end if;
|
170 |
|
|
if reg_v.tx_timer>"000" then -- TX cycle timer
|
171 |
|
|
reg_v.tx_timer:=reg_v.tx_timer-1;
|
172 |
|
|
if reg_v.tx_timer="000" then
|
173 |
|
|
reg_v.fifo.tx_wr:='0'; -- write happens on falling edge '''\,,,
|
174 |
|
|
reg_v.ftdi_precharge:="011"; --start cycle cap
|
175 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='1'; -- all sent
|
176 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_EMPTY_DH):='1'; -- ready for new data
|
177 |
|
|
set_uart_tx_int(reg_v.uart);
|
178 |
|
|
end if;
|
179 |
|
|
end if;
|
180 |
|
|
--RX Handler
|
181 |
|
|
|
182 |
|
|
|
183 |
|
|
if (not reg_v.pc_loop) or reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH)='1' then
|
184 |
|
|
if reg_v.fifo.tx_wr='0'and reg_v.ftdi_precharge="000" and reg_v.fifo_sync.rx_full_n='0' and reg_v.rx_timer="000" and reg_v.uart.lsr.reg(SEL_LSR_DATARDY)='0' then -- no ongoing TX and data in FTDI fifo and read buffer has been read
|
185 |
|
|
reg_v.fifo.rx_oe_n:='0'; -- output enable
|
186 |
|
|
reg_v.rx_timer:="100";
|
187 |
|
|
end if;
|
188 |
|
|
if reg_v.rx_timer>"000" then --RX cycle timer
|
189 |
|
|
reg_v.rx_timer:=reg_v.rx_timer-1;
|
190 |
|
|
if reg_v.rx_timer="000" then
|
191 |
|
|
reg_v.fifo.rx_oe_n:='1'; -- read happens on rising front ,,,,/'''' of oe_n
|
192 |
|
|
reg_v.ftdi_precharge:="101"; --start cycle cap
|
193 |
|
|
reg_v.uart.rxbuff.reg:=reg_v.fifo_sync.rxdata;
|
194 |
|
|
if reg_v.pc_loop then --pc test loop
|
195 |
|
|
reg_v.uart.txhold.reg:=reg_v.fifo_sync.rxdata;
|
196 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_EMPTY_TXH):='0'; --do transmit
|
197 |
|
|
else
|
198 |
|
|
reg_v.uart.lsr.reg(SEL_LSR_DATARDY):='1'; --set data ready in register
|
199 |
|
|
set_uart_rx_int(reg_v.uart);
|
200 |
|
|
end if;
|
201 |
|
|
end if;
|
202 |
|
|
end if;
|
203 |
|
|
end if;
|
204 |
|
|
|
205 |
|
|
--UART Interrupt
|
206 |
|
|
if reg_v.uart.iir.reg(SEL_IIR_PENDING_N)='0' then
|
207 |
|
|
reg_v.vci.lpc_irq:='1'; --set up int signal
|
208 |
|
|
else
|
209 |
|
|
reg_v.vci.lpc_irq:='0';
|
210 |
|
|
end if;
|
211 |
|
|
--End UART
|
212 |
|
|
|
213 |
|
|
--VCI request end, clear ack when val drops
|
214 |
|
|
if vci_in.lpc_val='0' and reg_v.vci.lpc_ack='1' then
|
215 |
|
|
reg_v.vci.lpc_ack:='0';
|
216 |
|
|
end if;
|
217 |
|
|
|
218 |
|
|
|
219 |
|
|
-- Design pattern
|
220 |
|
|
-- drive register input signals
|
221 |
|
|
reg_in<=reg_v;
|
222 |
|
|
-- drive module outputs signals
|
223 |
|
|
--port_comb_out<= reg_v.port_comb; --combinatorial output
|
224 |
|
|
--port_reg_out<= reg.port_reg; --registered output
|
225 |
|
|
vci_out<=reg.vci;
|
226 |
|
|
fifo_out<= reg.fifo;
|
227 |
|
|
end process;
|
228 |
|
|
|
229 |
|
|
-- Pattern process 2, Registers
|
230 |
|
|
regs : process (clock,reset_n)
|
231 |
|
|
begin
|
232 |
|
|
if reset_n='0' then
|
233 |
|
|
reg.pc_loop<=false;
|
234 |
|
|
reg.rx_timer<=(others=>'0');
|
235 |
|
|
reg.tx_timer<=(others=>'0');
|
236 |
|
|
reg.ftdi_precharge<=(others=>'0');
|
237 |
|
|
reg.vci_read_pending<=false;
|
238 |
|
|
reg.vci_write_pending<=false;
|
239 |
|
|
uart_reset(reg.uart);
|
240 |
|
|
fifo_reset(reg.fifo);
|
241 |
|
|
vci_slave_reset(reg.vci);
|
242 |
|
|
elsif rising_edge(clock) then
|
243 |
|
|
reg<=reg_in;
|
244 |
|
|
reg.fifo_sync<=fifo_in;
|
245 |
|
|
end if;
|
246 |
|
|
end process;
|
247 |
|
|
|
248 |
|
|
|
249 |
|
|
end rtl;
|