3 # SPDX-License-Identifier: LGPLv3+
4 # Copyright (C) 2022 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
5 # Sponsored by NLnet and NGI POINTER under EU Grants 871528 and 957073
6 # Part of the Libre-SOC Project.
8 # this is a wrapper around the opencores verilog uart16550 module
10 from nmigen
import (Elaboratable
, Cat
, Module
, Signal
, ClockSignal
, Instance
,
13 from nmigen_soc
.wishbone
.bus
import Interface
14 from nmigen
.cli
import rtlil
, verilog
17 __all__
= ["UART16550"]
20 class UART16550(Elaboratable
):
21 """16550 UART from opencores, nmigen wrapper. remember to call
22 UART16550.add_verilog_source
25 def __init__(self
, bus
=None, features
=None, name
=None, data_width
=32):
27 # convention: give the name in the format "name_number"
28 self
.idx
= int(name
.split("_")[-1])
33 # set up the wishbone bus
35 features
= frozenset()
37 bus
= Interface(addr_width
=5,
38 data_width
=data_width
,
41 name
=name
+"_wb_%d" % self
.idx
)
43 assert len(self
.bus
.dat_r
) == data_width
, \
44 "bus width must be %d" % data_width
46 # IRQ for data buffer receive/xmit
49 # 9-pin UART signals (if anyone still remembers those...)
50 self
.tx_o
= Signal() # transmit
51 self
.rx_i
= Signal() # receive
52 self
.rts_o
= Signal() # ready to send
53 self
.cts_i
= Signal() # clear to send
54 self
.dtr_o
= Signal() # data terminal ready
55 self
.dsr_i
= Signal() # data send ready
56 self
.ri_i
= Signal() # can't even remember what this is!
57 self
.dcd_i
= Signal() # or this!
60 def add_verilog_source(cls
, verilog_src_dir
, platform
):
61 # add each of the verilog sources, needed for when doing platform.build
62 for fname
in ['raminfr.v', 'uart_defines.v', 'uart_rfifo.v',
63 'uart_top.v', 'timescale.v', 'uart_receiver.v',
64 'uart_sync_flops.v', 'uart_transmitter.v',
65 'uart_debug_if.v', 'uart_regs.v',
66 'uart_tfifo.v', 'uart_wb.v'
68 # prepend the src directory to each filename, add its contents
69 fullname
= os
.path
.join(verilog_src_dir
, fname
)
70 with
open(fullname
) as f
:
71 platform
.add_file(fullname
, f
)
73 def elaborate(self
, platform
):
76 # create definition of external verilog 16550 uart here, so that # nmigen understands I/O directions (defined by i_ and o_ prefixes)
77 idx
, bus
= self
.idx
, self
.bus
78 uart
= Instance("uart_top",
79 # clock/reset (use DomainRenamer if needed)
80 i_wb_clk_i
=ClockSignal(),
81 i_wb_rst_i
=ResetSignal(),
82 # wishbone bus signals
93 # 9-pin RS232/UART signals
94 o_stx_pad_o
=self
.tx_o
,
95 i_srx_pad_i
=self
.rx_i
,
96 o_rts_pad_o
=self
.rts_o
,
97 i_cts_pad_i
=self
.cts_i
,
98 o_dtr_pad_o
=self
.dtr_o
,
99 i_dsr_pad_i
=self
.dsr_i
,
100 i_ri_pad_i
=self
.ri_i
,
101 i_dcd_pad_i
=self
.dcd_i
104 m
.submodules
['uart16550_%d' % self
.idx
] = uart
109 def create_ilang(dut
, ports
, test_name
):
110 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
111 with
open("%s.il" % test_name
, "w") as f
:
114 def create_verilog(dut
, ports
, test_name
):
115 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
116 with
open("%s.v" % test_name
, "w") as f
:
120 if __name__
== "__main__":
121 uart
= UART16550(name
="uart_0", data_width
=8)
122 create_ilang(uart
, [uart
.bus
.cyc
, uart
.bus
.stb
, uart
.bus
.ack
,
123 uart
.bus
.dat_r
, uart
.bus
.dat_w
, uart
.bus
.adr
,
124 uart
.bus
.we
, uart
.bus
.sel
,
126 uart
.tx_o
, uart
.rx_i
, uart
.rts_o
, uart
.cts_i
,
127 uart
.dtr_o
, uart
.dsr_i
, uart
.ri_i
, uart
.dcd_i