Skip to content
This repository was archived by the owner on Aug 21, 2023. It is now read-only.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.out
*.vcd
170 changes: 11 additions & 159 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,116 +1,27 @@
# CompArch HW b0100: Register File #

**Due:** Monday, October 16
### Jonah Spear

This homework is intended to introduce behavioral Verilog and practice test bench design. You will create your first memory, a register file, which will be reused in your CPU design.

Homework is to be completed individually. If you seek help from another individual, note that per deliverable.


## The Register File ##
The register file is an extremely small, extremely fast memory at the heart of your CPU. They vary per architecture, but you will create one with the following specifications:

- Width: 32 bits
- Depth: 32 words
- Write Port: Synchronous, Positive Edge Triggered
- Read Port 1: Asynchronous
- Read Port 2: Asynchronous
The purpose of this assignment is to build a 32 bit register in verilog. A 32 bit register is a type of memory that can hold 32 values of 32 bits each. The overall design of the register is as follows:

We are mimicking the MIPS architecture, which has one unusual feature in its register file: The first "register" is actually just the constant value zero. We will exploit this oddity later when we write assembly programs for the processor.

The overall structure of the register file is shown below. The core is the 32-bit registers: 31 normal registers and a constant zero. The read ports are a pair of giant multiplexers connected to the register outputs. The write port connects to the input of all registers, and a decoder optionally enables one register to be written. This homework will build these units incrementally in behavioral Verilog (wrapped in structural shells), and then assemble them to create the full register file.

<img src="https://e38023e2-a-62cb3a1a-s-sites.googlegroups.com/site/ca15fall/resources/regfile.png?attachauth=ANoY7coxaffMnfwuftWJOBUSY8OdyOcpfSRp2MJMGS76O8AVIidsNCLx2synldoGKALHHXlA4n5YorYntr0jQ-oBuUX0N1rVOQOnK8ZmJ25513iH3ek-2tkEb28NN1C9iUZRQVvt4zpwB1txBKiNLXSDQ8Rb2GYo5VZNyvINrXv4SBmqHK5VPNngT5WzEyJapUDCQPcL86zR-MMyb1fKthgwZ8Q-6Y8JUg%3D%3D&attredirects=0" alt="Register File diagram">

## Register ##

It is critically important to write registers in Behavioral Verilog so that the synthesizer can figure out what to do.
Here is the behavioral description of a D Flip Flop with enable, positive edge triggered:

```verilog
module register
(
output reg q,
input d,
input wrenable,
input clk
);
always @(posedge clk) begin
if(wrenable) begin
q = d;
end
end
endmodule
```

Note the enable logic. It may feel more natural to instead “gate the clock” like this:

```verilog
// Gated clock - avoid this style
always @(posedge (clk & wrenable)) begin
q = d;
end
```

Theoretically this would work – the clock signal would be steady `FALSE` when disabled, and only have positive edges when enabled. However, "gating the clock" is a bad idea in practice – what happens if that enable signal has glitches? Additionally, FPGAs are typically designed to only support a few distinct clocks.

### Deliverable 1 ###
Draw a circuit diagram showing the structural equivalent for each of the two register implementations above. You may use primitives such as the D Flip-Flop, MUX, decoder, and basic logic gates.

### Deliverable 2 ###
Create a module named `register32`. This module should exactly match the `register` definition above, but with 32 bits worth of D Flip Flops (`d` and `q` ports should increase width accordingly). If you’d like, try parameterizing this width.

### Deliverable 3 ###

Create a module named `register32zero`. This module should match the port definition above, but instead of storing data it should ignore its inputs and always output zero.


## Behavioral Muxes ##

Behavioral Verilog makes it very easy to create a multiplexer through its array syntax. This array syntax is very similar to that of the procedural languages (e.g. MATLAB, Python, C, Java, etc) you may already be familiar with:

```verilog
wire[31:0] inputsofmux;
wire outputofmux;
assign outputofmux=inputsofmux[address];
```

### Deliverable 4 ###
Create a 32:1 multiplexer with the following module definition:

```verilog
module mux32to1by1
(
output out,
input[4:0] address,
input[31:0] inputs
);
// Your code
endmodule
```

### Deliverable 5 ###
Circuit diagram for two register implementations:
<img src="https://github.com/Joboman555/HW4/blob/master/RegComparison.jpg" alt="Register File diagram">

Create a multiplexer that is 32 bits wide and 32 inputs deep. There are many syntaxes available to do so, and each of them have their own little bit of excitement. The version below has more typing involved than other options, but it will allow better flexibility later. Match the following module port definition:
### Deliverables 2-5 ###

