-
Notifications
You must be signed in to change notification settings - Fork 1
/
ACIA_6850.vhd
449 lines (407 loc) · 16.5 KB
/
ACIA_6850.vhd
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
--===========================================================================--
--
-- S Y N T H E Z I A B L E ACIA 6850 C O R E
--
-- www.OpenCores.Org - January 2007
-- This core adheres to the GNU public license
--
-- Design units : 6850 ACIA core
--
-- File name : ACIA6850.vhd
--
-- Purpose : Implements an RS232 Asynchronous serial communications device
--
-- Dependencies : ieee.std_logic_1164
-- ieee.numeric_std
-- unisim.vcomponents
--
--===========================================================================--
-------------------------------------------------------------------------------
-- Revision list
-- Version Author Date Changes
--
-- 0.1 Ovidiu Lupas 15 January 2000 New model
-- 1.0 Ovidiu Lupas January 2000 Synthesis optimizations
-- 2.0 Ovidiu Lupas April 2000 Bugs removed - RSBusCtrl
-- the RSBusCtrl did not process all possible situations
--
--
-- 3.0 John Kent October 2002 Changed Status bits to match mc6805
-- Added CTS, RTS, Baud rate control
-- & Software Reset
-- 3.1 John Kent 5 January 2003 Added Word Format control a'la mc6850
-- 3.2 John Kent 19 July 2003 Latched Data input to UART
-- 3.3 John Kent 16 January 2004 Integrated clkunit in rxunit & txunit
-- Now has external TX 7 RX Baud Clock
-- inputs like the MC6850...
-- also supports x1 clock and DCD.
-- 3.4 John Kent 13 September 2005 Removed LoadCS signal.
-- Fixed ReadCS and Read in "if" in
-- miniuart_DCD_Init process
-- 3.5 John Kent 28 November 2006 Cleaned up code.
--
-- 4.0 John Kent 3 February 2007 renamed ACIA6850
-- 4.1 John Kent 6 February 2007 Made software reset synchronous
-- 4.2 John Kent 25 February 2007 Changed sensitivity lists
-- Rearranged Reset process.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-----------------------------------------------------------------------
-- Entity for ACIA_6850 --
-----------------------------------------------------------------------
entity ACIA_6850 is
port (
--
-- CPU signals
--
Clk : in Std_Logic; -- System Clock
Reset_H : in Std_Logic; -- Reset input (active high)
CS_H : in Std_Logic; -- miniUART Chip Select
Write_L : in Std_Logic; -- Read / Not Write
IRQ_L : out Std_Logic; -- Interrupt (Note its NOT open drain/open collector)
RS : in Std_Logic; -- Register Select
DataIn : in Std_Logic_Vector(7 downto 0); -- Data Bus In
DataOut : out Std_Logic_Vector(7 downto 0); -- Data Bus Out
--
-- Uart Signals
--
RxClock : in Std_Logic; -- Receive Baud Clock
TxClock : in Std_Logic; -- Transmit Baud Clock
RxData : in Std_Logic; -- Receive Data
TxData : out Std_Logic; -- Transmit Data
DCD_L : in Std_Logic; -- Data Carrier Detect
CTS_L : in Std_Logic; -- Clear To Send
RTS_L : out Std_Logic ); -- Request To send
end ACIA_6850; --================== End of entity ==============================--
-------------------------------------------------------------------------------
-- Architecture for ACIA_6850 Interface registees
-------------------------------------------------------------------------------
architecture rtl of ACIA_6850 is
type DCD_State_Type is ( DCD_State_Idle, DCD_State_Int, DCD_State_Reset );
-----------------------------------------------------------------------------
-- Signals
-----------------------------------------------------------------------------
----------------------------------------------------------------------
-- Status Register: StatReg
----------------------------------------------------------------------
--
-- IO address + 0 Read
--
-----------+--------+-------+--------+--------+--------+--------+--------+
-- Irq | PErr | OErr | FErr | CTS | DCD | TxBE | RxDR |
-----------+--------+-------+--------+--------+--------+--------+--------+
-- Irq - Bit[7] - Interrupt request
-- PErr - Bit[6] - Receive Parity error (parity bit does not match)
-- OErr - Bit[5] - Receive Overrun error (new character received before last read)
-- FErr - Bit[4] - Receive Framing Error (bad stop bit)
-- CTS - Bit[3] - Clear To Send level
-- DCD - Bit[2] - Data Carrier Detect (lost modem carrier)
-- TxBE - Bit[1] - Transmit Buffer Empty (ready to accept next transmit character)
-- RxDR - Bit[0] - Receive Data Ready (character received)
--
signal StatReg : Std_Logic_Vector(7 downto 0) := (others => '0'); -- status register
----------------------------------------------------------------------
-- Control Register: CtrlReg
----------------------------------------------------------------------
--
-- IO address + 0 Write
--
-----------+--------+--------+--------+--------+--------+--------+--------+
-- RxIEnb |TxCtl(1)|TxCtl(0)|WdFmt(2)|WdFmt(1)|WdFmt(0)|BdCtl(1)|BdCtl(0)|
-----------+--------+--------+--------+--------+--------+--------+--------+
-- RxIEnb - Bit[7]
-- 0 - Rx Interrupt disabled
-- 1 - Rx Interrupt enabled
-- TxCtl - Bits[6..5]
-- 0 1 - Tx Interrupt Enable
-- 1 0 - RTS high
-- WdFmt - Bits[4..2]
-- 0 0 0 - 7 data, even parity, 2 stop
-- 0 0 1 - 7 data, odd parity, 2 stop
-- 0 1 0 - 7 data, even parity, 1 stop
-- 0 1 1 - 7 data, odd parity, 1 stop
-- 1 0 0 - 8 data, no parity, 2 stop
-- 1 0 1 - 8 data, no parity, 1 stop
-- 1 1 0 - 8 data, even parity, 1 stop
-- 1 1 1 - 8 data, odd parity, 1 stop
-- BdCtl - Bits[1..0]
-- 0 0 - Baud Clk divide by 1
-- 0 1 - Baud Clk divide by 16
-- 1 0 - Baud Clk divide by 64
-- 1 1 - reset
signal CtrlReg : Std_Logic_Vector(7 downto 0) := (others => '0'); -- control register
----------------------------------------------------------------------
-- Receive Register
----------------------------------------------------------------------
--
-- IO address + 1 Read
--
signal RecvReg : Std_Logic_Vector(7 downto 0) := (others => '0');
----------------------------------------------------------------------
-- Transmit Register
----------------------------------------------------------------------
--
-- IO address + 1 Write
--
signal TranReg : Std_Logic_Vector(7 downto 0) := (others => '0');
signal Reset : Std_Logic; -- Reset (Software & Hardware)
signal RxRst : Std_Logic; -- Receive Reset (Software & Hardware)
signal TxRst : Std_Logic; -- Transmit Reset (Software & Hardware)
signal TxDbit : Std_Logic; -- Transmit data bit
signal RxDR : Std_Logic := '0'; -- Receive Data ready
signal TxBE : Std_Logic := '0'; -- Transmit buffer empty
signal FErr : Std_Logic := '0'; -- Frame error
signal OErr : Std_Logic := '0'; -- Output error
signal PErr : Std_Logic := '0'; -- Parity Error
signal TxIEnb : Std_Logic := '0'; -- Transmit interrupt enable
signal RxIEnb : Std_Logic := '0'; -- Receive interrupt enable
signal ReadRR : Std_Logic := '0'; -- Read receive buffer
signal WriteTR : Std_Logic := '0'; -- Write transmit buffer
signal ReadSR : Std_Logic := '0'; -- Read Status register
signal DCDState : DCD_State_Type; -- DCD Reset state sequencer
signal DCDDel : Std_Logic := '0'; -- Delayed DCD_L
signal DCDEdge : Std_Logic := '0'; -- Rising DCD_L Edge Pulse
signal DCDInt : Std_Logic := '0'; -- DCD Interrupt
signal InternalDataOut : Std_Logic_Vector(7 downto 0) ;
-----------------------------------------------------------------------------
-- ACIA Receiver
-----------------------------------------------------------------------------
component ACIA_RX
port (
Clk : in Std_Logic; -- Bus Clock signal
RxRst : in Std_Logic; -- Reset input
RxRd : in Std_Logic; -- Read data strobe
WdFmt : in Std_Logic_Vector(2 downto 0); -- word format
BdFmt : in Std_Logic_Vector(1 downto 0); -- baud format
RxClk : in Std_Logic; -- Receive clock input
RxDat : in Std_Logic; -- Receive data bit input
RxFErr : out Std_Logic; -- Framing Error Status signal
RxOErr : out Std_Logic; -- Overrun Error Status signal
RxPErr : out Std_logic; -- Parity Error Status signal
RxRdy : out Std_Logic; -- Data Ready Status signal
RxDout : out Std_Logic_Vector(7 downto 0));-- Receive data bus output
end component;
-----------------------------------------------------------------------------
-- ACIA Transmitter
-----------------------------------------------------------------------------
component ACIA_TX
port (
Clk : in Std_Logic; -- Bus Clock signal
TxRst : in Std_Logic; -- Reset input
TxWr : in Std_Logic; -- Load transmit data strobe
TxDin : in Std_Logic_Vector(7 downto 0); -- Transmit data bus input
WdFmt : in Std_Logic_Vector(2 downto 0); -- Word format Control signal
BdFmt : in Std_Logic_Vector(1 downto 0); -- Baud format Control signal
TxClk : in Std_Logic; -- Transmit clock input
TxDat : out Std_Logic; -- Transmit data bit output
TxEmp : out Std_Logic ); -- Tx buffer empty status signal
end component;
begin
-----------------------------------------------------------------------------
-- Instantiation of internal components
-----------------------------------------------------------------------------
RxDev : ACIA_RX port map (
Clk => clk,
RxRst => RxRst,
RxRd => ReadRR,
WdFmt => CtrlReg(4 downto 2),
BdFmt => CtrlReg(1 downto 0),
RxClk => RxClock,
RxDat => RxData,
RxFErr => FErr,
RxOErr => OErr,
RxPErr => PErr,
RxRdy => RxDR,
RxDout => RecvReg
);
TxDev : ACIA_TX port map (
Clk => clk,
TxRst => TxRst,
TxWr => WriteTR,
TxDin => TranReg,
WdFmt => CtrlReg(4 downto 2),
BdFmt => CtrlReg(1 downto 0),
TxClk => TxClock,
TxDat => TxDbit,
TxEmp => TxBE
);
---------------------------------------------------------------
-- ACIA Reset may be hardware or software
---------------------------------------------------------------
ACIA_Reset : process( clk, Reset_H, Reset, DCD_L )
begin
-- Asynchronous External reset
if Reset_H = '1' then
Reset <= '1';
elsif clk'Event and clk = '0' then
-- Synchronous Software reset
Reset <= CtrlReg(1) and CtrlReg(0);
end if;
-- Transmitter reset
TxRst <= Reset;
-- Receiver reset
RxRst <= Reset or DCD_L;
end process;
-----------------------------------------------------------------------------
-- ACIA Status Register
-----------------------------------------------------------------------------
--
--ACIA_Status : process(clk, Reset, TxIEnb, RxIEnb,
-- RxDR, TxBE, DCD_L, CTS_n, DCDInt,
-- FErr, OErr, PErr )
ACIA_Status : process(Reset, clk )
begin
if Reset = '1' then
StatReg <= (others => '0');
elsif clk'event and clk='0' then
StatReg(0) <= RxDR; -- Receive Data Ready
StatReg(1) <= TxBE and (not CTS_L); -- Transmit Buffer Empty
StatReg(2) <= DCDInt; -- Data Carrier Detect
StatReg(3) <= CTS_L; -- Clear To Send
StatReg(4) <= FErr; -- Framing error
StatReg(5) <= OErr; -- Overrun error
StatReg(6) <= PErr; -- Parity error
StatReg(7) <= (RxIEnb and RxDR) or
(RxIEnb and DCDInt) or
(TxIEnb and TxBE);
end if;
end process;
-----------------------------------------------------------------------------
-- ACIA Transmit Control
-----------------------------------------------------------------------------
ACIA_Control : process( CtrlReg, TxDbit )
begin
case CtrlReg(6 downto 5) is
when "00" => -- Disable TX Interrupts, Assert RTS
RTS_L <= '0';
TxData <= TxDbit;
TxIEnb <= '0';
when "01" => -- Enable TX interrupts, Assert RTS
RTS_L <= '0';
TxData <= TxDbit;
TxIEnb <= '1';
when "10" => -- Disable Tx Interrupts, Clear RTS
RTS_L <= '1';
TxData <= TxDbit;
TxIEnb <= '0';
when "11" => -- Disable Tx interrupts, Assert RTS, send break
RTS_L <= '0';
TxData <= '0';
TxIEnb <= '0';
when others =>
null;
end case;
RxIEnb <= CtrlReg(7);
end process;
-----------------------------------------------------------------------------
-- Generate Read / Write strobes.
-----------------------------------------------------------------------------
--ACIA_Read_Write: process(clk, Reset, cs, rw, Addr, DataIn )
ACIA_Read_Write: process(clk, Reset )
begin
if reset = '1' then
CtrlReg <= (others => '0');
TranReg <= (others => '0');
ReadRR <= '0';
WriteTR <= '0';
ReadSR <= '0';
elsif clk'event and clk='0' then
ReadRR <= '0';
WriteTR <= '0';
ReadSR <= '0';
if CS_H = '1' then
if RS = '0' then -- Control / Status register
if Write_L = '0' then -- write control register
CtrlReg <= DataIn;
else -- read status register
ReadSR <= '1';
end if;
else -- Data Register
if Write_L = '0' then -- write transmiter register
TranReg <= DataIn;
WriteTR <= '1';
else -- read receiver register
ReadRR <= '1';
end if; -- Write_L
end if; -- Addr
end if; -- cs
end if; -- clk / reset
end process;
---------------------------------------------------------------
-- Set Data Output Multiplexer
--------------------------------------------------------------
ACIA_Data_Mux: process(RS, StatReg, RecvReg)
begin
if RS = '1' then
InternalDataOut <= RecvReg; -- read receiver register
else
InternalDataOut <= StatReg; -- read status register
end if; -- Addr
irq_l <= not StatReg(7); -- active low IRQ inverse of bit in status register
end process;
---------------------------------------------------------------
-- Tri_State Data Output Controller
--------------------------------------------------------------
ACIA_DataOut: process(CS_H, Write_L, InternalDataOut)
begin
if(CS_H = '1' and Write_L = '1') then
DataOut <= InternalDataOut ;
else
DataOut <= "ZZZZZZZZ"; -- else tri-state
end if;
end process;
---------------------------------------------------------------
-- Data Carrier Detect Edge rising edge detect
---------------------------------------------------------------
ACIA_DCD_edge : process( reset, clk )
begin
if reset = '1' then
DCDEdge <= '0';
DCDDel <= '0';
elsif clk'event and clk = '0' then
DCDDel <= DCD_L;
DCDEdge <= DCD_L and (not DCDDel);
end if;
end process;
---------------------------------------------------------------
-- Data Carrier Detect Interrupt
---------------------------------------------------------------
-- If Data Carrier is lost, an interrupt is generated
-- To clear the interrupt, first read the status register
-- then read the data receive register
--
ACIA_DCD_Int : process( reset, clk )
begin
if reset = '1' then
DCDInt <= '0';
DCDState <= DCD_State_Idle;
elsif clk'event and clk = '0' then
case DCDState is
when DCD_State_Idle =>
-- DCD Edge activates interrupt
if DCDEdge = '1' then
DCDInt <= '1';
DCDState <= DCD_State_Int;
end if;
when DCD_State_Int =>
-- To reset DCD interrupt,
-- First read status
if ReadSR = '1' then
DCDState <= DCD_State_Reset;
end if;
when DCD_State_Reset =>
-- Then read receive register
if ReadRR = '1' then
DCDInt <= '0';
DCDState <= DCD_State_Idle;
end if;
when others =>
null;
end case;
end if; -- clk / reset
end process;
end rtl; --===================== End of architecture =======================--