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.
Let's enhance your
ComplexALU
from HW1 by usingBundle
s and encapsulation. This problem will consist of multiple parts that build from each other.
Implement the
ComplexNum
bundle insrc/main/scala/hw2/Complex.scala
by adding twoSInt
fields:real
andimag
and four methods with the following signatures:def sumReal(that: ComplexNum): SInt def sumImag(that: ComplexNum): SInt def diffReal(that: ComplexNum): SInt def diffImag(that: ComplexNum): SIntThe goal of these methods is to effectively overload the
+
and-
operators so we can easily work withComplexNum
in future modules while hiding implementation details. Make sure the arithmetic methods allow for bit width growth.
Implement the
ComplexALUIO
bundle insrc/main/scala/hw2/Complex.scala
by adding threeInput
fields:doAdd: Option[Bool] c0: ComplexNum c1: ComplexNumand one
Output
field:out: ComplexNumEnsure the width of
out
allows for bit width growth. For help with optional IO see the cookbook.
Implement the
ComplexALU
module insrc/main/scala/hw2/Complex.scala
using only the methods defined inComplexNum
to perform arithmetic. It will behave similarly to HW1, except that if theonlyAdder
parameter is true, the generated hardware will not even include a port fordoAdd
.
- if
doAdd
is high, sum the real inputs and sum 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 needdoAdd
, it should be absent from the Verilog.
Let's enhance your
PolyEval
from HW1 to support arbitrary polynomials. Implement thePolyEval
module insrc/main/scala/hw2/PolyEval.scala
. Thecoefs
parameter is a list of coefficients ordered by ascending exponent powers. The generated hardware should produce the result combinatorally (within a cycle).For example:
coefs = Seq(4, 5, 6) x = 2 out = 4*x^0 + 5*x^1 + 6*x^2 = 4 + 10 + 24 = 38
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 atperiod
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 provideSineWave
(insrc/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.
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
andstride
). Each cycle the module will output the next sample ifen
is high, or keep returning the same sample ifen
is low. Thestride
input determines how many samples to step through the ROM each cycle. Note, thatstride
may not evenly divide the period.
Implement the
SineWaveGenIO
bundle insrc/main/scala/hw2/SineWaveGen.scala
by adding twoInput
fields:stride: UInt en: Booland one
Output
field:out: SInt
Implement the
SineWaveGen
module insrc/main/scala/hw2/SineWaveGen.scala
, using aSineWaveGenIO
as the module's IO.Example given these parameters:
val period = 16 val amplitude = 128If
stride
is1
thenSineWaveGen
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
is2
thenSineWaveGen
will return one value each cycle in this order:0, 90, 128, 90, 0, -90, -128, -90
An XOR cipher is a simple cryptographic encryption technique based on the XOR operation. Given a secret
key
anddata
of the same length, we can encryptdata
by performingciphertext = data ^ key
. We can decryptciphertext
by performingdata = ciphertext ^ key
.
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 keyloadKey
: storein
into the secret keyloadAndEnc
: storein
encrypted (via XOR with the secret key) into datadecrypt
: decrypt data with the secretkey
Implement the
XORCipherIO
bundle insrc/main/scala/hw2/XORCipher.scala
by adding twoInput
fields:in: UInt cmds: XORCipherCmds
and four
Output
fields:out: UInt (output of data register) full: Bool (data register has valid data) encrypted: Bool (data register has encrypted data) state: CipherState (eases testing of FSM)
Implement the
XORCipher
module insrc/main/scala/hw2/XORCipher.scala
usingXORCipherIO
as the IO. We will build a FSM with four states:
clear
: data and key are both 0 (initial state)ready
: secret key is setencrypted
: data is filled with ciphertextdecypted
: data is filled with decrypted data
The state transitions will follow this diagram:
In general, at most one signal in XORCipherCmds should be high at a time, but use the following precedence order when multiple are high:
clear > loadKey > loadAndEncrypt > decrypt
For example, any time
clear
is seen, flush the contents and go to theempty
state. If none of the transition conditions are satisfied, remain in the present state.
We recommend using the tester (after filling it in) located in
src/test/scala/hw2/XORCipherTestSuite.scala
to drive your development.