mirror of
https://github.com/handsomezhuzhu/2025-yatcpu.git
synced 2026-02-20 20:10:14 +00:00
lab2打包
This commit is contained in:
84
lab2/朱梓涵24325356/scala/peripheral/CharacterDisplay.scala
Normal file
84
lab2/朱梓涵24325356/scala/peripheral/CharacterDisplay.scala
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2022 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.util.{MuxLookup, log2Up}
|
||||
import chisel3.{Bool, Bundle, Module, Mux, Output, UInt, Wire, _}
|
||||
import peripheral.ScreenInfo.{DisplayHorizontal, DisplayVertical}
|
||||
import riscv.Parameters
|
||||
|
||||
object GlyphInfo {
|
||||
val glyphWidth = 8
|
||||
val glyphHeight = 16
|
||||
// ASCII printable characters start from here
|
||||
val spaceIndex = 1
|
||||
}
|
||||
|
||||
object ScreenInfo {
|
||||
val DisplayHorizontal = 640
|
||||
val DisplayVertical = 480
|
||||
}
|
||||
|
||||
object CharacterBufferInfo {
|
||||
val CharCols = DisplayHorizontal / GlyphInfo.glyphWidth
|
||||
val CharRows = DisplayVertical / GlyphInfo.glyphHeight
|
||||
val Chars = CharCols * CharRows
|
||||
}
|
||||
|
||||
class CharacterDisplay extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val bundle = new RAMBundle()
|
||||
|
||||
val x = Input(UInt(16.W))
|
||||
val y = Input(UInt(16.W))
|
||||
val video_on = Input(Bool())
|
||||
|
||||
val rgb = Output(UInt(24.W))
|
||||
})
|
||||
|
||||
val mem = Module(new BlockRAM(CharacterBufferInfo.Chars / Parameters.WordSize))
|
||||
mem.io.write_enable := io.bundle.write_enable
|
||||
mem.io.write_data := io.bundle.write_data
|
||||
mem.io.write_address := io.bundle.address
|
||||
mem.io.write_strobe := io.bundle.write_strobe
|
||||
mem.io.read_address := io.bundle.address
|
||||
io.bundle.read_data := mem.io.read_data
|
||||
|
||||
|
||||
val font_rom = Module(new FontROM)
|
||||
val row = (io.y >> log2Up(GlyphInfo.glyphHeight)).asUInt
|
||||
val col = (io.x >> log2Up(GlyphInfo.glyphWidth)).asUInt
|
||||
val char_index = (row * CharacterBufferInfo.CharCols.U) + col
|
||||
val offset = char_index(1, 0)
|
||||
val ch = Wire(UInt(8.W))
|
||||
|
||||
mem.io.debug_read_address := char_index
|
||||
ch := MuxLookup(
|
||||
offset,
|
||||
0.U,
|
||||
IndexedSeq(
|
||||
0.U -> mem.io.debug_read_data(7, 0).asUInt,
|
||||
1.U -> mem.io.debug_read_data(15, 8).asUInt,
|
||||
2.U -> mem.io.debug_read_data(23, 16).asUInt,
|
||||
3.U -> mem.io.debug_read_data(31, 24).asUInt
|
||||
)
|
||||
)
|
||||
font_rom.io.glyph_index := Mux(ch >= 32.U, ch - 31.U, 0.U)
|
||||
font_rom.io.glyph_y := io.y(log2Up(GlyphInfo.glyphHeight) - 1, 0)
|
||||
|
||||
// White if pixel_on and glyph pixel on
|
||||
val glyph_x = io.x(log2Up(GlyphInfo.glyphWidth) - 1, 0)
|
||||
io.rgb := Mux(io.video_on && font_rom.io.glyph_pixel_byte(glyph_x), 0xFFFFFF.U, 0.U)
|
||||
}
|
||||
29
lab2/朱梓涵24325356/scala/peripheral/Dummy.scala
Normal file
29
lab2/朱梓涵24325356/scala/peripheral/Dummy.scala
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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 riscv.Parameters
|
||||
|
||||
// A dummy master that never initiates reads or writes
|
||||
class Dummy extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val bundle = Flipped(new RAMBundle)
|
||||
})
|
||||
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
io.bundle.write_data := 0.U
|
||||
io.bundle.write_enable := false.B
|
||||
io.bundle.address := 0.U
|
||||
}
|
||||
64
lab2/朱梓涵24325356/scala/peripheral/FontROM.scala
Normal file
64
lab2/朱梓涵24325356/scala/peripheral/FontROM.scala
Normal file
@@ -0,0 +1,64 @@
|
||||
package peripheral
|
||||
|
||||
import chisel3.experimental.{ChiselAnnotation, annotate}
|
||||
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||
import chisel3.{Bundle, Input, Module, Output, SyncReadMem, UInt, _}
|
||||
import firrtl.annotations.MemorySynthInit
|
||||
|
||||
import java.io.FileWriter
|
||||
import java.nio.file.Paths
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
class FontROM(fontBitmapFilename: String = "vga_font_8x16.bmp") extends Module {
|
||||
val glyphWidth = GlyphInfo.glyphWidth
|
||||
val glyphHeight = GlyphInfo.glyphHeight
|
||||
|
||||
val io = IO(new Bundle {
|
||||
val glyph_index = Input(UInt(7.W))
|
||||
val glyph_y = Input(UInt(4.W))
|
||||
|
||||
val glyph_pixel_byte = Output(UInt(8.W))
|
||||
})
|
||||
|
||||
annotate(new ChiselAnnotation {
|
||||
override def toFirrtl =
|
||||
MemorySynthInit
|
||||
})
|
||||
|
||||
val (hexTxtPath, glyphCount) = readFontBitmap()
|
||||
val mem = SyncReadMem(glyphCount, UInt(8.W))
|
||||
loadMemoryFromFileInline(mem, hexTxtPath.toString.replaceAll("\\\\", "/"))
|
||||
io.glyph_pixel_byte := mem.read(io.glyph_index * GlyphInfo.glyphHeight.U + io.glyph_y, true.B)
|
||||
|
||||
def readFontBitmap() = {
|
||||
val inputStream = getClass.getClassLoader.getResourceAsStream(fontBitmapFilename)
|
||||
val image = ImageIO.read(inputStream)
|
||||
|
||||
val glyphColumns = image.getWidth() / glyphWidth
|
||||
val glyphRows = image.getHeight / glyphHeight
|
||||
val glyphCount = glyphColumns * glyphRows
|
||||
val glyphs = new Array[UInt](glyphCount * GlyphInfo.glyphHeight)
|
||||
|
||||
for (row <- 0 until glyphRows) {
|
||||
for (col <- 0 until glyphColumns) {
|
||||
for (i <- 0 until glyphHeight) {
|
||||
var lineInt = 0
|
||||
for (j <- 0 until glyphWidth) {
|
||||
if (image.getRGB(col * glyphWidth + j, row * glyphHeight + i) != 0xFFFFFFFF) {
|
||||
lineInt |= (1 << j)
|
||||
}
|
||||
}
|
||||
glyphs((row * glyphColumns + col) * GlyphInfo.glyphHeight + i) = lineInt.U(8.W)
|
||||
}
|
||||
}
|
||||
}
|
||||
val currentDir = System.getProperty("user.dir")
|
||||
val hexTxtPath = Paths.get(currentDir, "verilog", f"${fontBitmapFilename}.txt")
|
||||
val writer = new FileWriter(hexTxtPath.toString)
|
||||
for (i <- glyphs.indices) {
|
||||
writer.write(f"@$i%x\n${glyphs(i).litValue}%02x\n")
|
||||
}
|
||||
writer.close()
|
||||
(hexTxtPath, glyphs.length)
|
||||
}
|
||||
}
|
||||
394
lab2/朱梓涵24325356/scala/peripheral/HDMIDisplay.scala
Normal file
394
lab2/朱梓涵24325356/scala/peripheral/HDMIDisplay.scala
Normal file
@@ -0,0 +1,394 @@
|
||||
// Copyright 2022 hrpccs
|
||||
//
|
||||
// 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 HDMISync extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val hsync = Output(Bool())
|
||||
val vsync = Output(Bool())
|
||||
val video_on = Output(Bool())
|
||||
val p_tick = Output(Bool())
|
||||
val f_tick = Output(Bool())
|
||||
val x = Output(UInt(10.W))
|
||||
val y = Output(UInt(10.W))
|
||||
val x_next = Output(UInt(10.W))
|
||||
val y_next = Output(UInt(10.W))
|
||||
})
|
||||
|
||||
val DisplayHorizontal = ScreenInfo.DisplayHorizontal
|
||||
val DisplayVertical = ScreenInfo.DisplayVertical
|
||||
|
||||
val BorderLeft = 48
|
||||
val BorderRight = 16
|
||||
val BorderTop = 10
|
||||
val BorderBottom = 33
|
||||
|
||||
val RetraceHorizontal = 96
|
||||
val RetraceVertical = 2
|
||||
|
||||
val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1
|
||||
val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1
|
||||
|
||||
val RetraceHorizontalStart = DisplayHorizontal + BorderRight
|
||||
val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1
|
||||
|
||||
val RetraceVerticalStart = DisplayVertical + BorderBottom
|
||||
val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1
|
||||
|
||||
val pixel = RegInit(UInt(3.W), 0.U)
|
||||
val pixel_next = Wire(UInt(3.W))
|
||||
val pixel_tick = Wire(Bool())
|
||||
|
||||
val v_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
val h_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
|
||||
val v_count_next = Wire(UInt(10.W))
|
||||
val h_count_next = Wire(UInt(10.W))
|
||||
|
||||
val vsync_reg = RegInit(Bool(), false.B)
|
||||
val hsync_reg = RegInit(Bool(), false.B)
|
||||
|
||||
val vsync_next = Wire(Bool())
|
||||
val hsync_next = Wire(Bool())
|
||||
|
||||
pixel_next := Mux(pixel === 4.U, 0.U, pixel + 1.U)
|
||||
pixel_tick := pixel === 0.U
|
||||
|
||||
h_count_next := Mux(
|
||||
pixel_tick,
|
||||
Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U),
|
||||
h_count_reg
|
||||
)
|
||||
|
||||
v_count_next := Mux(
|
||||
pixel_tick && h_count_reg === MaxHorizontal.U,
|
||||
Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U),
|
||||
v_count_reg
|
||||
)
|
||||
|
||||
hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U
|
||||
vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U
|
||||
|
||||
pixel := pixel_next
|
||||
hsync_reg := hsync_next
|
||||
vsync_reg := vsync_next
|
||||
v_count_reg := v_count_next
|
||||
h_count_reg := h_count_next
|
||||
|
||||
io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U
|
||||
io.hsync := hsync_reg
|
||||
io.vsync := vsync_reg
|
||||
io.x := h_count_reg
|
||||
io.y := v_count_reg
|
||||
io.x_next := h_count_next
|
||||
io.y_next := v_count_next
|
||||
io.p_tick := pixel_tick
|
||||
io.f_tick := io.x === 0.U && io.y === 0.U
|
||||
}
|
||||
|
||||
class TMDS_encoder extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val video_data = Input(UInt(8.W)) //r,g,b,8bit
|
||||
val control_data = Input(UInt(2.W))
|
||||
val video_on = Input(Bool())
|
||||
val TMDS = Output(UInt(10.W))
|
||||
})
|
||||
val Nb1s = PopCount(io.video_data)
|
||||
val xored = xorfct(io.video_data)
|
||||
val xnored = xnorfct(io.video_data)
|
||||
val XNOR = (Nb1s > 4.U(4.W)) || (Nb1s === 4.U(4.W) && io.video_data(0) === 0.U)
|
||||
val q_m = RegInit(0.U(9.W))
|
||||
val diffSize = 4
|
||||
val diff = RegInit(0.S(diffSize.W))
|
||||
q_m := Mux(
|
||||
XNOR,
|
||||
xnored,
|
||||
xored
|
||||
)
|
||||
val disparitySize = 4
|
||||
val disparityReg = RegInit(0.S(disparitySize.W))
|
||||
diff := PopCount(q_m).asSInt - 4.S
|
||||
val doutReg = RegInit("b1010101011".U(10.W))
|
||||
|
||||
def xorfct(value: UInt): UInt = {
|
||||
val vin = VecInit(value.asBools)
|
||||
val res = VecInit(511.U.asBools)
|
||||
res(0) := vin(0)
|
||||
for (i <- 1 to 7) {
|
||||
res(i) := res(i - 1) ^ vin(i)
|
||||
}
|
||||
res(8) := 1.U
|
||||
res.asUInt
|
||||
}
|
||||
|
||||
def xnorfct(value: UInt): UInt = {
|
||||
val vin = VecInit(value.asBools)
|
||||
val res = VecInit(511.U.asBools)
|
||||
res(0) := vin(0)
|
||||
for (i <- 1 to 7) {
|
||||
res(i) := !(res(i - 1) ^ vin(i))
|
||||
}
|
||||
res(8) := 0.U
|
||||
res.asUInt
|
||||
}
|
||||
|
||||
when(io.video_on === false.B) {
|
||||
disparityReg := 0.S
|
||||
doutReg := "b1010101011".U(10.W)
|
||||
switch(io.control_data) {
|
||||
is("b00".U(2.W)) {
|
||||
doutReg := "b1101010100".U(10.W)
|
||||
}
|
||||
is("b01".U(2.W)) {
|
||||
doutReg := "b0010101011".U(10.W)
|
||||
}
|
||||
is("b10".U(2.W)) {
|
||||
doutReg := "b0101010100".U(10.W)
|
||||
}
|
||||
}
|
||||
}.otherwise {
|
||||
when(disparityReg === 0.S || diff === 0.S) {
|
||||
when(q_m(8) === false.B) {
|
||||
doutReg := "b10".U(2.W) ## ~q_m(7, 0)
|
||||
disparityReg := disparityReg - diff
|
||||
}.otherwise {
|
||||
doutReg := "b01".U(2.W) ## q_m(7, 0)
|
||||
disparityReg := disparityReg + diff
|
||||
}
|
||||
}.elsewhen((!diff(diffSize - 1) && !disparityReg(disparitySize - 1))
|
||||
|| (diff(diffSize - 1) && disparityReg(disparitySize - 1))) {
|
||||
doutReg := 1.U(1.W) ## q_m(8) ## ~q_m(7, 0)
|
||||
when(q_m(8)) {
|
||||
disparityReg := disparityReg + 1.S - diff
|
||||
}.otherwise {
|
||||
disparityReg := disparityReg - diff
|
||||
}
|
||||
}.otherwise {
|
||||
doutReg := 0.U(1.W) ## q_m
|
||||
when(q_m(8)) {
|
||||
disparityReg := disparityReg + diff
|
||||
}.otherwise {
|
||||
disparityReg := disparityReg - 1.S + diff
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
io.TMDS := doutReg
|
||||
}
|
||||
|
||||
class HDMIDisplay extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val rgb = Input(UInt(24.W))
|
||||
val x = Output(UInt(16.W))
|
||||
val y = Output(UInt(16.W))
|
||||
val x_next = Output(UInt(16.W))
|
||||
val y_next = Output(UInt(16.W))
|
||||
val video_on = Output(Bool())
|
||||
|
||||
val TMDSclk_p = Output(Bool())
|
||||
val TMDSdata_p = Output(UInt(3.W))
|
||||
val TMDSclk_n = Output(Bool())
|
||||
val TMDSdata_n = Output(UInt(3.W))
|
||||
})
|
||||
val rgb = io.rgb
|
||||
val pixel_clk = Wire(Bool())
|
||||
val hsync = Wire(Bool())
|
||||
val vsync = Wire(Bool())
|
||||
val sync = Module(new HDMISync)
|
||||
|
||||
io.x := sync.io.x
|
||||
io.y := sync.io.y
|
||||
io.x_next := sync.io.x_next
|
||||
io.y_next := sync.io.y_next
|
||||
io.video_on := sync.io.video_on
|
||||
|
||||
hsync := sync.io.hsync
|
||||
vsync := sync.io.vsync
|
||||
pixel_clk := sync.io.p_tick
|
||||
|
||||
// TMDS_PLLVR is a vivado IP core, check it in /verilog/pynq/TMDS_PLLVR.v
|
||||
val serial_clk = Wire(Clock())
|
||||
val pll_lock = Wire(Bool())
|
||||
val tmdspll = Module(new TMDS_PLLVR)
|
||||
val rst = Wire(Reset())
|
||||
tmdspll.io.clkin := pixel_clk.asClock
|
||||
serial_clk := tmdspll.io.clkout
|
||||
pll_lock := tmdspll.io.lock
|
||||
tmdspll.io.reset := reset
|
||||
rst := ~pll_lock
|
||||
|
||||
val tmds = Wire(UInt(3.W))
|
||||
val tmds_clk = Wire(Bool())
|
||||
withClockAndReset(pixel_clk.asClock, rst) {
|
||||
val tmds_channel1 = Wire(UInt(10.W))
|
||||
val tmds_channel2 = Wire(UInt(10.W))
|
||||
val tmds_channel0 = Wire(UInt(10.W))
|
||||
|
||||
val tmds_green = Module(new TMDS_encoder)
|
||||
val tmds_red = Module(new TMDS_encoder)
|
||||
val tmds_blue = Module(new TMDS_encoder)
|
||||
|
||||
tmds_red.io.video_on := sync.io.video_on
|
||||
tmds_blue.io.video_on := sync.io.video_on
|
||||
tmds_green.io.video_on := sync.io.video_on
|
||||
|
||||
tmds_blue.io.control_data := sync.io.vsync ## sync.io.hsync
|
||||
tmds_green.io.control_data := 0.U
|
||||
tmds_red.io.control_data := 0.U
|
||||
|
||||
tmds_red.io.video_data := rgb(23, 16)
|
||||
tmds_blue.io.video_data := rgb(7, 0)
|
||||
tmds_green.io.video_data := rgb(15, 8)
|
||||
|
||||
tmds_channel0 := tmds_blue.io.TMDS
|
||||
tmds_channel1 := tmds_green.io.TMDS
|
||||
tmds_channel2 := tmds_red.io.TMDS
|
||||
|
||||
val serdesBlue = Module(new Oser10Module())
|
||||
serdesBlue.io.data := tmds_channel0
|
||||
serdesBlue.io.fclk := serial_clk
|
||||
|
||||
val serdesGreen = Module(new Oser10Module())
|
||||
serdesGreen.io.data := tmds_channel1
|
||||
serdesGreen.io.fclk := serial_clk
|
||||
|
||||
val serdesRed = Module(new Oser10Module())
|
||||
serdesRed.io.data := tmds_channel2
|
||||
serdesRed.io.fclk := serial_clk
|
||||
|
||||
tmds := serdesRed.io.q ## serdesGreen.io.q ## serdesBlue.io.q
|
||||
|
||||
//serdesCLk : 25Mhz ,Why not directly use p_tick?
|
||||
//cause Duty Ratio of p_tick is 10% , while which of serdesCLk is 50%
|
||||
val serdesClk = Module(new Oser10Module())
|
||||
serdesClk.io.data := "b1111100000".U(10.W)
|
||||
serdesClk.io.fclk := serial_clk
|
||||
|
||||
tmds_clk := serdesClk.io.q
|
||||
|
||||
val buffDiffBlue = Module(new OBUFDS)
|
||||
buffDiffBlue.io.I := tmds(0)
|
||||
val buffDiffGreen = Module(new OBUFDS)
|
||||
buffDiffGreen.io.I := tmds(1)
|
||||
val buffDiffRed = Module(new OBUFDS)
|
||||
buffDiffRed.io.I := tmds(2)
|
||||
val buffDiffClk = Module(new OBUFDS)
|
||||
buffDiffClk.io.I := tmds_clk
|
||||
|
||||
io.TMDSclk_p := buffDiffClk.io.O
|
||||
io.TMDSclk_n := buffDiffClk.io.OB
|
||||
io.TMDSdata_p := buffDiffRed.io.O ## buffDiffGreen.io.O ## buffDiffBlue.io.O
|
||||
io.TMDSdata_n := buffDiffRed.io.OB ## buffDiffGreen.io.OB ## buffDiffBlue.io.OB
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
//PLL frequency multiplier using BlackBox
|
||||
class TMDS_PLLVR extends BlackBox {
|
||||
val io = IO(new Bundle {
|
||||
val clkin = Input(Clock())
|
||||
val reset = Input(Reset())
|
||||
val clkout = Output(Clock())
|
||||
val clkoutd = Output(Clock())
|
||||
val lock = Output(Bool())
|
||||
})
|
||||
}
|
||||
|
||||
/* OSER10 : serializer 10:1*/
|
||||
class OSER10 extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val Q = Output(Bool()) // OSER10 data output signal
|
||||
val D0 = Input(Bool())
|
||||
val D1 = Input(Bool())
|
||||
val D2 = Input(Bool())
|
||||
val D3 = Input(Bool())
|
||||
val D4 = Input(Bool())
|
||||
val D5 = Input(Bool())
|
||||
val D6 = Input(Bool())
|
||||
val D7 = Input(Bool())
|
||||
val D8 = Input(Bool())
|
||||
val D9 = Input(Bool()) // OSER10 data input signal
|
||||
val PCLK = Input(Clock()) // Primary clock input signal
|
||||
val FCLK = Input(Clock()) // High speed clock input signal
|
||||
val RESET = Input(Reset()) // Asynchronous reset input signal,
|
||||
//active-high.
|
||||
})
|
||||
withClockAndReset(io.FCLK, io.RESET) {
|
||||
val count = RegInit(0.U(4.W))
|
||||
val countnext = Wire(UInt(4.W))
|
||||
io.Q := MuxLookup(
|
||||
count,
|
||||
0.U,
|
||||
IndexedSeq(
|
||||
0.U -> io.D0.asBool,
|
||||
1.U -> io.D1.asBool,
|
||||
2.U -> io.D2.asBool,
|
||||
3.U -> io.D3.asBool,
|
||||
4.U -> io.D4.asBool,
|
||||
5.U -> io.D5.asBool,
|
||||
6.U -> io.D6.asBool,
|
||||
7.U -> io.D7.asBool,
|
||||
8.U -> io.D8.asBool,
|
||||
9.U -> io.D9.asBool
|
||||
)
|
||||
)
|
||||
countnext := Mux(
|
||||
count === 9.U, 0.U, count + 1.U
|
||||
)
|
||||
count := countnext
|
||||
}
|
||||
}
|
||||
|
||||
class Oser10Module extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val q = Output(Bool())
|
||||
val data = Input(UInt(10.W))
|
||||
val fclk = Input(Clock()) // Fast clock
|
||||
})
|
||||
|
||||
val osr10 = Module(new OSER10())
|
||||
io.q := osr10.io.Q
|
||||
osr10.io.D0 := io.data(0)
|
||||
osr10.io.D1 := io.data(1)
|
||||
osr10.io.D2 := io.data(2)
|
||||
osr10.io.D3 := io.data(3)
|
||||
osr10.io.D4 := io.data(4)
|
||||
osr10.io.D5 := io.data(5)
|
||||
osr10.io.D6 := io.data(6)
|
||||
osr10.io.D7 := io.data(7)
|
||||
osr10.io.D8 := io.data(8)
|
||||
osr10.io.D9 := io.data(9)
|
||||
osr10.io.PCLK := clock
|
||||
osr10.io.FCLK := io.fclk
|
||||
osr10.io.RESET := reset
|
||||
}
|
||||
|
||||
/* lvds output */
|
||||
class OBUFDS extends BlackBox {
|
||||
val io = IO(new Bundle {
|
||||
val O = Output(Bool())
|
||||
val OB = Output(Bool())
|
||||
val I = Input(Bool())
|
||||
})
|
||||
}
|
||||
//-----------------------------------------
|
||||
|
||||
|
||||
//-----------------------------------------
|
||||
|
||||
|
||||
68
lab2/朱梓涵24325356/scala/peripheral/InstructionROM.scala
Normal file
68
lab2/朱梓涵24325356/scala/peripheral/InstructionROM.scala
Normal file
@@ -0,0 +1,68 @@
|
||||
// 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.experimental.{ChiselAnnotation, annotate}
|
||||
import chisel3.util.experimental.loadMemoryFromFileInline
|
||||
import firrtl.annotations.MemorySynthInit
|
||||
import riscv.Parameters
|
||||
|
||||
import java.io.FileWriter
|
||||
import java.nio.file.{Files, Paths}
|
||||
import java.nio.{ByteBuffer, ByteOrder}
|
||||
|
||||
class InstructionROM(instructionFilename: String) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val address = Input(UInt(Parameters.AddrWidth))
|
||||
val data = Output(UInt(Parameters.InstructionWidth))
|
||||
})
|
||||
|
||||
val (instructionsInitFile, capacity) = readAsmBinary(instructionFilename)
|
||||
val mem = Mem(capacity, UInt(Parameters.InstructionWidth))
|
||||
annotate(new ChiselAnnotation {
|
||||
override def toFirrtl =
|
||||
MemorySynthInit
|
||||
})
|
||||
loadMemoryFromFileInline(mem, instructionsInitFile.toString.replaceAll("\\\\", "/"))
|
||||
io.data := mem.read(io.address)
|
||||
|
||||
def readAsmBinary(filename: String) = {
|
||||
val inputStream = if (Files.exists(Paths.get(filename))) {
|
||||
Files.newInputStream(Paths.get(filename))
|
||||
} else {
|
||||
getClass.getClassLoader.getResourceAsStream(filename)
|
||||
}
|
||||
var instructions = new Array[BigInt](0)
|
||||
val arr = new Array[Byte](4)
|
||||
while (inputStream.read(arr) == 4) {
|
||||
val instBuf = ByteBuffer.wrap(arr)
|
||||
instBuf.order(ByteOrder.LITTLE_ENDIAN)
|
||||
val inst = BigInt(instBuf.getInt() & 0xFFFFFFFFL)
|
||||
instructions = instructions :+ inst
|
||||
}
|
||||
instructions = instructions :+ BigInt(0x00000013L)
|
||||
instructions = instructions :+ BigInt(0x00000013L)
|
||||
instructions = instructions :+ BigInt(0x00000013L)
|
||||
val currentDir = System.getProperty("user.dir")
|
||||
val exeTxtPath = Paths.get(currentDir, "verilog", f"${instructionFilename}.txt")
|
||||
val writer = new FileWriter(exeTxtPath.toString)
|
||||
for (i <- instructions.indices) {
|
||||
writer.write(f"@$i%x\n${instructions(i)}%08x\n")
|
||||
}
|
||||
writer.close()
|
||||
(exeTxtPath, instructions.length)
|
||||
}
|
||||
}
|
||||
77
lab2/朱梓涵24325356/scala/peripheral/Memory.scala
Normal file
77
lab2/朱梓涵24325356/scala/peripheral/Memory.scala
Normal file
@@ -0,0 +1,77 @@
|
||||
// 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._
|
||||
import riscv.Parameters
|
||||
|
||||
class RAMBundle extends Bundle {
|
||||
val address = Input(UInt(Parameters.AddrWidth))
|
||||
val write_data = Input(UInt(Parameters.DataWidth))
|
||||
val write_enable = Input(Bool())
|
||||
val write_strobe = Input(Vec(Parameters.WordSize, Bool()))
|
||||
val read_data = Output(UInt(Parameters.DataWidth))
|
||||
}
|
||||
// The purpose of this module is to help the synthesis tool recognize
|
||||
// our memory as a Block RAM template
|
||||
class BlockRAM(capacity: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val read_address = Input(UInt(Parameters.AddrWidth))
|
||||
val write_address = Input(UInt(Parameters.AddrWidth))
|
||||
val write_data = Input(UInt(Parameters.DataWidth))
|
||||
val write_enable = Input(Bool())
|
||||
val write_strobe = Input(Vec(Parameters.WordSize, Bool()))
|
||||
|
||||
val debug_read_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val read_data = Output(UInt(Parameters.DataWidth))
|
||||
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||
when(io.write_enable) {
|
||||
val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||
for (i <- 0 until Parameters.WordSize) {
|
||||
write_data_vec(i) := io.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits)
|
||||
}
|
||||
mem.write((io.write_address >> 2.U).asUInt, write_data_vec, io.write_strobe)
|
||||
}
|
||||
io.read_data := mem.read((io.read_address >> 2.U).asUInt, true.B).asUInt
|
||||
io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt
|
||||
}
|
||||
|
||||
class Memory(capacity: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val bundle = new RAMBundle
|
||||
|
||||
val instruction = Output(UInt(Parameters.DataWidth))
|
||||
val instruction_address = Input(UInt(Parameters.AddrWidth))
|
||||
|
||||
val debug_read_address = Input(UInt(Parameters.AddrWidth))
|
||||
val debug_read_data = Output(UInt(Parameters.DataWidth))
|
||||
})
|
||||
|
||||
val mem = SyncReadMem(capacity, Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||
when(io.bundle.write_enable) {
|
||||
val write_data_vec = Wire(Vec(Parameters.WordSize, UInt(Parameters.ByteWidth)))
|
||||
for (i <- 0 until Parameters.WordSize) {
|
||||
write_data_vec(i) := io.bundle.write_data((i + 1) * Parameters.ByteBits - 1, i * Parameters.ByteBits)
|
||||
}
|
||||
mem.write((io.bundle.address >> 2.U).asUInt, write_data_vec, io.bundle.write_strobe)
|
||||
}
|
||||
io.bundle.read_data := mem.read((io.bundle.address >> 2.U).asUInt, true.B).asUInt
|
||||
io.debug_read_data := mem.read((io.debug_read_address >> 2.U).asUInt, true.B).asUInt
|
||||
io.instruction := mem.read((io.instruction_address >> 2.U).asUInt, true.B).asUInt
|
||||
}
|
||||
50
lab2/朱梓涵24325356/scala/peripheral/ROMLoader.scala
Normal file
50
lab2/朱梓涵24325356/scala/peripheral/ROMLoader.scala
Normal file
@@ -0,0 +1,50 @@
|
||||
// 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 riscv.Parameters
|
||||
|
||||
class ROMLoader(capacity: Int) extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val bundle = Flipped(new RAMBundle)
|
||||
|
||||
val rom_address = Output(UInt(Parameters.AddrWidth))
|
||||
val rom_data = Input(UInt(Parameters.InstructionWidth))
|
||||
|
||||
val load_address = Input(UInt(Parameters.AddrWidth))
|
||||
val load_finished = Output(Bool())
|
||||
})
|
||||
|
||||
val address = RegInit(0.U(32.W))
|
||||
val valid = RegInit(false.B)
|
||||
|
||||
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(false.B))
|
||||
io.bundle.address := 0.U
|
||||
io.bundle.write_data := 0.U
|
||||
io.bundle.write_enable := false.B
|
||||
when(address <= (capacity - 1).U) {
|
||||
io.bundle.write_enable := true.B
|
||||
io.bundle.write_data := io.rom_data
|
||||
io.bundle.address := (address << 2.U).asUInt + io.load_address
|
||||
io.bundle.write_strobe := VecInit(Seq.fill(Parameters.WordSize)(true.B))
|
||||
address := address + 1.U
|
||||
when(address === (capacity - 1).U) {
|
||||
valid := true.B
|
||||
}
|
||||
}
|
||||
io.load_finished := valid
|
||||
io.rom_address := address
|
||||
}
|
||||
61
lab2/朱梓涵24325356/scala/peripheral/Timer.scala
Normal file
61
lab2/朱梓涵24325356/scala/peripheral/Timer.scala
Normal file
@@ -0,0 +1,61 @@
|
||||
// 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._
|
||||
import riscv.Parameters
|
||||
|
||||
class Timer extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val bundle = new RAMBundle
|
||||
val signal_interrupt = Output(Bool())
|
||||
|
||||
val debug_limit = Output(UInt(Parameters.DataWidth))
|
||||
val debug_enabled = Output(Bool())
|
||||
})
|
||||
|
||||
|
||||
val count = RegInit(0.U(32.W))
|
||||
val limit = RegInit(100000000.U(32.W))
|
||||
io.debug_limit := limit
|
||||
val enabled = RegInit(true.B)
|
||||
io.debug_enabled := enabled
|
||||
|
||||
//lab2(CLINTCSR)
|
||||
val address = io.bundle.address
|
||||
io.bundle.read_data := 0.U
|
||||
when(address === 0x4.U) {
|
||||
io.bundle.read_data := limit
|
||||
}.elsewhen(address === 0x8.U) {
|
||||
io.bundle.read_data := enabled
|
||||
}
|
||||
|
||||
when(io.bundle.write_enable) {
|
||||
when(address === 0x4.U) {
|
||||
limit := io.bundle.write_data
|
||||
}.elsewhen(address === 0x8.U) {
|
||||
enabled := io.bundle.write_data(0)
|
||||
}
|
||||
}
|
||||
|
||||
when(enabled && count >= limit) {
|
||||
io.signal_interrupt := true.B
|
||||
count := 0.U
|
||||
}.otherwise {
|
||||
io.signal_interrupt := false.B
|
||||
count := count + 1.U
|
||||
}
|
||||
}
|
||||
204
lab2/朱梓涵24325356/scala/peripheral/UART.scala
Normal file
204
lab2/朱梓涵24325356/scala/peripheral/UART.scala
Normal file
@@ -0,0 +1,204 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
116
lab2/朱梓涵24325356/scala/peripheral/VGADisplay.scala
Normal file
116
lab2/朱梓涵24325356/scala/peripheral/VGADisplay.scala
Normal file
@@ -0,0 +1,116 @@
|
||||
// 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._
|
||||
|
||||
|
||||
class VGASync extends Module {
|
||||
val io = IO(new Bundle {
|
||||
val hsync = Output(Bool())
|
||||
val vsync = Output(Bool())
|
||||
val video_on = Output(Bool())
|
||||
val p_tick = Output(Bool())
|
||||
val f_tick = Output(Bool())
|
||||
val x = Output(UInt(10.W))
|
||||
val y = Output(UInt(10.W))
|
||||
})
|
||||
|
||||
val DisplayHorizontal = ScreenInfo.DisplayHorizontal
|
||||
val DisplayVertical = ScreenInfo.DisplayVertical
|
||||
|
||||
val BorderLeft = 48
|
||||
val BorderRight = 16
|
||||
val BorderTop = 10
|
||||
val BorderBottom = 33
|
||||
|
||||
val RetraceHorizontal = 96
|
||||
val RetraceVertical = 2
|
||||
|
||||
val MaxHorizontal = DisplayHorizontal + BorderLeft + BorderRight + RetraceHorizontal - 1
|
||||
val MaxVertical = DisplayVertical + BorderTop + BorderBottom + RetraceVertical - 1
|
||||
|
||||
val RetraceHorizontalStart = DisplayHorizontal + BorderRight
|
||||
val RetraceHorizontalEnd = RetraceHorizontalStart + RetraceHorizontal - 1
|
||||
|
||||
val RetraceVerticalStart = DisplayVertical + BorderBottom
|
||||
val RetraceVerticalEnd = RetraceVerticalStart + RetraceVertical - 1
|
||||
|
||||
val pixel = RegInit(UInt(2.W), 0.U)
|
||||
val pixel_next = Wire(UInt(2.W))
|
||||
val pixel_tick = Wire(Bool())
|
||||
|
||||
val v_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
val h_count_reg = RegInit(UInt(10.W), 0.U)
|
||||
|
||||
val v_count_next = Wire(UInt(10.W))
|
||||
val h_count_next = Wire(UInt(10.W))
|
||||
|
||||
val vsync_reg = RegInit(Bool(), false.B)
|
||||
val hsync_reg = RegInit(Bool(), false.B)
|
||||
|
||||
val vsync_next = Wire(Bool())
|
||||
val hsync_next = Wire(Bool())
|
||||
|
||||
pixel_next := pixel + 1.U
|
||||
pixel_tick := pixel === 0.U
|
||||
|
||||
h_count_next := Mux(
|
||||
pixel_tick,
|
||||
Mux(h_count_reg === MaxHorizontal.U, 0.U, h_count_reg + 1.U),
|
||||
h_count_reg
|
||||
)
|
||||
|
||||
v_count_next := Mux(
|
||||
pixel_tick && h_count_reg === MaxHorizontal.U,
|
||||
Mux(v_count_reg === MaxVertical.U, 0.U, v_count_reg + 1.U),
|
||||
v_count_reg
|
||||
)
|
||||
|
||||
hsync_next := h_count_reg >= RetraceHorizontalStart.U && h_count_reg <= RetraceHorizontalEnd.U
|
||||
vsync_next := v_count_reg >= RetraceVerticalStart.U && v_count_reg <= RetraceVerticalEnd.U
|
||||
|
||||
pixel := pixel_next
|
||||
hsync_reg := hsync_next
|
||||
vsync_reg := vsync_next
|
||||
v_count_reg := v_count_next
|
||||
h_count_reg := h_count_next
|
||||
|
||||
io.video_on := h_count_reg < DisplayHorizontal.U && v_count_reg < DisplayVertical.U
|
||||
io.hsync := hsync_reg
|
||||
io.vsync := vsync_reg
|
||||
io.x := h_count_reg
|
||||
io.y := v_count_reg
|
||||
io.p_tick := pixel_tick
|
||||
io.f_tick := io.x === 0.U && io.y === 0.U
|
||||
}
|
||||
|
||||
class VGADisplay extends Module {
|
||||
val io = IO(new Bundle() {
|
||||
val x = Output(UInt(16.W))
|
||||
val y = Output(UInt(16.W))
|
||||
val video_on = Output(Bool())
|
||||
|
||||
val hsync = Output(Bool())
|
||||
val vsync = Output(Bool())
|
||||
})
|
||||
|
||||
val sync = Module(new VGASync)
|
||||
io.hsync := sync.io.hsync
|
||||
io.vsync := sync.io.vsync
|
||||
io.x := sync.io.x
|
||||
io.y := sync.io.y
|
||||
io.video_on := sync.io.y
|
||||
}
|
||||
Reference in New Issue
Block a user