```verilog
module mux32to1by32
(
output[31:0] out,
input[4:0] address,
input[31:0] input0, input1, input2, ..., input31
);
See containing files.

wire[31:0] mux[31:0]; // Create a 2D array of wires
assign mux[0] = input0; // Connect the sources of the array
// Repeat 31 times...
assign out = mux[address]; // Connect the output of the array
endmodule
```

## Decoder ##
### Deliverable 6 ###

The decoder selects which register of the register file is being written to. Here is the full definition:
Given the following definition for a decoder, describe how this decoder works.

```verilog
module decoder1to32
Expand All @@ -123,68 +34,9 @@ input[4:0] address
endmodule
```

### Deliverable 6 ###

Provide a brief written description of how the above module works. How does this behavioral Verilog result in a decoder?

## Stitch it all together ##

You now have all the components necessary to create your register file. Use the following module definition and structure to create your register file:

```verilog
module regfile
(
output[31:0] ReadData1, // Contents of first register read
output[31:0] ReadData2, // Contents of second register read
input[31:0] WriteData, // Contents to write to register
input[4:0] ReadRegister1, // Address of first register to read
input[4:0] ReadRegister2, // Address of second register to read
input[4:0] WriteRegister, // Address of register to write
input RegWrite, // Enable writing of register when High
input Clk // Clock (Positive Edge Triggered)
);
```

### Deliverable 7 ###
Submit Verilog files that containing your register file and all supporting modules. Note that Deliverable 8 will help you with this.

### Deliverable 8 ###
Expand the provided test bench to catch register files with the following error types:

1. A fully perfect register file. Return True when this is detected, false for all others.
1. Write Enable is broken / ignored – Register is always written to.
1. Decoder is broken – All registers are written to.
1. Register Zero is actually a register instead of the constant value zero.
1. Port 2 is broken and always reads register 14 (for example).

These will be graded by instantiating intentionally broken register files with your tester. Your tester must return true (works!) or false (broken!) as appropriate.

It is to your advantage to test more than just these cases to better ensure that your good register file is actually good.

## Submission ##

Push your work to GitHub and submit a pull request to the course repo. You should include:
- Verilog: top-level `regfile.v` and any supporting files
- Test benches: `regfile.t.v` and any other testing files
- Scripts to run your tests
- "Report" with writing/drawing for deliverables 1 and 6
This shifts either 1 or 0 to the left by n bits, effectively setting the nth bit high.

You can choose how to organize your Verilog modules (e.g. one module per file matching filename, all sizes of decoder grouped in `decoders.v`, something else) and testbenches, but the top-level of each must be named `regfile.v` and `regfile.t.v` as specified.

## Rubric ##
Code portions of this assignment will be checked automatically by scripts. It is therefore critical to follow the module definitions exactly – same port definitions, same names.

| Deliverable | Weight | Grading |
|-------------|--------|---------|
| 1 | 10 | Manual |
| 2 | 5 | Automatic |
| 3 | 5 | Automatic |
| 4 | 10 | Automatic |
| 5 | 10 | Automatic |
| 6 | 10 | Manual |
| 7 | 25 | Automatic |
| 8 | 25 | Automatic |
| Total | 100 | |
## Submission ##

## Notes ##
We are not doing any time delay related analysis for this assignment. Please do not include time delays.
All tests are contained in regfile.t.v
Binary file added RegComparison.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions mux32to1by32.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
module mux32to1by32
(
output[31:0] out,
input[4:0] address,
input[31:0] input0, input1, input2, input3,
input[31:0] input4, input5, input6, input7,
input[31:0] input8, input9, input10, input11,
input[31:0] input12, input13, input14, input15,
input[31:0] input16, input17, input18, input19,
input[31:0] input20, input21, input22, input23,
input[31:0] input24, input25, input26, input27,
input[31:0] input28, input29, input30, input31
);
wire [31:0] mux[31:0];
assign mux[0] = input0;
assign mux[1] = input1;
assign mux[2] = input2;
assign mux[3] = input3;
assign mux[4] = input4;
assign mux[5] = input5;
assign mux[6] = input6;
assign mux[7] = input7;
assign mux[8] = input8;
assign mux[9] = input9;
assign mux[10] = input10;
assign mux[11] = input11;
assign mux[12] = input12;
assign mux[13] = input13;
assign mux[14] = input14;
assign mux[15] = input15;
assign mux[16] = input16;
assign mux[17] = input17;
assign mux[18] = input18;
assign mux[19] = input19;
assign mux[20] = input20;
assign mux[21] = input21;
assign mux[22] = input22;
assign mux[23] = input23;
assign mux[24] = input24;
assign mux[25] = input25;
assign mux[26] = input26;
assign mux[27] = input27;
assign mux[28] = input28;
assign mux[29] = input29;
assign mux[30] = input30;
assign mux[31] = input31;

assign out = mux[address];
endmodule
Loading