Files
2025-yatcpu/lab3/src/main/scala/peripheral/UART.scala
TOKISAKIX\21168 910ee11168 init repo
2023-12-11 21:50:22 +08:00

205 lines
5.0 KiB
Scala

// Copyright 2021 Howard Lau
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package peripheral
import chisel3._
import chisel3.util._
class UartIO extends DecoupledIO(UInt(8.W)) {
}
/**
* Transmit part of the UART.
* A minimal version without any additional buffering.
* Use a ready/valid handshaking.
*/
class Tx(frequency: Int, baudRate: Int) extends Module {
val io = IO(new Bundle {
val txd = Output(UInt(1.W))
val channel = Flipped(new UartIO())
})
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U
val shiftReg = RegInit(0x7ff.U)
val cntReg = RegInit(0.U(20.W))
val bitsReg = RegInit(0.U(4.W))
io.channel.ready := (cntReg === 0.U) && (bitsReg === 0.U)
io.txd := shiftReg(0)
when(cntReg === 0.U) {
cntReg := BIT_CNT
when(bitsReg =/= 0.U) {
val shift = shiftReg >> 1
shiftReg := Cat(1.U, shift(9, 0))
bitsReg := bitsReg - 1.U
}.otherwise {
when(io.channel.valid) {
shiftReg := Cat(Cat(3.U, io.channel.bits), 0.U) // two stop bits, data, one start bit
bitsReg := 11.U
}.otherwise {
shiftReg := 0x7ff.U
}
}
}.otherwise {
cntReg := cntReg - 1.U
}
}
/**
* Receive part of the UART.
* A minimal version without any additional buffering.
* Use a ready/valid handshaking.
*
* The following code is inspired by Tommy's receive code at:
* https://github.com/tommythorn/yarvi
*/
class Rx(frequency: Int, baudRate: Int) extends Module {
val io = IO(new Bundle {
val rxd = Input(UInt(1.W))
val channel = new UartIO()
})
val BIT_CNT = ((frequency + baudRate / 2) / baudRate - 1).U
val START_CNT = ((3 * frequency / 2 + baudRate / 2) / baudRate - 1).U
// Sync in the asynchronous RX data, reset to 1 to not start reading after a reset
val rxReg = RegNext(RegNext(io.rxd, 1.U), 1.U)
val shiftReg = RegInit(0.U(8.W))
val cntReg = RegInit(0.U(20.W))
val bitsReg = RegInit(0.U(4.W))
val valReg = RegInit(false.B)
when(cntReg =/= 0.U) {
cntReg := cntReg - 1.U
}.elsewhen(bitsReg =/= 0.U) {
cntReg := BIT_CNT
shiftReg := Cat(rxReg, shiftReg >> 1)
bitsReg := bitsReg - 1.U
// the last shifted in
when(bitsReg === 1.U) {
valReg := true.B
}
}.elsewhen(rxReg === 0.U) { // wait 1.5 bits after falling edge of start
cntReg := START_CNT
bitsReg := 8.U
}
when(valReg && io.channel.ready) {
valReg := false.B
}
io.channel.bits := shiftReg
io.channel.valid := valReg
}
/**
* A single byte buffer with a ready/valid interface
*/
class Buffer extends Module {
val io = IO(new Bundle {
val in = Flipped(new UartIO())
val out = new UartIO()
})
val empty :: full :: Nil = Enum(2)
val stateReg = RegInit(empty)
val dataReg = RegInit(0.U(8.W))
io.in.ready := stateReg === empty
io.out.valid := stateReg === full
when(stateReg === empty) {
when(io.in.valid) {
dataReg := io.in.bits
stateReg := full
}
}.otherwise { // full
when(io.out.ready) {
stateReg := empty
}
}
io.out.bits := dataReg
}
/**
* A transmitter with a single buffer.
*/
class BufferedTx(frequency: Int, baudRate: Int) extends Module {
val io = IO(new Bundle {
val txd = Output(UInt(1.W))
val channel = Flipped(new UartIO())
})
val tx = Module(new Tx(frequency, baudRate))
val buf = Module(new Buffer)
buf.io.in <> io.channel
tx.io.channel <> buf.io.out
io.txd <> tx.io.txd
}
class Uart(frequency: Int, baudRate: Int) extends Module {
val io = IO(new Bundle {
val bundle = new RAMBundle
val rxd = Input(UInt(1.W))
val txd = Output(UInt(1.W))
val signal_interrupt = Output(Bool())
})
val interrupt = RegInit(false.B)
val rxData = RegInit(0.U)
val tx = Module(new BufferedTx(frequency, baudRate))
val rx = Module(new Rx(frequency, baudRate))
io.bundle.read_data := 0.U
when(io.bundle.address === 0x4.U) {
io.bundle.read_data := baudRate.U
}.elsewhen(io.bundle.address === 0xC.U) {
io.bundle.read_data := rxData
interrupt := false.B
}
tx.io.channel.valid := false.B
tx.io.channel.bits := 0.U
when(io.bundle.write_enable) {
when(io.bundle.address === 0x8.U) {
interrupt := io.bundle.write_data =/= 0.U
}.elsewhen(io.bundle.address === 0x10.U) {
tx.io.channel.valid := true.B
tx.io.channel.bits := io.bundle.write_data
}
}
io.txd := tx.io.txd
rx.io.rxd := io.rxd
io.signal_interrupt := interrupt
rx.io.channel.ready := false.B
when(rx.io.channel.valid) {
rx.io.channel.ready := true.B
rxData := rx.io.channel.bits
interrupt := true.B
}
}