Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRC Generation Module #54

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
bf62871
Wrote initial module structure
ronitnag04 Oct 23, 2023
6a36944
Added Reset Logic
ronitnag04 Oct 23, 2023
472b6da
Generated CRC-16 Lookup table
ronitnag04 Oct 23, 2023
78584bc
Created lookup table class for CRC calculations
ronitnag04 Oct 23, 2023
d27e94b
Fixed lookup table format and successful import
ronitnag04 Oct 23, 2023
d2ab201
Set up CRC Gen algorithm (not functional)
ronitnag04 Oct 24, 2023
7341b9f
Updated CRCGenerator for Shift Register (non-functional)
ronitnag04 Oct 25, 2023
643b383
Compiled, functioning shift, algorithm incorrect
ronitnag04 Oct 26, 2023
2b9bb8a
Test Structure fixed
ronitnag04 Oct 26, 2023
a0ed001
Resolved issues, added test cases
ronitnag04 Oct 26, 2023
ad22060
Added test cases
ronitnag04 Oct 26, 2023
eaead7e
style: Refactored to snake_case, split test modules
ronitnag04 Oct 26, 2023
ba286e3
Refactored data_in to message Decoupled ReadyValid3IO
ronitnag04 Oct 26, 2023
6ee2f2b
Remove helper files
ronitnag04 Oct 26, 2023
63cd816
Format changes
ronitnag04 Nov 1, 2023
7a8e649
Format with scalafmtAll
ronitnag04 Nov 1, 2023
0b3c701
Added back-to-back 1024-bit test
ronitnag04 Nov 1, 2023
618df0b
Reconfigured CRC 3IO interface, documentation
ronitnag04 Nov 1, 2023
252ed7e
Fixed documentation typo
ronitnag04 Nov 1, 2023
b2837fd
Reconfigured IO, testing with DecoupledDriver
ronitnag04 Nov 2, 2023
966ba5e
Fixed lookup table docstring
ronitnag04 Nov 2, 2023
5465b45
Fixed with scalafmtAll
ronitnag04 Nov 2, 2023
2bf4ecb
refactor: make CRC16Lookup an object
ethanwu10 Nov 2, 2023
7f83684
Fixed error test case
ronitnag04 Nov 3, 2023
8946b69
Reconfigured CRC update to one line
ronitnag04 Nov 15, 2023
d6d3b53
Added paramterized bytes consumed per cycle
ronitnag04 Nov 18, 2023
97a8bb0
Merge branch 'main' into d2dadapter-crc
ronitnag04 Nov 18, 2023
cbeb474
Refactored to only send next-consumed message bits
ronitnag04 Nov 29, 2023
091cddf
Fixed formatting
ronitnag04 Nov 29, 2023
3d4ee4f
Replaced CRC lookup table with shift, XOR CRC_poly method
ronitnag04 Dec 14, 2023
1df3eda
Merge branch 'main' into d2dadapter-crc
ronitnag04 Feb 24, 2024
71d1365
Merge branch 'd2dadapter-crc' of https://github.com/ucb-ucie/uciedigi…
ronitnag04 Feb 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 17 additions & 41 deletions src/main/scala/d2dadapter/CRCGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package edu.berkeley.cs.ucie.digital.d2dadapter

import chisel3._
import chisel3.util._
import chisel3.util.Decoupled
import edu.berkeley.cs.ucie.digital.d2dadapter.CRC16Lookup

/** Generates the CRC of data using the polynomial x^16 + x^15 + x^2 + 1. The
* message must be formatted according to the UCIe1.1 spec, and the message
Expand All @@ -19,16 +17,10 @@ import edu.berkeley.cs.ucie.digital.d2dadapter.CRC16Lookup
* The input and output controls of the CRCGenerator module
*/

