366696e977a0993d603eb7fafedcf57e333dce25
[soc.git] / src / soc / bus / uart_16550.py
1 #!/usr/bin/env python3
2 #
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.
7 #
8 # this is a wrapper around the opencores verilog uart16550 module
9
10 from nmigen import (Elaboratable, Cat, Module, Signal, ClockSignal, Instance,
11 ResetSignal)
12
13 from nmigen_soc.wishbone.bus import Interface
14 from nmigen.cli import rtlil, verilog
15 import os
16
17 __all__ = ["UART16550"]
18
19
20 class UART16550(Elaboratable):
21 """16550 UART from opencores, nmigen wrapper. remember to call
22 UART16550.add_verilog_source
23 """
24
25 def __init__(self, bus=None, features=None, name=None, data_width=32,
26 pins=None):
27 if name is not None:
28 # convention: give the name in the format "name_number"
29 self.idx = int(name.split("_")[-1])
30 else:
31 self.idx = 0
32 name = "uart_0"
33 self.data_width = data_width
34
35 # set up the wishbone bus
36 if features is None:
37 features = frozenset()
38 if bus is None:
39 bus = Interface(addr_width=5,
40 data_width=data_width,
41 features=features,
42 granularity=8,
43 name=name+"_wb_%d" % self.idx)
44 self.bus = bus
45 assert len(self.bus.dat_r) == data_width, \
46 "bus width must be %d" % data_width
47
48 # IRQ for data buffer receive/xmit
49 self.irq = Signal()
50
51 # 9-pin UART signals (if anyone still remembers those...)
52 self.tx_o = Signal() # transmit
53 self.rx_i = Signal() # receive
54 self.rts_o = Signal() # ready to send
55 self.cts_i = Signal() # clear to send
56 self.dtr_o = Signal() # data terminal ready
57 self.dsr_i = Signal() # data send ready
58 self.ri_i = Signal() # can't even remember what this is!
59 self.dcd_i = Signal() # or this!
60
61 # pins resource
62 self.pins = pins
63
64 @classmethod
65 def add_verilog_source(cls, verilog_src_dir, platform):
66 # add each of the verilog sources, needed for when doing platform.build
67 for fname in ['raminfr.v', 'uart_defines.v', 'uart_rfifo.v',
68 'uart_top.v', 'timescale.v', 'uart_receiver.v',
69 'uart_sync_flops.v', 'uart_transmitter.v',
70 'uart_debug_if.v', 'uart_regs.v',
71 'uart_tfifo.v', 'uart_wb.v'
72 ]:
73 # prepend the src directory to each filename, add its contents
74 fullname = os.path.join(verilog_src_dir, fname)
75 with open(fullname) as f:
76 platform.add_file(fullname, f)
77
78 def elaborate(self, platform):
79 m = Module()
80 comb = m.d.comb
81
82 # create definition of external verilog 16550 uart here, so that # nmigen understands I/O directions (defined by i_ and o_ prefixes)
83 idx, bus = self.idx, self.bus
84 uart = Instance("uart_top",
85 # clock/reset (use DomainRenamer if needed)
86 i_wb_clk_i=ClockSignal(),
87 i_wb_rst_i=ResetSignal(),
88 # wishbone bus signals
89 i_wb_adr_i=bus.adr,
90 i_wb_dat_i=bus.dat_w,
91 i_wb_sel_i=bus.sel,
92 o_wb_dat_o=bus.dat_r,
93 i_wb_we_i=bus.we,
94 i_wb_stb_i=bus.stb,
95 i_wb_cyc_i=bus.cyc,
96 o_wb_ack_o=bus.ack,
97 # interrupt line
98 o_int_o=self.irq,
99 # 9-pin RS232/UART signals
100 o_stx_pad_o=self.tx_o,
101 i_srx_pad_i=self.rx_i,
102 o_rts_pad_o=self.rts_o,
103 i_cts_pad_i=self.cts_i,
104 o_dtr_pad_o=self.dtr_o,
105 i_dsr_pad_i=self.dsr_i,
106 i_ri_pad_i=self.ri_i,
107 i_dcd_pad_i=self.dcd_i
108 );
109
110 m.submodules['uart16550_%d' % self.idx] = uart
111
112 if self.pins is not None:
113 comb += self.pins.tx.eq(self.tx_o)
114 comb += self.rx_i.eq(self.pins.rx)
115
116 return m
117
118
119 def create_ilang(dut, ports, test_name):
120 vl = rtlil.convert(dut, name=test_name, ports=ports)
121 with open("%s.il" % test_name, "w") as f:
122 f.write(vl)
123
124 def create_verilog(dut, ports, test_name):
125 vl = verilog.convert(dut, name=test_name, ports=ports)
126 with open("%s.v" % test_name, "w") as f:
127 f.write(vl)
128
129
130 if __name__ == "__main__":
131 uart = UART16550(name="uart_0", data_width=8)
132 create_ilang(uart, [uart.bus.cyc, uart.bus.stb, uart.bus.ack,
133 uart.bus.dat_r, uart.bus.dat_w, uart.bus.adr,
134 uart.bus.we, uart.bus.sel,
135 uart.irq,
136 uart.tx_o, uart.rx_i, uart.rts_o, uart.cts_i,
137 uart.dtr_o, uart.dsr_i, uart.ri_i, uart.dcd_i
138 ], "uart_0")
139