diff --git a/README.md b/README.md
index a353e5e..56ff9e5 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@ Homework 2 - Chisel State
Adopting our agile mindset, some of these problems revise components introduced in prior homework assignments. Although we provide a skeleton for testers, you will need to implement them in order to use them. Be sure not to modify external IO interfaces to maintain compatability with the autograder.
-# Problem 1 - Improved ComplexALU (50pts)
-> Let's enhance our `ComplexALU` from HW1 using `Bundle`s and encapsulation. This problem will consist of multiple parts that build from each other.
+# Problem 1 - Improved ComplexALU (15 pts)
+> Let's enhance your `ComplexALU` from HW1 by using `Bundle`s and encapsulation. This problem will consist of multiple parts that build from each other.
### Part 1 - ComplexNum
> Implement the `ComplexNum` bundle in `src/main/scala/hw2/Complex.scala` by adding two `SInt` fields: `real` and `imag` and four methods with the following signatures:
> ```scala
@@ -31,12 +31,12 @@ Adopting our agile mindset, some of these problems revise components introduced
### Part 3 - ComplexALU
> Implement the `ComplexALU` module in `src/main/scala/hw2/Complex.scala` using only the methods defined in `ComplexNum` to perform arithmetic. It will behave similarly to HW1, except that if the `onlyAdder` parameter is true, the generated hardware will not even include a port for `doAdd`.
>> - if `doAdd` is high, sum the real inputs and sum the imaginary inputs
->> - if `doAdd` is low, find difference between the real inputs and the difference between the imaginary inputs
+>> - if `doAdd` is low, find the difference between the real inputs and the difference between the imaginary inputs
>> - if `onlyAdder` is true, only generate logic to sum the real inputs and sum the imaginary inputs. Since we no longer need `doAdd`, it should be absent from the Verilog.
-# Problem 2 - Improved PolyEval (40pts)
-> Let's enhance our `PolyEval` from HW1 to support arbitrary polynomials. Implement the `PolyEval` module in `src/main/scala/hw2/PolyEval.scala`. The `coefs` parameter is a list of coefficients ordered by ascending exponent powers. The generated hardware should produce the result combinatorally (within a cycle).
+# Problem 2 - Improved PolyEval (15 pts)
+> Let's enhance your `PolyEval` from HW1 to support arbitrary polynomials. Implement the `PolyEval` module in `src/main/scala/hw2/PolyEval.scala`. The `coefs` parameter is a list of coefficients ordered by ascending exponent powers. The generated hardware should produce the result combinatorally (within a cycle).
>
> For example:
> ```
@@ -45,11 +45,13 @@ Adopting our agile mindset, some of these problems revise components introduced
> out = 4*x^0 + 5*x^1 + 6*x^2 = 4 + 10 + 24 = 38
-# Problem 3 - Sine Wave Generator (40pts)
-> Sine waves are useful in DSPs, and in this problem, we will implement a sine wave generator (`SinGen`). Over multiple cycles, the generated hardware will produce the output values for a sine wave. Internally, it will track where it is in the period, and use that to index into a lookup table. The lookup table will hold a single period of the sine wave sampled at `n` points, and those precomputed `sin(x)` values will be stored in a ROM. Use the provided `SineWave` code to populate a ROM in the `SinGen` module located in `src/main/scala/hw2/SineWave.scala`.
+# Problem 3 - Sine Wave Generator (30 pts)
+> Sine waves are useful in DSPs, and in this problem, you will implement a sine wave generator (`SineWaveGen`). Over multiple cycles, the generated hardware will produce the output values for a sine wave. Internally, it will track where it is in the period, and use that to index into a lookup table. The lookup table will hold a single period of the sine wave sin(x) sampled at `period` points. Thus, due to the periodic nature of a sine wave, a point at _p_ should be the same as a point _p + period_. To assist, we provide `SineWave` (in `src/main/scala/hw2/SineWaveGen.scala`) which represents the sine wave to be turned into a hardware table, and it can also be used as a Scala functional model to get the needed points.
-### Part 1 - SinGenIO
-> Implement the `SinGenIO` bundle in `src/main/scala/hw2/SineWave.scala` by adding two `Input` fields:
+> Since we are working with UInts instead of floating-point, we use the parameter `amplitude` to scale up the result. The generated hardware will take two inputs (`en` and `stride`). Each cycle the module will output the next sample if `en` is high, or keep returning the same sample if `en` is low. The `stride` input determines how many samples to step through the ROM each cycle. Note, that `stride` may not evenly divide the period.
+
+### Part 1 - SineWaveGenIO
+> Implement the `SineWaveGenIO` bundle in `src/main/scala/hw2/SineWaveGen.scala` by adding two `Input` fields:
> ```scala
> stride: UInt
> en: Bool
@@ -59,28 +61,27 @@ Adopting our agile mindset, some of these problems revise components introduced
> out: SInt
> ```
-### Part 2 - SinGen
-> Implement the `SinGen` module in `src/main/scala/hw2/SineWave.scala`. Use `SinGenIO` as the module's IO. Each cycle the module will output the next sample if `en` is high, or keep returning the same sample if `en` is low. The `stride` input determines how many samples to step through the ROM each cycle.
+### Part 2 - SineWaveGen
+> Implement the `SineWaveGen` module in `src/main/scala/hw2/SineWaveGen.scala`, using a `SineWaveGenIO` as the module's IO.
>> Example given these parameters:
>> ```scala
->> val period = 8
+>> val period = 16
>> val amplitude = 128
->> val n = 16
>> ```
->> If `stride` is `1` then `SinGen` will return one value each cycle in this order:
+>> If `stride` is `1` then `SineWaveGen` will return one value each cycle in this order:
>> ```
>> 0, 48, 90, 118, 128, 118, 90, 48, 0, -48, -90, -118, -128, -118, -90, -48
>> ```
->> If `stride` is `2` then `SinGen` will return one value each cycle in this order:
+>> If `stride` is `2` then `SineWaveGen` will return one value each cycle in this order:
>> ```
>> 0, 90, 128, 90, 0, -90, -128, -90
>> ```
-# Problem 4 - XOR Cipher (60pts)
-> The XOR operation is the basis of a simple cryptographic encryption algorithm called an [XOR cipher](https://en.wikipedia.org/wiki/XOR_cipher). Given a secret `key` and `data` of the same length, we can encrypt `data` by performing `ciphertext = in ^ key`. We can decrypt `ciphertext` by performing `in = ciphertext ^ key`.
+# Problem 4 - XOR Cipher (40 pts)
+> An [XOR cipher](https://en.wikipedia.org/wiki/XOR_cipher) is a simple cryptographic encryption technique based on the XOR operation. Given a secret `key` and `data` of the same length, we can encrypt `data` by performing `ciphertext = data ^ key`. We can decrypt `ciphertext` by performing `data = ciphertext ^ key`.
-> We will implement a simple XOR cipher. Inside the generated hardware, there will be a register to hold the data (potentially encrypted) and a register to hold the key. We will use a state machine internally to keep track of the status of the system. Upon reset, the system will wait until it is given a secret key to load in. With the secret key stored inside, it is now ready to accept data. When given data, it will encrypt it on the way in. The data can be decrypted, but after a cycle it must be overwritten or zeroed out.
+> You will implement a simple XOR cipher. Inside the generated hardware, there will be a register _data_ to hold the data (potentially encrypted) and a register _key_ to hold the key. You will use a state machine internally to keep track of the status of the system. Upon reset, the system will wait until it is given an input secret key to load in. Once the secret key is stored inside _key_, it is now ready to accept input data. When given input data, it will encrypt it on the way in and store it in _data_ as ciphertext. The ciphertext in _data_ can be decrypted, but after a cycle the decrypted data must be overwritten or zeroed out.
>
> To encode commands, we use the following input signals:
> - `clear`: zero out both the _data_ and the secret _key_
@@ -99,14 +100,14 @@ Adopting our agile mindset, some of these problems revise components introduced
> out: UInt (output of data register)
> full: Bool (data register has valid data)
> encrypted: Bool (data register has encrypted data)
-> state: UInt (eases testing of FSM)
+> state: CipherState (eases testing of FSM)
### Part 2 - XORCipher
> Implement the `XORCipher` module in `src/main/scala/hw2/XORCipher.scala` using `XORCipherIO` as the IO. We will build a FSM with four states:
-> - `clear`: data and key are both 0
-> - `ready`: secret key is set
-> - `encrypted`: data is stored encrypted
-> - `decypted`: data is stored decrypted
+> - `clear`: _data_ and _key_ are both 0 (initial state)
+> - `ready`: secret _key_ is set
+> - `encrypted`: _data_ is filled with ciphertext
+> - `decypted`: _data_ is filled with decrypted data
> The state transitions will follow this diagram:
@@ -115,6 +116,6 @@ Adopting our agile mindset, some of these problems revise components introduced
> ```
> clear > loadKey > loadAndEncrypt > decrypt
> ```
-> For example, any time `clear` is seen, flush the contents and go to the `empty` state`. If none of the transition conditions are satisfied, remain in the present state.
+> For example, any time `clear` is seen, flush the contents and go to the `empty` state. If none of the transition conditions are satisfied, remain in the present state.
-> You may use the tester (after filling it in) located in `src/test/scala/hw2/XORCipherTestSuite.scala` to drive your development.
+> We recommend using the tester (after filling it in) located in `src/test/scala/hw2/XORCipherTestSuite.scala` to drive your development.
diff --git a/build.sbt b/build.sbt
index 27d54a7..548a465 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,32 +1,25 @@
-// See README.md for license details.
-
-ThisBuild / scalaVersion := "2.13.7"
+ThisBuild / scalaVersion := "2.13.14"
ThisBuild / version := "0.1.0"
ThisBuild / organization := "UCSC-AHD"
-val chiselVersion = "3.5.0"
-// For running the gradescope tests
-libraryDependencies += "org.scalatestplus" %% "junit-4-13" % "3.2.10.0" % "test"
+val chiselVersion = "3.6.1"
-// This sets it up so all tests that end in "Tester" will be run when you run sbt test
-// and all tests that end in "Grader" will run when you run sbt Grader / test
-lazy val scalatest = "org.scalatest" %% "scalatest" % "3.2.10"
-lazy val Grader = config("grader") extend(Test)
-lazy val TestAll = config("testAll") extend(Test)
-lazy val Hw2 = config("hw2") extend(Test)
-def allFilter(name: String): Boolean = name endsWith "Tester"
-def graderFilter(name: String): Boolean = name endsWith "Grader"
-def hw2Filter(name: String): Boolean = name endsWith "Testerhw2"
+// The following sets it up such that when you run sbt ...
+// Grader / test you run all tests that end in "Grader"
+// test you run all tests that don't end in "Grader"
+lazy val Grader = config("grader") extend(Test)
+def endsWithGrader(name: String): Boolean = name endsWith "Grader"
+lazy val scalatest = "org.scalatest" %% "scalatest" % "3.2.15"
lazy val root = (project in file("."))
-.configs(TestAll).configs(Grader).configs(Hw2)
- .settings(
- name := "hw2",
+.configs(Grader)
+ .settings(
+ name := "hw2",
libraryDependencies ++= Seq(
"edu.berkeley.cs" %% "chisel3" % chiselVersion,
- "edu.berkeley.cs" %% "chiseltest" % "0.5.0" % "test"
+ "edu.berkeley.cs" %% "chiseltest" % "0.6.2" % "test"
),
scalacOptions ++= Seq(
"-language:reflectiveCalls",
@@ -35,18 +28,12 @@ lazy val root = (project in file("."))
"-Xcheckinit",
),
addCompilerPlugin("edu.berkeley.cs" % "chisel3-plugin" % chiselVersion cross CrossVersion.full),
- // from dino
- inConfig(Grader)(Defaults.testTasks),
- inConfig(TestAll)(Defaults.testTasks),
- inConfig(Hw2)(Defaults.testTasks),
- libraryDependencies += scalatest % TestAll,
- libraryDependencies += scalatest % Grader,
- libraryDependencies += scalatest % Hw2,
+ // For Gradescope tests
+ libraryDependencies += "org.scalatestplus" %% "junit-4-13" % "3.2.15.0" % "test",
- testOptions in TestAll := Seq(Tests.Filter(allFilter)),
- // CHANGE THE LINE BELOW FOR EACH LAB!!!! Use the matching filter
- testOptions in Test := Seq(Tests.Filter(allFilter)),
- testOptions in Grader := Seq(Tests.Filter(graderFilter)),
- testOptions in Hw2 := Seq(Tests.Filter(hw2Filter)),
+ inConfig(Grader)(Defaults.testTasks),
+ libraryDependencies += scalatest % Grader,
+ Grader / testOptions := Seq(Tests.Filter(endsWithGrader)),
+ Test / testOptions := Seq(Tests.Filter(!endsWithGrader(_))),
)
diff --git a/fsm.svg b/fsm.svg
index 699f1a9..e7b56af 100644
--- a/fsm.svg
+++ b/fsm.svg
@@ -1,40 +1,40 @@
-