class CRCGenerator(width: Int) extends Module { //
class CRCGenerator(width: Int) extends Module {
assert(width % 8 == 0)
val io = IO(new Bundle {

/** Resets the CRCGenerator, and sets the default message ready state high
* and crc valid state low. CRC bits will be cleared to 0.
* @group Signals
*/
val reset = Input(Bool())

/** ReadyValid3IO interface to allow consumer to transfer message bits to
/** ReadyValidIO interface to allow consumer to transfer message bits to
* the CRCGenerator. Message bits are latched when message ready and
* message valid are high for the same clock cycle, and then the
* CRCGenerator is locked into the calculation loop.
Expand All @@ -43,7 +35,7 @@ class CRCGenerator(width: Int) extends Module { //
*/
val message = Flipped(Decoupled(Bits(width.W)))

/** ReadyValid3IO interface to allow CRCGenerator to transfer crc bits to
/** ReadyValidIO interface to allow CRCGenerator to transfer crc bits to
* the consumer. CRC will be cleared to 0 and invalid on reset.
*
* Once message bits have been transfered, the CRCGenerator will enter the
Expand All @@ -70,14 +62,10 @@ class CRCGenerator(width: Int) extends Module { //
val crc_valid = RegInit(Bool(), false.B)

// CRC calculating registers
val step = RegInit(
UInt(log2Ceil(width / 8 + 1).W),
0.U,
) // Store number of bytes in width bits
val message_bits = RegInit(
Bits(width.W),
0.U,
) // Latches full word of data when message_ready and data_val
// Store number of bytes in width bits
val step = RegInit(0.U(log2Ceil(width / 8 + 1).W))
// Latches full message when message_ready and data_val
val message_bits = RegInit(Bits(width.W), 0.U)

// CRC calculating table
val lookup = new CRC16Lookup
Expand All @@ -89,32 +77,22 @@ class CRCGenerator(width: Int) extends Module { //
io.crc.valid := crc_valid
io.message.ready := message_ready

// Reset logic
when(io.reset) {
// Reset output data registers

// Latch data on message_ready and data_val
when(io.message.fire) {
// Reset logic
crc0 := 0.U
crc1 := 0.U

// Signal Valid and Ready
crc_valid := false.B
message_ready := true.B

// Reset CRC calculating registers
step := 0.U
}

// Latch data on message_ready and data_val
when(io.message.valid & io.message.ready) {
step := (width / 8).U // Reset step to number of bytes in word
step := (width / 8).U // Set step to number of bytes in word
message_bits := io.message.bits
crc_valid := false.B
message_ready := false.B
}

// Computation not finished when step is not 0
when(step > 0.U) {
crc1 := crc0 ^ lookup
.table(crc1 ^ message_bits(width - 1, width - 8))(15, 8)
crc1 := crc0 ^ lookup.table(crc1 ^ message_bits(width - 1, width - 8))(15, 8)
crc0 := lookup.table(crc1 ^ message_bits(width - 1, width - 8))(7, 0)
message_bits := message_bits << 8
step := step - 1.U
Expand All @@ -123,10 +101,8 @@ class CRCGenerator(width: Int) extends Module { //

/* Idle with crc output valid until consumer initiates transfer of CRC with
* io.crc.ready */
when(crc_valid) {
if (io.crc.ready == true.B) {
crc_valid := false.B
message_ready := true.B
}
when(io.crc.fire) {
crc_valid := false.B
message_ready := true.B
}
}
159 changes: 47 additions & 112 deletions src/test/scala/d2dadapter/CRCGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,75 +9,38 @@ class CRCGeneratorTest extends AnyFunSpec with ChiselScalatestTester {
describe("CRCGenerator, 32-bit messages") {
it("should produce h8BC as the 16-bit CRC of hF3D1AB23") {
test(new CRCGenerator(32)).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
c.io.message.bits.poke("hF3D1AB23".U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("h08BC".U)
c.io.message.initSource().setSourceClock(c.clock)
c.io.crc.initSink().setSinkClock(c.clock)
c.io.message.enqueueNow("hF3D1AB23".U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("h08BC".U)
}
}

it("should produce hD34D as the 16-bit CRC of hB481A391") {
test(new CRCGenerator(32)).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
c.io.message.bits.poke("hB481A391".U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("hD34D".U)
c.io.message.initSource().setSourceClock(c.clock)
c.io.crc.initSink().setSinkClock(c.clock)
c.io.message.enqueueNow("hB481A391".U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("hD34D".U)
}
}

it(
"should produce back to back valid 16-bit CRCs of hF3D1AB23 and hB481A391",
) {
test(new CRCGenerator(32)).withAnnotations(Seq(WriteVcdAnnotation)) { c =>
c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
c.io.message.bits.poke("hF3D1AB23".U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("h08BC".U)
c.io.message.initSource().setSourceClock(c.clock)
c.io.crc.initSink().setSinkClock(c.clock)

c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
c.io.message.bits.poke("hB481A391".U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("hD34D".U)
c.io.message.enqueueNow("hF3D1AB23".U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("h08BC".U)

c.io.message.enqueue("hB481A391".U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("hD34D".U)
}
}
}
Expand All @@ -86,9 +49,8 @@ class CRCGeneratorTest extends AnyFunSpec with ChiselScalatestTester {
it("should produce h5557 as the 16-bit CRC of he3c3598e...") {
test(new CRCGenerator(1024)).withAnnotations(Seq(WriteVcdAnnotation)) {
c =>
c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
c.io.message.initSource().setSourceClock(c.clock)
c.io.crc.initSink().setSinkClock(c.clock)
val num =
("he3c3598e_dd1a3be2_d429ad05_2b927c61_" +
"c2ba41b6_fc7ac0df_093b5d8b_b754d97d_" +
Expand All @@ -98,26 +60,17 @@ class CRCGeneratorTest extends AnyFunSpec with ChiselScalatestTester {
"bba8b55f_0eadc080_b0955182_0d8200ce_" +
"31a58b25_6c8086f6_d535913e_e7867535_" +
"f5e15126_f682f852_0fb831c3_ba7e5b69")
c.io.message.bits.poke((num).U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("h5557".U)
c.io.message.enqueueNow((num).U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("h5557".U)
}
}

it("should produce h5b39 as the 16-bit CRC of h21940141...") {
test(new CRCGenerator(1024)).withAnnotations(Seq(WriteVcdAnnotation)) {
c =>
c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
c.io.message.initSource().setSourceClock(c.clock)
c.io.crc.initSink().setSinkClock(c.clock)
val num =
"h21940141_94204c5b_66aadb33_39ff52dd_" +
"59187e4d_8d7f45a0_92f32508_9fdc1174_" +
Expand All @@ -127,17 +80,9 @@ class CRCGeneratorTest extends AnyFunSpec with ChiselScalatestTester {
"1651c46c_3f9a38dd_50d0b5a9_4a8f23e3_" +
"f1915b39_e0570141_22bdfa54_293ad6fe_" +
"3ef3d240_ae894873_835dc657_881e5c7d"
c.io.message.bits.poke((num).U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("h5B39".U)
c.io.message.enqueueNow((num).U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("h5B39".U)
}
}

Expand All @@ -146,9 +91,8 @@ class CRCGeneratorTest extends AnyFunSpec with ChiselScalatestTester {
) {
test(new CRCGenerator(1024)).withAnnotations(Seq(WriteVcdAnnotation)) {
c =>
c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
c.io.message.initSource().setSourceClock(c.clock)
c.io.crc.initSink().setSinkClock(c.clock)
val num1 =
("he3c3598e_dd1a3be2_d429ad05_2b927c61_" +
"c2ba41b6_fc7ac0df_093b5d8b_b754d97d_" +
Expand All @@ -158,21 +102,10 @@ class CRCGeneratorTest extends AnyFunSpec with ChiselScalatestTester {
"bba8b55f_0eadc080_b0955182_0d8200ce_" +
"31a58b25_6c8086f6_d535913e_e7867535_" +
"f5e15126_f682f852_0fb831c3_ba7e5b69")
c.io.message.bits.poke((num1).U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("h5557".U)
c.io.message.enqueueNow((num1).U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("h5557".U)

c.io.reset.poke(true.B)
c.clock.step()
c.io.reset.poke(false.B)
val num2 = "h21940141_94204c5b_66aadb33_39ff52dd_" +
"59187e4d_8d7f45a0_92f32508_9fdc1174_" +
"62f98566_b5767b24_38ffcf48_dcd48173_" +
Expand All @@ -181,18 +114,20 @@ class CRCGeneratorTest extends AnyFunSpec with ChiselScalatestTester {
"1651c46c_3f9a38dd_50d0b5a9_4a8f23e3_" +
"f1915b39_e0570141_22bdfa54_293ad6fe_" +
"3ef3d240_ae894873_835dc657_881e5c7d"
c.io.message.bits.poke((num2).U)
c.clock.step()
c.io.message.valid.poke(true.B)
c.clock.step()
c.io.message.valid.poke(false.B)
c.io.crc.ready.poke(true.B)
c.clock.step()
while (c.io.crc.valid.peek().litValue != 1) {
c.clock.step()
}
c.io.crc.bits.expect("h5B39".U)
c.io.message.enqueue((num2).U)
c.io.crc.waitForValid()
c.io.crc.expectDequeueNow("h5B39".U)
}
}
}

describe("CRCGenerator, 1023-bit width") {
it("should fail due to invalid width = 1023 % 8 != 0") {
assertThrows[AssertionError] {
test(new CRCGenerator(1023)) { c =>
throw new AssertionError
ronitnag04 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
}