bceec5e29249b0048f0d0ca936b5b10243cc7505
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
18 __all__
= ["UART16550"]
21 class UART16550(Elaboratable
):
22 """16550 UART from opencores, nmigen wrapper. remember to call
23 UART16550.add_verilog_source
26 def __init__(self
, bus
=None, features
=None, name
=None, data_width
=32,
29 # convention: give the name in the format "name_number"
30 self
.idx
= int(name
.split("_")[-1])
34 self
.data_width
= data_width
36 # set up the wishbone bus
38 features
= frozenset()
40 bus
= Interface(addr_width
=5,
41 data_width
=data_width
,
44 name
=name
+"_wb_%d" % self
.idx
)
46 assert len(self
.bus
.dat_r
) == data_width
, \
47 "bus width must be %d" % data_width
49 # IRQ for data buffer receive/xmit
52 # 9-pin UART signals (if anyone still remembers those...)
53 self
.tx_o
= Signal() # transmit
54 self
.rx_i
= Signal() # receive
55 self
.rts_o
= Signal() # ready to send
56 self
.cts_i
= Signal() # clear to send
57 self
.dtr_o
= Signal() # data terminal ready
58 self
.dsr_i
= Signal() # data send ready
59 self
.ri_i
= Signal() # can't even remember what this is!
60 self
.dcd_i
= Signal() # or this!
66 def add_verilog_source(cls
, verilog_src_dir
, platform
):
67 # create a temp file containing "`define DATA_BUS_WIDTH_8"
68 t
= tempfile
.NamedTemporaryFile(delete
=False, suffix
=".v")
69 t
.write("`define DATA_BUS_WIDTH_8\n".encode())
72 platform
.add_file(t
.name
, t
)
74 # add each of the verilog sources, needed for when doing platform.build
75 for fname
in ['raminfr.v', 'uart_defines.v', 'uart_rfifo.v',
76 'uart_top.v', 'timescale.v', 'uart_receiver.v',
77 'uart_sync_flops.v', 'uart_transmitter.v',
78 'uart_debug_if.v', 'uart_regs.v',
79 'uart_tfifo.v', 'uart_wb.v'
81 # prepend the src directory to each filename, add its contents
82 fullname
= os
.path
.join(verilog_src_dir
, fname
)
83 with
open(fullname
) as f
:
84 platform
.add_file(fullname
, f
)
86 def elaborate(self
, platform
):
90 # create definition of external verilog 16550 uart here, so that # nmigen understands I/O directions (defined by i_ and o_ prefixes)
91 idx
, bus
= self
.idx
, self
.bus
92 uart
= Instance("uart_top",
93 # clock/reset (use DomainRenamer if needed)
94 i_wb_clk_i
=ClockSignal(),
95 i_wb_rst_i
=ResetSignal(),
96 # wishbone bus signals
100 o_wb_dat_o
=bus
.dat_r
,
107 # 9-pin RS232/UART signals
108 o_stx_pad_o
=self
.tx_o
,
109 i_srx_pad_i
=self
.rx_i
,
110 o_rts_pad_o
=self
.rts_o
,
111 i_cts_pad_i
=self
.cts_i
,
112 o_dtr_pad_o
=self
.dtr_o
,
113 i_dsr_pad_i
=self
.dsr_i
,
114 i_ri_pad_i
=self
.ri_i
,
115 i_dcd_pad_i
=self
.dcd_i
118 m
.submodules
['uart16550_%d' % self
.idx
] = uart
120 if self
.pins
is not None:
121 comb
+= self
.pins
.tx
.eq(self
.tx_o
)
122 comb
+= self
.rx_i
.eq(self
.pins
.rx
)
127 def create_ilang(dut
, ports
, test_name
):
128 vl
= rtlil
.convert(dut
, name
=test_name
, ports
=ports
)
129 with
open("%s.il" % test_name
, "w") as f
:
132 def create_verilog(dut
, ports
, test_name
):
133 vl
= verilog
.convert(dut
, name
=test_name
, ports
=ports
)
134 with
open("%s.v" % test_name
, "w") as f
:
138 if __name__
== "__main__":
139 uart
= UART16550(name
="uart_0", data_width
=8)
140 create_ilang(uart
, [uart
.bus
.cyc
, uart
.bus
.stb
, uart
.bus
.ack
,
141 uart
.bus
.dat_r
, uart
.bus
.dat_w
, uart
.bus
.adr
,
142 uart
.bus
.we
, uart
.bus
.sel
,
144 uart
.tx_o
, uart
.rx_i
, uart
.rts_o
, uart
.cts_i
,
145 uart
.dtr_o
, uart
.dsr_i
, uart
.ri_i
, uart
.dcd_i