diplomacy: update to new API (#40)
[sifive-blocks.git] / src / main / scala / devices / uart / UART.scala
1 // See LICENSE for license details.
2 package sifive.blocks.devices.uart
3
4 import Chisel._
5 import chisel3.experimental.MultiIOModule
6 import freechips.rocketchip.config.Parameters
7 import freechips.rocketchip.regmapper._
8 import freechips.rocketchip.tilelink._
9 import freechips.rocketchip.util._
10
11 import sifive.blocks.util.{NonBlockingEnqueue, NonBlockingDequeue}
12
13 case class UARTParams(
14 address: BigInt,
15 dataBits: Int = 8,
16 stopBits: Int = 2,
17 divisorInit: Int = 0,
18 divisorBits: Int = 16,
19 oversample: Int = 4,
20 nSamples: Int = 3,
21 nTxEntries: Int = 8,
22 nRxEntries: Int = 8)
23
24 trait HasUARTParameters {
25 def c: UARTParams
26 def uartDataBits = c.dataBits
27 def uartStopBits = c.stopBits
28 def uartDivisorInit = c.divisorInit
29 def uartDivisorBits = c.divisorBits
30
31 def uartOversample = c.oversample
32 def uartOversampleFactor = 1 << uartOversample
33 def uartNSamples = c.nSamples
34
35 def uartNTxEntries = c.nTxEntries
36 def uartNRxEntries = c.nRxEntries
37
38 require(uartDivisorInit != 0) // should have been initialized during instantiation
39 require(uartDivisorBits > uartOversample)
40 require(uartOversampleFactor > uartNSamples)
41 }
42
43 abstract class UARTModule(val c: UARTParams)(implicit val p: Parameters)
44 extends Module with HasUARTParameters
45
46 class UARTPortIO extends Bundle {
47 val txd = Bool(OUTPUT)
48 val rxd = Bool(INPUT)
49 }
50
51 trait HasUARTTopBundleContents extends Bundle {
52 val port = new UARTPortIO
53 }
54
55 class UARTTx(c: UARTParams)(implicit p: Parameters) extends UARTModule(c)(p) {
56 val io = new Bundle {
57 val en = Bool(INPUT)
58 val in = Decoupled(Bits(width = uartDataBits)).flip
59 val out = Bits(OUTPUT, 1)
60 val div = UInt(INPUT, uartDivisorBits)
61 val nstop = UInt(INPUT, log2Up(uartStopBits))
62 }
63
64 val prescaler = Reg(init = UInt(0, uartDivisorBits))
65 val pulse = (prescaler === UInt(0))
66
67 private val n = uartDataBits + 1
68 val counter = Reg(init = UInt(0, log2Floor(n + uartStopBits) + 1))
69 val shifter = Reg(Bits(width = n))
70 val out = Reg(init = Bits(1, 1))
71 io.out := out
72
73 val plusarg_tx = PlusArg("uart_tx", 1, "Enable/disable the TX to speed up simulation").orR
74
75 val busy = (counter =/= UInt(0))
76 io.in.ready := io.en && !busy
77 when (io.in.fire()) {
78 printf("UART TX (%x): %c\n", io.in.bits, io.in.bits)
79 }
80 when (io.in.fire() && plusarg_tx) {
81 shifter := Cat(io.in.bits, Bits(0, 1))
82 counter := Mux1H((0 until uartStopBits).map(i =>
83 (io.nstop === UInt(i)) -> UInt(n + i + 1)))
84 }
85 when (busy) {
86 prescaler := Mux(pulse, io.div, prescaler - UInt(1))
87 }
88 when (pulse && busy) {
89 counter := counter - UInt(1)
90 shifter := Cat(Bits(1, 1), shifter >> 1)
91 out := shifter(0)
92 }
93 }
94
95 class UARTRx(c: UARTParams)(implicit p: Parameters) extends UARTModule(c)(p) {
96 val io = new Bundle {
97 val en = Bool(INPUT)
98 val in = Bits(INPUT, 1)
99 val out = Valid(Bits(width = uartDataBits))
100 val div = UInt(INPUT, uartDivisorBits)
101 }
102
103 val debounce = Reg(init = UInt(0, 2))
104 val debounce_max = (debounce === UInt(3))
105 val debounce_min = (debounce === UInt(0))
106
107 val prescaler = Reg(init = UInt(0, uartDivisorBits - uartOversample))
108 val start = Wire(init = Bool(false))
109 val busy = Wire(init = Bool(false))
110 val pulse = (prescaler === UInt(0)) && busy
111
112 when (busy) {
113 prescaler := prescaler - UInt(1)
114 }
115 when (start || pulse) {
116 prescaler := io.div >> uartOversample
117 }
118
119 val sample = Reg(Bits(width = uartNSamples))
120 val voter = Majority(sample.toBools.toSet)
121 when (pulse) {
122 sample := Cat(sample, io.in)
123 }
124
125 private val delay0 = (uartOversampleFactor + uartNSamples) >> 1
126 private val delay1 = uartOversampleFactor
127
128 val timer = Reg(UInt(width = uartOversample + 1))
129 val counter = Reg(UInt(width = log2Floor(uartDataBits) + 1))
130 val shifter = Reg(Bits(width = uartDataBits))
131 val expire = (timer === UInt(0)) && pulse
132
133 val sched = Wire(init = Bool(false))
134 when (pulse) {
135 timer := timer - UInt(1)
136 }
137 when (sched) {
138 timer := UInt(delay1-1)
139 }
140
141 val valid = Reg(init = Bool(false))
142 valid := Bool(false)
143 io.out.valid := valid
144 io.out.bits := shifter
145
146 val (s_idle :: s_start :: s_data :: Nil) = Enum(UInt(), 3)
147 val state = Reg(init = s_idle)
148
149 switch (state) {
150 is (s_idle) {
151 when (!(!io.in) && !debounce_min) {
152 debounce := debounce - UInt(1)
153 }
154 when (!io.in) {
155 debounce := debounce + UInt(1)
156 when (debounce_max) {
157 state := s_start
158 start := Bool(true)
159 timer := UInt(delay0-1)
160 }
161 }
162 }
163
164 is (s_start) {
165 busy := Bool(true)
166 when (expire) {
167 sched := Bool(true)
168 when (voter) {
169 state := s_idle
170 } .otherwise {
171 state := s_data
172 counter := UInt(uartDataBits)
173 }
174 }
175 }
176
177 is (s_data) {
178 busy := Bool(true)
179 when (expire) {
180 counter := counter - UInt(1)
181 when (counter === UInt(0)) {
182 state := s_idle
183 valid := Bool(true)
184 } .otherwise {
185 shifter := Cat(voter, shifter >> 1)
186 sched := Bool(true)
187 }
188 }
189 }
190 }
191
192 when (!io.en) {
193 debounce := UInt(0)
194 }
195 }
196
197 class UARTInterrupts extends Bundle {
198 val rxwm = Bool()
199 val txwm = Bool()
200 }
201
202 trait HasUARTTopModuleContents extends MultiIOModule with HasUARTParameters with HasRegMap {
203 val io: HasUARTTopBundleContents
204 implicit val p: Parameters
205 def params: UARTParams
206 def c = params
207
208 val txm = Module(new UARTTx(params))
209 val txq = Module(new Queue(txm.io.in.bits, uartNTxEntries))
210
211 val rxm = Module(new UARTRx(params))
212 val rxq = Module(new Queue(rxm.io.out.bits, uartNRxEntries))
213
214 val div = Reg(init = UInt(uartDivisorInit, uartDivisorBits))
215
216 private val stopCountBits = log2Up(uartStopBits)
217 private val txCountBits = log2Floor(uartNTxEntries) + 1
218 private val rxCountBits = log2Floor(uartNRxEntries) + 1
219
220 val txen = Reg(init = Bool(false))
221 val rxen = Reg(init = Bool(false))
222 val txwm = Reg(init = UInt(0, txCountBits))
223 val rxwm = Reg(init = UInt(0, rxCountBits))
224 val nstop = Reg(init = UInt(0, stopCountBits))
225
226 txm.io.en := txen
227 txm.io.in <> txq.io.deq
228 txm.io.div := div
229 txm.io.nstop := nstop
230 io.port.txd := txm.io.out
231
232 rxm.io.en := rxen
233 rxm.io.in := io.port.rxd
234 rxq.io.enq <> rxm.io.out
235 rxm.io.div := div
236
237 val ie = Reg(init = new UARTInterrupts().fromBits(Bits(0)))
238 val ip = Wire(new UARTInterrupts)
239
240 ip.txwm := (txq.io.count < txwm)
241 ip.rxwm := (rxq.io.count > rxwm)
242 interrupts(0) := (ip.txwm && ie.txwm) || (ip.rxwm && ie.rxwm)
243
244 regmap(
245 UARTCtrlRegs.txfifo -> NonBlockingEnqueue(txq.io.enq),
246 UARTCtrlRegs.rxfifo -> NonBlockingDequeue(rxq.io.deq),
247
248 UARTCtrlRegs.txctrl -> Seq(
249 RegField(1, txen),
250 RegField(stopCountBits, nstop)),
251 UARTCtrlRegs.rxctrl -> Seq(RegField(1, rxen)),
252 UARTCtrlRegs.txmark -> Seq(RegField(txCountBits, txwm)),
253 UARTCtrlRegs.rxmark -> Seq(RegField(rxCountBits, rxwm)),
254
255 UARTCtrlRegs.ie -> Seq(
256 RegField(1, ie.txwm),
257 RegField(1, ie.rxwm)),
258
259 UARTCtrlRegs.ip -> Seq(
260 RegField.r(1, ip.txwm),
261 RegField.r(1, ip.rxwm)),
262
263 UARTCtrlRegs.div -> Seq(
264 RegField(uartDivisorBits, div))
265 )
266 }
267
268 // Magic TL2 Incantation to create a TL2 UART
269 class TLUART(w: Int, c: UARTParams)(implicit p: Parameters)
270 extends TLRegisterRouter(c.address, "serial", Seq("sifive,uart0"), interrupts = 1, beatBytes = w)(
271 new TLRegBundle(c, _) with HasUARTTopBundleContents)(
272 new TLRegModule(c, _, _) with HasUARTTopModuleContents)