Verified Commit af265cdc authored by Minyong Li's avatar Minyong Li 💬
Browse files

project: migrate Module to MultiIOModule

parent 453d1bdb
Pipeline #7472 passed with stage
in 57 seconds
......@@ -13,7 +13,6 @@ lazy val root = (project in file("."))
"edu.berkeley.cs" %% "chiseltest" % "0.3.3" % "test"
),
scalacOptions ++= Seq(
"-Xsource:2.11",
"-language:reflectiveCalls",
"-deprecation",
"-feature",
......
......@@ -5,22 +5,20 @@ package uk.ac.soton.ecs.can.core
import chisel3._
class ChaChaBlock extends Module {
val io = IO(new Bundle {
val muxIn = Input(Bool())
val in = Input(Vec(16, UInt(32.W)))
val out = Output(Vec(16, UInt(32.W)))
})
class ChaChaBlock extends MultiIOModule {
val muxIn = IO(Input(Bool()))
val in = IO(Input(Vec(16, UInt(32.W))))
val out = IO(Output(Vec(16, UInt(32.W))))
val initialState = Reg(Vec(16, UInt(32.W)))
val doubleRound = Module(new ChaChaInnerBlock(regBetweenRounds = true))
val doubleRoundState = Reg(Vec(16, UInt(32.W)))
initialState := io.in
doubleRound.io.in := Mux(io.muxIn, initialState, doubleRoundState)
doubleRoundState := doubleRound.io.out
initialState := in
doubleRound.in := Mux(muxIn, initialState, doubleRoundState)
doubleRoundState := doubleRound.out
val addedState = doubleRoundState.zip(initialState).map(t => t._1 + t._2)
io.out := addedState
out := addedState
}
......@@ -5,11 +5,9 @@ package uk.ac.soton.ecs.can.core
import chisel3._
class ChaChaInnerBlock(regBetweenRounds: Boolean) extends Module {
val io = IO(new Bundle {
val in = Input(Vec(16, UInt(32.W)))
val out = Output(Vec(16, UInt(32.W)))
})
class ChaChaInnerBlock(regBetweenRounds: Boolean) extends MultiIOModule {
val in = IO(Input(Vec(16, UInt(32.W))))
val out = IO(Output(Vec(16, UInt(32.W))))
val betweenRounds =
if (regBetweenRounds)
......@@ -20,8 +18,8 @@ class ChaChaInnerBlock(regBetweenRounds: Boolean) extends Module {
val columnRound = Module(new ColumnRound)
val diagonalRound = Module(new DiagonalRound)
columnRound.io.in := io.in
betweenRounds := columnRound.io.out
diagonalRound.io.in := betweenRounds
io.out := diagonalRound.io.out
columnRound.in := in
betweenRounds := columnRound.out
diagonalRound.in := betweenRounds
out := diagonalRound.out
}
......@@ -5,11 +5,9 @@ package uk.ac.soton.ecs.can.core
import chisel3._
class ColumnRound extends Module {
val io = IO(new Bundle {
val in = Input(Vec(16, UInt(32.W)))
val out = Output(Vec(16, UInt(32.W)))
})
class ColumnRound extends MultiIOModule {
val in = IO(Input(Vec(16, UInt(32.W))))
val out = IO(Output(Vec(16, UInt(32.W))))
Seq(
Seq(0, 4, 8, 12),
......@@ -19,8 +17,8 @@ class ColumnRound extends Module {
).foreach { roundWires =>
val quarterRound = Module(new QuarterRound)
roundWires.zipWithIndex.foreach { roundWire =>
quarterRound.io.in(roundWire._2) := io.in(roundWire._1)
io.out(roundWire._1) := quarterRound.io.out(roundWire._2)
quarterRound.in(roundWire._2) := in(roundWire._1)
out(roundWire._1) := quarterRound.out(roundWire._2)
}
}
}
......@@ -5,24 +5,23 @@ package uk.ac.soton.ecs.can.core
import chisel3._
class DataMemory(addrWidth: Int, dataWidth: Int, size: Int) extends Module {
val io = IO(new Bundle {
val read = new Bundle {
val addr = Input(UInt(addrWidth.W))
val data = Output(UInt(dataWidth.W))
}
val write = new Bundle {
val en = Input(Bool())
val addr = Input(UInt(addrWidth.W))
val data = Input(UInt(dataWidth.W))
}
class DataMemory(addrWidth: Int, dataWidth: Int, size: Int)
extends MultiIOModule {
val read = IO(new Bundle {
val addr = Input(UInt(addrWidth.W))
val data = Output(UInt(dataWidth.W))
})
val write = IO(new Bundle {
val en = Input(Bool())
val addr = Input(UInt(addrWidth.W))
val data = Input(UInt(dataWidth.W))
})
val mem = SyncReadMem(size, UInt(dataWidth.W))
io.read.data := mem(io.read.addr)
read.data := mem(read.addr)
when(io.write.en) {
mem(io.write.addr) := io.write.data
when(write.en) {
mem(write.addr) := write.data
}
}
......@@ -5,11 +5,9 @@ package uk.ac.soton.ecs.can.core
import chisel3._
class DiagonalRound extends Module {
val io = IO(new Bundle {
val in = Input(Vec(16, UInt(32.W)))
val out = Output(Vec(16, UInt(32.W)))
})
class DiagonalRound extends MultiIOModule {
val in = IO(Input(Vec(16, UInt(32.W))))
val out = IO(Output(Vec(16, UInt(32.W))))
Seq(
Seq(0, 5, 10, 15),
......@@ -19,8 +17,8 @@ class DiagonalRound extends Module {
).foreach { roundWires =>
val quarterRound = Module(new QuarterRound)
roundWires.zipWithIndex.foreach { roundWire =>
quarterRound.io.in(roundWire._2) := io.in(roundWire._1)
io.out(roundWire._1) := quarterRound.io.out(roundWire._2)
quarterRound.in(roundWire._2) := in(roundWire._1)
out(roundWire._1) := quarterRound.out(roundWire._2)
}
}
}
......@@ -5,35 +5,34 @@ package uk.ac.soton.ecs.can.core
import chisel3._
class ProgramMemory(addrWidth: Int, cwWidth: Int, size: Int) extends Module {
val io = IO(new Bundle {
val br = new Bundle {
val abs = Input(Bool())
val rel = Input(Bool())
val addr = Input(UInt(addrWidth.W))
}
val cw = Output(UInt(cwWidth.W))
val write = new Bundle {
val en = Input(Bool())
val addr = Input(UInt(addrWidth.W))
val data = Input(UInt(cwWidth.W))
}
class ProgramMemory(addrWidth: Int, cwWidth: Int, size: Int)
extends MultiIOModule {
val br = IO(new Bundle {
val abs = Input(Bool())
val rel = Input(Bool())
val addr = Input(UInt(addrWidth.W))
})
val cw = IO(Output(UInt(cwWidth.W)))
val write = IO(new Bundle {
val en = Input(Bool())
val addr = Input(UInt(addrWidth.W))
val data = Input(UInt(cwWidth.W))
})
val mem = SyncReadMem(size, UInt(cwWidth.W))
val pc = RegInit(0.U(addrWidth.W))
when(io.write.en) {
mem(io.write.addr) := io.write.data
when(write.en) {
mem(write.addr) := write.data
}
when(io.br.abs) {
pc := io.br.addr.asUInt()
}.elsewhen(io.br.rel) {
pc := (pc.asSInt() + io.br.addr.asSInt()).asUInt()
when(br.abs) {
pc := br.addr.asUInt()
}.elsewhen(br.rel) {
pc := (pc.asSInt() + br.addr.asSInt()).asUInt()
}.otherwise {
pc := pc + 1.U
}
io.cw := mem(pc)
cw := mem(pc)
}
......@@ -5,19 +5,17 @@ package uk.ac.soton.ecs.can.core
import chisel3._
class QuarterRound extends Module {
val io = IO(new Bundle {
val in = Input(Vec(4, UInt(32.W)))
val out = Output(Vec(4, UInt(32.W)))
})
class QuarterRound extends MultiIOModule {
val in = IO(Input(Vec(4, UInt(32.W))))
val out = IO(Output(Vec(4, UInt(32.W))))
private def rotateLeft(v: UInt, b: Int): UInt =
v(31 - b, 0) ## v(31, 32 - b)
val a0 = io.in(0)
val b0 = io.in(1)
val c0 = io.in(2)
val d0 = io.in(3)
val a0 = in(0)
val b0 = in(1)
val c0 = in(2)
val d0 = in(3)
val a1 = a0 + b0
val d1 = rotateLeft(d0 ^ a1, 16)
......@@ -29,8 +27,8 @@ class QuarterRound extends Module {
val c2 = c1 + d2
val b2 = rotateLeft(b1 ^ c2, 7)
io.out(0) := a2
io.out(1) := b2
io.out(2) := c2
io.out(3) := d2
out(0) := a2
out(1) := b2
out(2) := c2
out(3) := d2
}
......@@ -64,7 +64,7 @@ class ChaChaBlockTest extends FlatSpec with ChiselScalatestTester {
)
private def doTest(c: ChaChaBlock, testVector: Seq[(UInt, UInt)]) {
c.io.in.zip(testVector).foreach { t =>
c.in.zip(testVector).foreach { t =>
t._1.poke(t._2._1)
}
......@@ -72,20 +72,20 @@ class ChaChaBlockTest extends FlatSpec with ChiselScalatestTester {
c.clock.step()
// Select the initial state register as the input to the 2-round circuit
c.io.muxIn.poke(true.B)
c.muxIn.poke(true.B)
// Shift the 2-rounded state to the round register
c.clock.step(2)
// Select the round register as the input to the 2-round circuit
c.io.muxIn.poke(false.B)
c.muxIn.poke(false.B)
// Depending on the ChaCha variant and the pipeline configuration, wait
// for the correct time for the correct result. Note that one 2-round has
// been processed in the above steps.
c.clock.step(19)
c.io.out.zip(testVector).foreach { t =>
c.out.zip(testVector).foreach { t =>
t._1.expect(t._2._2)
}
}
......
......@@ -16,40 +16,40 @@ class DataMemoryTest extends FlatSpec with ChiselScalatestTester {
it should "store some values" in {
test(new DataMemory(addrWidth, dataWidth, size)) { c =>
c.io.write.addr.poke("h01".U(addrWidth.W))
c.io.write.data.poke("h1234".U(dataWidth.W))
c.io.write.en.poke(true.B)
c.write.addr.poke("h01".U(addrWidth.W))
c.write.data.poke("h1234".U(dataWidth.W))
c.write.en.poke(true.B)
c.clock.step(2)
c.io.write.en.poke(false.B)
c.io.read.addr.poke("h01".U(addrWidth.W))
c.write.en.poke(false.B)
c.read.addr.poke("h01".U(addrWidth.W))
c.clock.step(2)
c.io.read.data.expect("h1234".U(dataWidth.W))
c.read.data.expect("h1234".U(dataWidth.W))
c.io.write.addr.poke("h0a".U(addrWidth.W))
c.io.write.data.poke("hfefe".U(dataWidth.W))
c.io.write.en.poke(true.B)
c.write.addr.poke("h0a".U(addrWidth.W))
c.write.data.poke("hfefe".U(dataWidth.W))
c.write.en.poke(true.B)
c.clock.step(2)
c.io.write.en.poke(false.B)
c.io.read.addr.poke("h0a".U(addrWidth.W))
c.write.en.poke(false.B)
c.read.addr.poke("h0a".U(addrWidth.W))
c.clock.step(2)
c.io.read.data.expect("hfefe".U(dataWidth.W))
c.read.data.expect("hfefe".U(dataWidth.W))
}
}
it should "not write without write enable" in {
test(new DataMemory(addrWidth, dataWidth, size)) { c =>
c.io.write.addr.poke("h06".U(addrWidth.W))
c.io.write.data.poke("hcafe".U(dataWidth.W))
c.io.write.en.poke(true.B)
c.write.addr.poke("h06".U(addrWidth.W))
c.write.data.poke("hcafe".U(dataWidth.W))
c.write.en.poke(true.B)
c.clock.step(2)
c.io.write.en.poke(false.B)
c.io.read.addr.poke("h06".U(addrWidth.W))
c.write.en.poke(false.B)
c.read.addr.poke("h06".U(addrWidth.W))
c.clock.step(2)
c.io.read.data.expect("hcafe".U(dataWidth.W))
c.read.data.expect("hcafe".U(dataWidth.W))
c.io.write.data.poke("hefac".U(dataWidth.W))
c.write.data.poke("hefac".U(dataWidth.W))
c.clock.step(8)
c.io.read.data.expect("hcafe".U(dataWidth.W))
c.read.data.expect("hcafe".U(dataWidth.W))
}
}
}
......@@ -24,15 +24,15 @@ class ProgramMemoryTest extends FlatSpec with ChiselScalatestTester {
private def initMemory(pm: ProgramMemory): Unit = {
pm.reset.poke(true.B)
pm.io.write.en.poke(true.B)
pm.write.en.poke(true.B)
memMap.foreach { m =>
pm.io.write.addr.poke(m._1)
pm.io.write.data.poke(m._2)
pm.write.addr.poke(m._1)
pm.write.data.poke(m._2)
pm.clock.step()
}
pm.io.write.en.poke(false.B)
pm.write.en.poke(false.B)
pm.reset.poke(false.B)
}
......@@ -40,23 +40,23 @@ class ProgramMemoryTest extends FlatSpec with ChiselScalatestTester {
it should "be writable and readable as PC increments" in {
test(new ProgramMemory(addrWidth, cwWidth, size)) { c =>
c.io.br.abs.poke(false.B)
c.io.br.rel.poke(false.B)
c.io.br.addr.poke(0.U(addrWidth.W))
c.br.abs.poke(false.B)
c.br.rel.poke(false.B)
c.br.addr.poke(0.U(addrWidth.W))
initMemory(c)
c.io.cw.expect("h0000".U(cwWidth.W))
c.cw.expect("h0000".U(cwWidth.W))
c.clock.step()
// NOTE: FPGA block RAM is synchronous-read. At this moment a new value
// has been fetched, but this 1-cycle delay exists because it hasn't been
// stored into the read register yet.
c.io.cw.expect("h0000".U(cwWidth.W))
c.cw.expect("h0000".U(cwWidth.W))
c.clock.step()
memMap.takeRight(memMap.length - 1).foreach { m =>
c.io.cw.expect(m._2)
c.cw.expect(m._2)
c.clock.step()
}
}
......@@ -64,39 +64,39 @@ class ProgramMemoryTest extends FlatSpec with ChiselScalatestTester {
it should "do relative branching correctly" in {
test(new ProgramMemory(addrWidth, cwWidth, size)) { c =>
c.io.br.abs.poke(false.B)
c.io.br.rel.poke(false.B)
c.io.br.addr.poke(0.U(addrWidth.W))
c.br.abs.poke(false.B)
c.br.rel.poke(false.B)
c.br.addr.poke(0.U(addrWidth.W))
initMemory(c)
c.io.cw.expect("h0000".U(cwWidth.W))
c.cw.expect("h0000".U(cwWidth.W))
c.clock.step()
memMap.take(3).foreach { m =>
c.io.cw.expect(m._2)
c.cw.expect(m._2)
c.clock.step()
}
// @ 0x03 -> 0x369a
c.io.cw.expect("h369a".U(cwWidth.W))
c.cw.expect("h369a".U(cwWidth.W))
// > 0x06 -> 0x6efc
// NOTE: Because of the synchronous BRAM, a 1-cycle delay slot is
// introduced. At this moment 0x04 has been fetched, so the offset should
// be calculated based on 0x04 rather than 0x03. Here 4 + 2 = 6.
c.io.br.addr.poke(2.U(addrWidth.W))
c.io.br.rel.poke(true.B)
c.br.addr.poke(2.U(addrWidth.W))
c.br.rel.poke(true.B)
c.clock.step()
c.io.br.rel.poke(false.B)
c.br.rel.poke(false.B)
// 0x04 is now present, but 0x06 has been fetched
c.io.cw.expect("h4c2d".U(cwWidth.W))
c.cw.expect("h4c2d".U(cwWidth.W))
c.clock.step()
// @ 0x06 now
memMap.takeRight(2).foreach { m =>
c.io.cw.expect(m._2)
c.cw.expect(m._2)
c.clock.step()
}
}
......@@ -104,36 +104,36 @@ class ProgramMemoryTest extends FlatSpec with ChiselScalatestTester {
it should "do absolute branching correctly" in {
test(new ProgramMemory(addrWidth, cwWidth, size)) { c =>
c.io.br.abs.poke(false.B)
c.io.br.rel.poke(false.B)
c.io.br.addr.poke(0.U(addrWidth.W))
c.br.abs.poke(false.B)
c.br.rel.poke(false.B)
c.br.addr.poke(0.U(addrWidth.W))
initMemory(c)
c.io.cw.expect("h0000".U(cwWidth.W))
c.cw.expect("h0000".U(cwWidth.W))
c.clock.step()
memMap.take(5).foreach { m =>
c.io.cw.expect(m._2)
c.cw.expect(m._2)
c.clock.step()
}
// @ 0x05 -> 0x59f7
c.io.cw.expect("h59f7".U(cwWidth.W))
c.cw.expect("h59f7".U(cwWidth.W))
// > 0x01 -> 0x1234
c.io.br.addr.poke("h01".U(addrWidth.W))
c.io.br.abs.poke(true.B)
c.br.addr.poke("h01".U(addrWidth.W))
c.br.abs.poke(true.B)
c.clock.step()
c.io.br.abs.poke(false.B)
c.br.abs.poke(false.B)
// Delay slot: 0x06 will present no matter what
c.io.cw.expect("h6efc".U(cwWidth.W))
c.cw.expect("h6efc".U(cwWidth.W))
c.clock.step()
// @ 0x01 now
memMap.takeRight(memMap.length - 1).foreach { m =>
c.io.cw.expect(m._2)
c.cw.expect(m._2)
c.clock.step()
}
}
......
......@@ -12,29 +12,29 @@ class QuarterRoundTest extends FlatSpec with ChiselScalatestTester {
it should "compute RFC8439 2.1.1 test vector correctly" in {
test(new QuarterRound) { c =>
c.io.in(0).poke("h11111111".U(32.W))
c.io.in(1).poke("h01020304".U(32.W))
c.io.in(2).poke("h9b8d6f43".U(32.W))
c.io.in(3).poke("h01234567".U(32.W))
c.in(0).poke("h11111111".U(32.W))
c.in(1).poke("h01020304".U(32.W))
c.in(2).poke("h9b8d6f43".U(32.W))
c.in(3).poke("h01234567".U(32.W))
c.io.out(0).expect("hea2a92f4".U(32.W))
c.io.out(1).expect("hcb1cf8ce".U(32.W))
c.io.out(2).expect("h4581472e".U(32.W))
c.io.out(3).expect("h5881c4bb".U(32.W))
c.out(0).expect("hea2a92f4".U(32.W))
c.out(1).expect("hcb1cf8ce".U(32.W))
c.out(2).expect("h4581472e".U(32.W))
c.out(3).expect("h5881c4bb".U(32.W))
}
}
it should "compute RFC8439 2.2.1 test vector correctly" in {
test(new QuarterRound) { c =>
c.io.in(0).poke("h516461b1".U(32.W))
c.io.in(1).poke("h2a5f714c".U(32.W))
c.io.in(2).poke("h53372767".U(32.W))
c.io.in(3).poke("h3d631689".U(32.W))
c.in(0).poke("h516461b1".U(32.W))
c.in(1).poke("h2a5f714c".U(32.W))
c.in(2).poke("h53372767".U(32.W))
c.in(3).poke("h3d631689".U(32.W))
c.io.out(0).expect("hbdb886dc".U(32.W))
c.io.out(1).expect("hcfacafd2".U(32.W))
c.io.out(2).expect("he46bea80".U(32.W))
c.io.out(3).expect("hccc07c79".U(32.W))
c.out(0).expect("hbdb886dc".U(32.W))
c.out(1).expect("hcfacafd2".U(32.W))
c.out(2).expect("he46bea80".U(32.W))
c.out(3).expect("hccc07c79".U(32.W))
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment