From 407d36452f8d3e988d72835f802fdb345b03b0c8 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Tue, 28 Nov 2017 10:56:37 -0500 Subject: [PATCH 01/98] Create ProjectProposal.md --- ProjectProposal.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 ProjectProposal.md diff --git a/ProjectProposal.md b/ProjectProposal.md new file mode 100644 index 0000000..4161326 --- /dev/null +++ b/ProjectProposal.md @@ -0,0 +1,36 @@ +# GPU Matrix Operations +### Ariana Olson, Rocco DiVerdi, Serena Chen + +We want to study GPU architectures, and build a simple one to do matrix operations. We want to understand the strategy for multiplying matrices in the GPU, and how the GPU is programmed to perform these operations. We will also build a small toy matrix multiplier module in verilog, which can be scaled in scope depending on how much time the previous parts of the project take. + +## References: + +[Understanding the Efficiency of GPU Algorithms for Matrix-Matrix Multiplication](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.1.6823&rep=rep1&type=pdf) + +[Matrix computations on the GPU](https://developer.nvidia.com/sites/default/files/akamai/cuda/files/Misc/mygpu.pdf) + +[Matrix Multiplication with CUDA — A basic introduction to the CUDA programming model](https://www.shodor.org/media/content/petascale/materials/UPModules/matrixMultiplication/moduleDocument.pdf) + +[some random project from somewhere making a GPU](https://courses.cs.washington.edu/courses/cse467/15wi/docs/prj1.pdf) + +## MVP: + +Present to class about how GPUs perform matrix multiplication and other operations. And how it compares to MIPS CPU. + +Planned: Build a toy processor that performs operations and prints results to the terminal. + +Stretch: Visualize real time matrix transformations for a small set of “pixels” + +Super Stretch: be hired by Nvidia + +Even more super stretch: start a GPU company and make Nvidia obsolete + +## Work Plan: + +Thanksgiving break: sleep + +11/27-12/3: Learn about matrix multiplication on GPUs, run some example programs on actual GPUs. Set up documentation framework. Start writing up explanations of what we have learned. + +12/4-12/10: Start implementing verilog modules. Create documentation on performance, how to run tests/examples, block diagrams, etc. + +12/10-12/14: Debugging, polishing, documenting. (try not to be dead) From d9790b08b01838ee9ed1380e375fa2c54c35a793 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Thu, 30 Nov 2017 14:00:31 -0500 Subject: [PATCH 02/98] dot product whoooo --- arithmetic.t.v | 19 +++++++++++++++++++ arithmetic.v | 9 +++++++++ dot.v | 11 +++++++++++ 3 files changed, 39 insertions(+) create mode 100644 arithmetic.t.v create mode 100644 arithmetic.v create mode 100644 dot.v diff --git a/arithmetic.t.v b/arithmetic.t.v new file mode 100644 index 0000000..79762bf --- /dev/null +++ b/arithmetic.t.v @@ -0,0 +1,19 @@ +`include "arithmetic.v" + +module testMult(); + +reg[4:0] a, b; +wire[4:0] out; + +multiplication dut (a, b, out); + +initial begin +a = 4'd4; +b = 4'd6; +#10 + +$display("%d",out); + +end + +endmodule // testMult \ No newline at end of file diff --git a/arithmetic.v b/arithmetic.v new file mode 100644 index 0000000..86aa45f --- /dev/null +++ b/arithmetic.v @@ -0,0 +1,9 @@ + +module multiplication ( + input [4:0] a, b, + output [4:0] result +); + +assign result = a*b; + +endmodule // multiplication diff --git a/dot.v b/dot.v new file mode 100644 index 0000000..30d311f --- /dev/null +++ b/dot.v @@ -0,0 +1,11 @@ +`include "arithmetic.v" + +module dot ( + + input[4:0] a0, a1, a2, b0, b1, b2, + output[8:0] product +); + +assign product = (a0*b0) + (a1*b1) + (a2*b2); + +endmodule \ No newline at end of file From a7465c3d15ebe780fd2323a0f822bbe6bccc70e1 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:09:27 -0500 Subject: [PATCH 03/98] Ignore auto-generated files (ie gtkwave and compiled verilog) --- .gitignore | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7bc0784 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +# Ignore compiled binaries +* +!/**/ +!*.* +!makefile +*.out + +# Ignore gtkwave files +*.vcd + +# Ignore temporary memory file +mem.dat \ No newline at end of file From fe1c0d5b2441d21daf943555fae05d70ffd7b1e3 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:10:09 -0500 Subject: [PATCH 04/98] Create makefile for compiling verilog --- makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 makefile diff --git a/makefile b/makefile new file mode 100644 index 0000000..c57c530 --- /dev/null +++ b/makefile @@ -0,0 +1,10 @@ +all: arithmetic dot matrixmultiplication + +arithmetic: arithmetic.v arithmetic.t.v + iverilog -Wall -o aritmetic arithmetic.t.v + +dot: dot.v dot.t.v arithmetic + iverilog -Wall -o dot dot.t.v + +matrixmultiplication: matrixmultiplication.v matrixmultiplication.t.v dot + iverilog -Wall -o matmul matrixmultiplication.t.v \ No newline at end of file From 32560ed5b2ceceb61e5ec2289ceedcbfeedf12fc Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:11:11 -0500 Subject: [PATCH 05/98] Add testbench --- dot.t.v | 64 ++++++++++++++++++++++++++++++++++++++++ matrixmultiplication.t.v | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 dot.t.v create mode 100644 matrixmultiplication.t.v diff --git a/dot.t.v b/dot.t.v new file mode 100644 index 0000000..491a791 --- /dev/null +++ b/dot.t.v @@ -0,0 +1,64 @@ +"""Test bench for the 3 dimensional vector dot product.""" + +`include "dot.v" + +module dot_TEST(); + + parameter ENTRY_SIZE = 5; + parameter RESENTRY_SIZE = 9; + + reg[ENTRY_SIZE - 1:0] a0, a1, a2, b0, b1, b2; + wire[RESENTRY_SIZE - 1:0] product; + + dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) dut (a0, a1, a2, b0, b1, b2, product); + initial begin + a0 = 5'd0; a1 = 5'd0; a2 = 5'd0; b0 = 5'd0; b1 = 5'd0; b2 = 5'd0; + #50 + if (product !== 9'd0) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd0, product); + end + + a0 = 5'd1; a1 = 5'd0; a2 = 5'd0; b0 = 5'd2; b1 = 5'd3; b2 = 5'd4; + #50 + if (product !== 9'd2) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd2, product); + end + + a0 = 5'd0; a1 = 5'd1; a2 = 5'd0; b0 = 5'd2; b1 = 5'd3; b2 = 5'd4; + #50 + if (product !== 9'd3) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd3, product); + end + + a0 = 5'd0; a1 = 5'd0; a2 = 5'd1; b0 = 5'd2; b1 = 5'd3; b2 = 5'd4; + #50 + if (product !== 9'd4) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd4, product); + end + + a0 = 5'd1; a1 = 5'd1; a2 = 5'd0; b0 = 5'd2; b1 = 5'd3; b2 = 5'd4; + #50 + if (product !== 9'd5) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd5, product); + end + + a0 = 5'd1; a1 = 5'd0; a2 = 5'd1; b0 = 5'd2; b1 = 5'd3; b2 = 5'd4; + #50 + if (product !== 9'd6) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd6, product); + end + + a0 = 5'd0; a1 = 5'd1; a2 = 5'd1; b0 = 5'd2; b1 = 5'd3; b2 = 5'd4; + #50 + if (product !== 9'd7) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd7, product); + end + + a0 = 5'd1; a1 = 5'd1; a2 = 5'd1; b0 = 5'd2; b1 = 5'd3; b2 = 5'd4; + #50 + if (product !== 9'd9) begin + $display("Test failed. Expected: %d. Actual: %d.", 9'd9, product); + end + end +endmodule // dot_TEST + diff --git a/matrixmultiplication.t.v b/matrixmultiplication.t.v new file mode 100644 index 0000000..f63536f --- /dev/null +++ b/matrixmultiplication.t.v @@ -0,0 +1,56 @@ +"""Test bench for the 3x3 matrix multiplication module.""" + +`include "matrixmultiplication.v" + +module matrixmultiplication3by3_TEST(); + parameter ENTRY_SIZE = 5; + parameter RESENTRY_SIZE = 9; + parameter VECTOR_SIZE = 3 * ENTRY_SIZE; + parameter RESVECTOR_SIZE = 3 * RESENTRY_SIZE; + + reg[VECTOR_SIZE - 1:0] matrixAv1, matrixAv2, matrixAv3; + reg[VECTOR_SIZE - 1:0] matrixBv1, matrixBv2, matrixBv3; + + wire[RESVECTOR_SIZE - 1:0] matrixCv1, matrixCv2, matrixCv3; + + matrixmultiplication3by3 #( + .ENTRY_SIZE(ENTRY_SIZE), + .RESENTRY_SIZE(RESENTRY_SIZE) + ) dut ( + .matrixAv1(matrixAv1), .matrixAv2(matrixAv2), .matrixAv3(matrixAv3), + .matrixBv1(matrixBv1), .matrixBv2(matrixBv2), .matrixBv3(matrixBv3), + .matrixCv1(matrixCv1), .matrixCv2(matrixCv2), .matrixCv3(matrixCv3) + ); + + initial begin + $dumpfile("matmul.vcd"); + $dumpvars(); + + // Multiply by zero matrix. + matrixAv1 = {{5'd0}, {5'd0}, {5'd0}}; matrixAv2 = {{5'd0}, {5'd0}, {5'd0}}; matrixAv3 = {{5'd0}, {5'd0}, {5'd0}}; + matrixBv1 = {{5'd0}, {5'd0}, {5'd0}}; matrixBv2 = {{5'd0}, {5'd0}, {5'd0}}; matrixBv3 = {{5'd0}, {5'd2}, {5'd1}}; + #50 + if (matrixCv1 !== 27'b0 || matrixCv2 !== 27'b0 || matrixCv3 !== 27'b0) begin + $display("Test failed. Expected 0 matrix, received: \n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d", + matrixCv1[26:18], matrixCv1[17:9], matrixCv1[8:0], + matrixCv2[26:18], matrixCv2[17:9], matrixCv2[8:0], + matrixCv3[26:18], matrixCv3[17:9], matrixCv3[8:0]); + end + + // Multiply by identity matrix. + matrixAv1 = {{5'd1}, {5'd0}, {5'd0}}; matrixAv2 = {{5'd0}, {5'd1}, {5'd0}}; matrixAv3 = {{5'd0}, {5'd0}, {5'd1}}; + matrixBv1 = {{5'd1}, {5'd2}, {5'd3}}; matrixBv2 = {{5'd2}, {5'd3}, {5'd1}}; matrixBv3 = {{5'd3}, {5'd1}, {5'd2}}; + #50 + if (matrixCv1 !== {{9'd1}, {9'd2}, {9'd3}} || matrixCv2 !== {{9'd2}, {9'd3}, {9'd1}} || matrixCv3 !== {{9'd3}, {9'd1}, {9'd2}}) begin + $display("Test failed. Expected: \n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d\n Actual: \n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d", + 9'd1, 9'd2, 9'd3, + 9'd2, 9'd3, 9'd1, + 9'd3, 9'd1, 9'd2, + matrixCv1[26:18], matrixCv1[17:9], matrixCv1[8:0], + matrixCv2[26:18], matrixCv2[17:9], matrixCv2[8:0], + matrixCv3[26:18], matrixCv3[17:9], matrixCv3[8:0]); + end + + $finish(); + end +endmodule \ No newline at end of file From 2e9e01fbfb45df064dbbf7d7289d4dacf579a979 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:11:43 -0500 Subject: [PATCH 06/98] Create core multiplication module --- matrixmultiplication.v | 128 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 matrixmultiplication.v diff --git a/matrixmultiplication.v b/matrixmultiplication.v new file mode 100644 index 0000000..57871f8 --- /dev/null +++ b/matrixmultiplication.v @@ -0,0 +1,128 @@ +""" +Multiply two square 3x3 matrices. +Represents the operation A * B = C +Inputs: + - matrixAv1, ..., v3 and matrixBv1, ..., v3 represent the rows of A and B. +Outputs: + - matrixCv1, ..., v3 repreents the rows of C. +Parameters: + - ENTRY_SIZE is the size of each individual entry of A and B. + - RESENTRY_SIZE is the size of each individual entry in the result C. + - VECTOR_SIZE is the size of each row vector in A and B. + - RESVECTOR_SIZE is the size of each row vector in the result C. +""" + +`include "dot.v" + +module matrixmultiplication3by3 +#( + parameter ENTRY_SIZE = 5, + parameter RESENTRY_SIZE = 9, + parameter VECTOR_SIZE = 3 * ENTRY_SIZE, + parameter RESVECTOR_SIZE = 3 * RESENTRY_SIZE +) +( + input[VECTOR_SIZE - 1: 0] matrixAv1, matrixAv2, matrixAv3, + input[VECTOR_SIZE - 1: 0] matrixBv1, matrixBv2, matrixBv3, + output [RESVECTOR_SIZE - 1: 0] matrixCv1, matrixCv2, matrixCv3 +); + +wire[RESENTRY_SIZE - 1:0] c11, c12, c13; +wire[RESENTRY_SIZE - 1:0] c21, c22, c23; +wire[RESENTRY_SIZE - 1:0] c31, c32, c33; + +// Row 1 Column 1 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r1c1 ( + .a0(matrixAv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c11)); + +// Row 1 Column 2 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r1c2 ( + .a0(matrixAv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c12)); + +// Row 1 Column 3 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r1c3 ( + .a0(matrixAv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c13)); + +// Row 2 Column 1 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r2c1 ( + .a0(matrixAv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c21)); + +// Row 2 Column 2 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r2c2 ( + .a0(matrixAv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c22)); + +// Row 2 Column 3 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r2c3 ( + .a0(matrixAv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c23)); + +// Row 3 Column 1 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r3c1 ( + .a0(matrixAv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c31)); + +// Row 3 Column 2 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r3c2 ( + .a0(matrixAv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c32)); + +// Row 3 Column 3 +dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r3c3 ( + .a0(matrixAv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .a1(matrixAv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .a2(matrixAv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b0(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b1(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b2(matrixBv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .product(c33)); + +assign matrixCv1 = {{c11}, {c12}, {c13}}; +assign matrixCv2 = {{c21}, {c22}, {c23}}; +assign matrixCv3 = {{c31}, {c32}, {c33}}; + +endmodule \ No newline at end of file From 3080450b2a61dad78c9550ee2f7dfa99afd6e33c Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:13:57 -0500 Subject: [PATCH 07/98] Parameterize and add header comments --- arithmetic.v | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/arithmetic.v b/arithmetic.v index 86aa45f..67a57a6 100644 --- a/arithmetic.v +++ b/arithmetic.v @@ -1,7 +1,22 @@ - -module multiplication ( - input [4:0] a, b, - output [4:0] result +""" +Performs a scalar multiplication on two numbers. +Represents the operation a * b = c. +Inputs: + - a and b are the two scalars being multiplied +Outputs: + - result is the scalar product. +Parameters: + - ENTRY_SIZE is the size of a and b + - RESENTRY_SIZE is the size of result +""" +module scalar_multiplication +#( + parameter ENTRY_SIZE = 5, + parameter RESENTRY_SIZE = 9 +) +( + input [ENTRY_SIZE - 1:0] a, b, + output [RESENTRY_SIZE - 1:0] result ); assign result = a*b; From 188a2b00739f878aac952b6f23be3d6ff7bafe3b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:14:18 -0500 Subject: [PATCH 08/98] Add test cases --- arithmetic.t.v | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/arithmetic.t.v b/arithmetic.t.v index 79762bf..f5dd636 100644 --- a/arithmetic.t.v +++ b/arithmetic.t.v @@ -1,19 +1,40 @@ +"""Test bench for the scalar multiplication module""" + `include "arithmetic.v" +module scalar_multiplication_TEST(); -module testMult(); +parameter ENTRY_SIZE = 5; +parameter RESENTRY_SIZE = 9; -reg[4:0] a, b; -wire[4:0] out; +reg[ENTRY_SIZE - 1:0] a, b; +wire[RESENTRY_SIZE - 1:0] out; -multiplication dut (a, b, out); +scalar_multiplication #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) dut (a, b, out); initial begin -a = 4'd4; -b = 4'd6; -#10 + // Multiply by 0 + a = 5'd0; b = 5'd0; #50 + if (out !== 9'd0) begin + $display("Test failed. Expected output: %b. Actual output: %b", 9'd0, out); + end -$display("%d",out); + // Multiply by 1 + a = 5'd1; b = 5'd15; #50 + if (out !== 9'd15) begin + $display("Test failed. Expected output: %b. Actual output: %b", 9'd15, out); + end -end + // Multiply two numbers that do not overflow the result size + a = 5'd25; b = 5'd20; #50 + if (out !== 9'd500) begin + $display("Test failed. Expected output: %b. Actual output: %b", 9'd500, out); + end + // Multiply two numbers that overflow the result size + // Expect the most significant bits to be truncated + a = 5'd31; b = 5'd25; #50 + if (out !== 9'd263) begin + $display("Test failed. Expected output: %b. Actual output: %b", 9'd263, out); + end +end endmodule // testMult \ No newline at end of file From 306e9ce9908883ab6039a146273752a5b33d369d Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:14:40 -0500 Subject: [PATCH 09/98] Parameterize and add header comments --- dot.v | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/dot.v b/dot.v index 30d311f..11fdefa 100644 --- a/dot.v +++ b/dot.v @@ -1,11 +1,35 @@ -`include "arithmetic.v" +""" +Perform the dot product on two 3 dimensional vectors. +Represents the operation dot(a, b) = c +Inputs: + - a0, ..., a2 and b0, ..., b2 represent the entries of the vectors a and b. +Outputs: + - product represents the scalar c. +Parameters: + - ENTRY_SIZE is the size of each individual entry of a and b. + - RESENTRY_SIZE is the size of the product c. +""" -module dot ( +`include "arithmetic.v" - input[4:0] a0, a1, a2, b0, b1, b2, - output[8:0] product +module dot +#( + parameter ENTRY_SIZE = 5, + parameter RESENTRY_SIZE = 9 +) +( + input[ENTRY_SIZE - 1:0] a0, a1, a2, b0, b1, b2, + output[RESENTRY_SIZE - 1:0] product ); -assign product = (a0*b0) + (a1*b1) + (a2*b2); +wire[RESENTRY_SIZE - 1:0] multres0; +wire[RESENTRY_SIZE - 1:0] multres1; +wire[RESENTRY_SIZE - 1:0] multres2; + +scalar_multiplication #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) multop0 (.a(a0), .b(b0), .result(multres0)); +scalar_multiplication #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) multop1 (.a(a1), .b(b1), .result(multres1)); +scalar_multiplication #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) multop2 (.a(a2), .b(b2), .result(multres2)); + +assign product = multres0 + multres1 + multres2; endmodule \ No newline at end of file From 58aa6fcc5b28052d6f7e7f60b77c5f3629a74a6b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 20:47:22 -0500 Subject: [PATCH 10/98] Add script for running test benches --- run_tests.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100755 run_tests.sh diff --git a/run_tests.sh b/run_tests.sh new file mode 100755 index 0000000..3bcb921 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +make + +echo "Running all module tests:" + +echo "Running arithmetic tests..." +./arithmetic +echo "Running dot tests..." +./dot +echo "Running matmul tests..." +./matmul \ No newline at end of file From e18f8987c4a10d7916ccd6986cf7a78027806211 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 21:14:21 -0500 Subject: [PATCH 11/98] Add description of how to run tests and use makefile --- testing.md | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 testing.md diff --git a/testing.md b/testing.md new file mode 100644 index 0000000..04c941f --- /dev/null +++ b/testing.md @@ -0,0 +1,59 @@ +# How to Run Tests +## Getting Started +Before being able to run tests, you must compile the verilog files. +To do this, at the command line enter the command `make` This will +compile any of the necessary verilog files to create the test executables. If a file has already been compiled and no changes have been made to it or its dependencies, the file will not be recompiled. + +## Run Single Test +Enter the command +```bash +./ +``` + +To run a single file once it has been compiled. If all unit tests pass, nothing will be printed to the terminal. A notice that one or more tests failed will be printed to the terminal otherwise. + +## Run All Tests +The script `run_tests.sh` will compile and run all of the tests at once + +If you are running the script for the first time, you will need to type +```bash +chmod 755 run_tests.sh +``` +In order to gain permission to run the script. + +Once you have gained permission run: +```bash +./run_tests.sh +``` + +If all tests pass, the only output to the terminal from the script will be any commands run from the makefile and any notifications about .vcd files being opened for output. Otherwise, notice that one or more tests failed will be printed to the terminal. + +## Add a Test to Run +If a new testbench binary is created, it must be added to the script in order to be run. To do this, add the following lines to `run_tests.sh`: +```bash +echo "Running tests..." +./ +``` + +# How to Edit the Makefile +## Adding build targets +To add a build target for a new testbench, add the following lines to the makefile: +``` +: ... + iverilog -Wall -o +``` + +As a style choice, the binary name should match the target name. Dependencies can either be other build targets or verilog files. An example build target might look like: + +``` +dot: dot.v dot.t.v arithmetic + iverilog -Wall -o dot dot.t.v +``` + +In addition, the new build target must be added to the all build target at the top of the makefile, otherwise it will not be built automatically. + +``` +all: arithmetic dot matrixmultiplication +``` + + \ No newline at end of file From 1436000c71e5fbf670e821e0f3617dd2881ddb0b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 21:15:13 -0500 Subject: [PATCH 12/98] Fix header comment syntax error --- arithmetic.t.v | 4 +++- arithmetic.v | 4 ++-- dot.t.v | 4 +++- dot.v | 4 ++-- matrixmultiplication.t.v | 4 +++- matrixmultiplication.v | 4 ++-- 6 files changed, 15 insertions(+), 9 deletions(-) diff --git a/arithmetic.t.v b/arithmetic.t.v index f5dd636..9bc805f 100644 --- a/arithmetic.t.v +++ b/arithmetic.t.v @@ -1,4 +1,6 @@ -"""Test bench for the scalar multiplication module""" +/* +Test bench for the scalar multiplication module +*/ `include "arithmetic.v" module scalar_multiplication_TEST(); diff --git a/arithmetic.v b/arithmetic.v index 67a57a6..fd9d04b 100644 --- a/arithmetic.v +++ b/arithmetic.v @@ -1,4 +1,4 @@ -""" +/* Performs a scalar multiplication on two numbers. Represents the operation a * b = c. Inputs: @@ -8,7 +8,7 @@ Outputs: Parameters: - ENTRY_SIZE is the size of a and b - RESENTRY_SIZE is the size of result -""" +*/ module scalar_multiplication #( parameter ENTRY_SIZE = 5, diff --git a/dot.t.v b/dot.t.v index 491a791..516b69b 100644 --- a/dot.t.v +++ b/dot.t.v @@ -1,4 +1,6 @@ -"""Test bench for the 3 dimensional vector dot product.""" +/* +Test bench for the 3 dimensional vector dot product. +*/ `include "dot.v" diff --git a/dot.v b/dot.v index 11fdefa..e4832d3 100644 --- a/dot.v +++ b/dot.v @@ -1,4 +1,4 @@ -""" +/* Perform the dot product on two 3 dimensional vectors. Represents the operation dot(a, b) = c Inputs: @@ -8,7 +8,7 @@ Outputs: Parameters: - ENTRY_SIZE is the size of each individual entry of a and b. - RESENTRY_SIZE is the size of the product c. -""" +*/ `include "arithmetic.v" diff --git a/matrixmultiplication.t.v b/matrixmultiplication.t.v index f63536f..bb06918 100644 --- a/matrixmultiplication.t.v +++ b/matrixmultiplication.t.v @@ -1,4 +1,6 @@ -"""Test bench for the 3x3 matrix multiplication module.""" +/* +Test bench for the 3x3 matrix multiplication module. +*/ `include "matrixmultiplication.v" diff --git a/matrixmultiplication.v b/matrixmultiplication.v index 57871f8..ae3d056 100644 --- a/matrixmultiplication.v +++ b/matrixmultiplication.v @@ -1,4 +1,4 @@ -""" +/* Multiply two square 3x3 matrices. Represents the operation A * B = C Inputs: @@ -10,7 +10,7 @@ Parameters: - RESENTRY_SIZE is the size of each individual entry in the result C. - VECTOR_SIZE is the size of each row vector in A and B. - RESVECTOR_SIZE is the size of each row vector in the result C. -""" +*/ `include "dot.v" From 9b350d579f1a7a3e4ba91440b2353426d6f102ba Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Wed, 6 Dec 2017 21:15:42 -0500 Subject: [PATCH 13/98] Fix typo --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index c57c530..611e499 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ all: arithmetic dot matrixmultiplication arithmetic: arithmetic.v arithmetic.t.v - iverilog -Wall -o aritmetic arithmetic.t.v + iverilog -Wall -o arithmetic arithmetic.t.v dot: dot.v dot.t.v arithmetic iverilog -Wall -o dot dot.t.v From 622219dc672a942f1c5bbfc4102fffaf1c66ee33 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Thu, 7 Dec 2017 18:32:17 -0500 Subject: [PATCH 14/98] Fied transpose issue --- matrixmultiplication.t.v | 4 ++-- matrixmultiplication.v | 36 ++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/matrixmultiplication.t.v b/matrixmultiplication.t.v index bb06918..c22838f 100644 --- a/matrixmultiplication.t.v +++ b/matrixmultiplication.t.v @@ -41,9 +41,9 @@ module matrixmultiplication3by3_TEST(); // Multiply by identity matrix. matrixAv1 = {{5'd1}, {5'd0}, {5'd0}}; matrixAv2 = {{5'd0}, {5'd1}, {5'd0}}; matrixAv3 = {{5'd0}, {5'd0}, {5'd1}}; - matrixBv1 = {{5'd1}, {5'd2}, {5'd3}}; matrixBv2 = {{5'd2}, {5'd3}, {5'd1}}; matrixBv3 = {{5'd3}, {5'd1}, {5'd2}}; + matrixBv1 = {{5'd1}, {5'd2}, {5'd3}}; matrixBv2 = {{5'd2}, {5'd3}, {5'd5}}; matrixBv3 = {{5'd3}, {5'd1}, {5'd2}}; #50 - if (matrixCv1 !== {{9'd1}, {9'd2}, {9'd3}} || matrixCv2 !== {{9'd2}, {9'd3}, {9'd1}} || matrixCv3 !== {{9'd3}, {9'd1}, {9'd2}}) begin + if (matrixCv1 !== {{9'd1}, {9'd2}, {9'd3}} || matrixCv2 !== {{9'd2}, {9'd3}, {9'd5}} || matrixCv3 !== {{9'd3}, {9'd1}, {9'd2}}) begin $display("Test failed. Expected: \n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d\n Actual: \n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d", 9'd1, 9'd2, 9'd3, 9'd2, 9'd3, 9'd1, diff --git a/matrixmultiplication.v b/matrixmultiplication.v index ae3d056..e33e17a 100644 --- a/matrixmultiplication.v +++ b/matrixmultiplication.v @@ -37,8 +37,8 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r1c1 ( .a1(matrixAv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .b0(matrixBv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), - .b1(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), - .b2(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b1(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b2(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .product(c11)); // Row 1 Column 2 @@ -46,9 +46,9 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r1c2 ( .a0(matrixAv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .a1(matrixAv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), - .b0(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b0(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .b1(matrixBv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), - .b2(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b2(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .product(c12)); // Row 1 Column 3 @@ -56,8 +56,8 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r1c3 ( .a0(matrixAv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .a1(matrixAv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), - .b0(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), - .b1(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b0(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b1(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .b2(matrixBv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .product(c13)); @@ -67,8 +67,8 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r2c1 ( .a1(matrixAv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .b0(matrixBv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), - .b1(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), - .b2(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b1(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b2(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .product(c21)); // Row 2 Column 2 @@ -76,9 +76,9 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r2c2 ( .a0(matrixAv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .a1(matrixAv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), - .b0(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b0(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .b1(matrixBv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), - .b2(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b2(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .product(c22)); // Row 2 Column 3 @@ -86,8 +86,8 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r2c3 ( .a0(matrixAv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .a1(matrixAv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), - .b0(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), - .b1(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b0(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b1(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .b2(matrixBv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .product(c23)); @@ -97,8 +97,8 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r3c1 ( .a1(matrixAv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .b0(matrixBv1[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), - .b1(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), - .b2(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b1(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b2(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .product(c31)); // Row 3 Column 2 @@ -106,9 +106,9 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r3c2 ( .a0(matrixAv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .a1(matrixAv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), - .b0(matrixBv2[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), + .b0(matrixBv1[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .b1(matrixBv2[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), - .b2(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b2(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .product(c32)); // Row 3 Column 3 @@ -116,8 +116,8 @@ dot #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) r3c3 ( .a0(matrixAv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), .a1(matrixAv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), .a2(matrixAv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), - .b0(matrixBv3[VECTOR_SIZE - 1:VECTOR_SIZE - ENTRY_SIZE]), - .b1(matrixBv3[VECTOR_SIZE - ENTRY_SIZE - 1: VECTOR_SIZE - (2 * ENTRY_SIZE)]), + .b0(matrixBv1[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), + .b1(matrixBv2[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .b2(matrixBv3[VECTOR_SIZE - (2 * ENTRY_SIZE) - 1: 0]), .product(c33)); From 029da1140c06b443c75ae77277b865714e8e525a Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Fri, 8 Dec 2017 05:56:02 -1000 Subject: [PATCH 15/98] creating docs folder --- docs/docs/index.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/docs/index.md diff --git a/docs/docs/index.md b/docs/docs/index.md new file mode 100644 index 0000000..f5c8782 --- /dev/null +++ b/docs/docs/index.md @@ -0,0 +1 @@ +# Matrix Multiplication From 86f4c2262765cf180a585e7a43e32fc97025f8fd Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Fri, 8 Dec 2017 06:06:30 -1000 Subject: [PATCH 16/98] Set theme jekyll-theme-midnight --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..1885487 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-midnight \ No newline at end of file From 551b8cdc6824c69747883e88116d9cb59769dfda Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Fri, 8 Dec 2017 12:22:43 -0500 Subject: [PATCH 17/98] Add data memory implementation and tests --- data_memory.t.v | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ data_memory.v | 30 ++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 data_memory.t.v create mode 100644 data_memory.v diff --git a/data_memory.t.v b/data_memory.t.v new file mode 100644 index 0000000..774841c --- /dev/null +++ b/data_memory.t.v @@ -0,0 +1,56 @@ +/* +Test bench for data memory module. +*/ + +`include "data_memory.v" + +module memory_TEST(); + parameter ENTRY_SIZE = 5; + reg clk; + reg [31:0] address; + reg writeEnable; + reg [ENTRY_SIZE - 1:0] dataIn; + + wire [ENTRY_SIZE - 1:0] dataOut; + + memory #(.width(ENTRY_SIZE) dut(clk, dataOut, address, writeEnable, dataIn); + + initial clk = 0; + always #10 clk = !clk; + initial begin + $dumpfile("memory.vcd"); + $dumpvars(0, memory_TEST, dut.memory[0]); + + // Test Case 1: Do not write if writeEnable is low. + writeEnable = 0; dataIn = 5'hffff; address = 5'd0; + #20 + if (dataOut === dataIn) begin + $display("Test case 1 failed: memory was written to when writeEnable was false."); + end + + else if (dataOut === 5'bx) begin + $display("Test case 1 failed: there is no memory at the given address."); + end + + #1000 + // Test case 2: Write to memory if writeEnable is high. + writeEnable = 1; dataIn = 5'hffff; address = 5'd0; + #40 + + if (dataOut === 5'bx) begin + $display("Test case 2 failed: there is no memory at the given address."); + end + + if (dut.memory[0] !== dataIn) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn"); + end + + if (dataOut !== dataIn) begin + $display("Test case 2 failed: memory was not written to when writeEnable was true."); + end + + #1000 + + $finish; + end +endmodule \ No newline at end of file diff --git a/data_memory.v b/data_memory.v new file mode 100644 index 0000000..3be74bb --- /dev/null +++ b/data_memory.v @@ -0,0 +1,30 @@ +/* +The memory where matrices are stored. +*/ + +module memory +#( + parameter addresswidth = 32, + parameter depth = addresswidth * 2, + parameter width = 32 +) +( + input clk, + output [width-1:0] dataOut, + input [addresswidth-1:0] address, + input writeEnable, + input [width-1:0] dataIn +); + + + reg [width-1:0] memory [depth-1:0]; + + always @(negedge clk) begin + if(writeEnable) + memory[address >> 2] <= dataIn; + end + assign dataOut = memory[address >> 2]; + + initial $readmemh("matrix_mem.dat", memory); + +endmodule \ No newline at end of file From a5996a7e8529799be41ed0c8a6b8078314e9246b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Fri, 8 Dec 2017 12:23:33 -0500 Subject: [PATCH 18/98] Create test memory for testbench --- mem_test_data.dat | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 mem_test_data.dat diff --git a/mem_test_data.dat b/mem_test_data.dat new file mode 100644 index 0000000..1bb139f --- /dev/null +++ b/mem_test_data.dat @@ -0,0 +1,65 @@ +// This is the memory that should be used in the data memory test bench +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 \ No newline at end of file From cb61d00f4312c8e6b37d5df84ee1b165a10b05ad Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Fri, 8 Dec 2017 12:23:53 -0500 Subject: [PATCH 19/98] Update to include data memory --- makefile | 7 +++++-- run_tests.sh | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 611e499..eaeb5bf 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -all: arithmetic dot matrixmultiplication +all: arithmetic dot matrixmultiplication data_mem arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -7,4 +7,7 @@ dot: dot.v dot.t.v arithmetic iverilog -Wall -o dot dot.t.v matrixmultiplication: matrixmultiplication.v matrixmultiplication.t.v dot - iverilog -Wall -o matmul matrixmultiplication.t.v \ No newline at end of file + iverilog -Wall -o matmul matrixmultiplication.t.v + +data_mem: data_memory.v data_memory.t.v + iverilog -Wall -o data_mem data_memory.t.v \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh index 3bcb921..90869d5 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -4,6 +4,9 @@ make echo "Running all module tests:" +cat mem_test_data.dat > matrix_mem.dat +echo "Running data memory tests..." +./data_mem echo "Running arithmetic tests..." ./arithmetic echo "Running dot tests..." From 4756e3ba2881d08b9984a3200f4081a3ac81020b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Fri, 8 Dec 2017 12:25:34 -0500 Subject: [PATCH 20/98] Change test matrix to not be symmetric --- matrixmultiplication.t.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrixmultiplication.t.v b/matrixmultiplication.t.v index c22838f..e9d1a44 100644 --- a/matrixmultiplication.t.v +++ b/matrixmultiplication.t.v @@ -46,7 +46,7 @@ module matrixmultiplication3by3_TEST(); if (matrixCv1 !== {{9'd1}, {9'd2}, {9'd3}} || matrixCv2 !== {{9'd2}, {9'd3}, {9'd5}} || matrixCv3 !== {{9'd3}, {9'd1}, {9'd2}}) begin $display("Test failed. Expected: \n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d\n Actual: \n%d\t%d\t%d\n%d\t%d\t%d\n%d\t%d\t%d", 9'd1, 9'd2, 9'd3, - 9'd2, 9'd3, 9'd1, + 9'd2, 9'd3, 9'd5, 9'd3, 9'd1, 9'd2, matrixCv1[26:18], matrixCv1[17:9], matrixCv1[8:0], matrixCv2[26:18], matrixCv2[17:9], matrixCv2[8:0], From 6792931e4370b0c3f53a52c9a462f2a0d7a3c774 Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Fri, 8 Dec 2017 12:32:39 -0500 Subject: [PATCH 21/98] added some words --- docs/index.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/index.md b/docs/index.md index f5c8782..8df8009 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1 +1,17 @@ # Matrix Multiplication + +## Abstract + +For our Computer Architecture final project, we designed computer hardware to multiply two matricies (final constrints here). Matrix multiplication is a complex and time intensive opperation for normal computer architectures becuase there are a large number of individual computations; however, it is used frequently for machine learning and ???. Because each value in the result matrix can be computed independently from any other result, matrix multiplication is an excellent candidate for parallelization. We wanted to explore the potential efficiency gain from using a purpose built matrix multiplier, and see how a computer architecture which splits a work load among a large number of computing units would actually work. + +## Project Motivation and Background + +After studying single cycle MIPS CPUs, we were interested in other computing architectures with different strengths and weakensses. We first looked at GPUs, which were originally designed specifically for graphics, but have recently been generalized to be fully functional CPUs. Graphics opperations are essentially a subset of matrix opperations (where the :With this added functionallity, GPUs have become increasingly usefull for machine learning algorithms and general parallel computing. Mostly, computations on matricies are complex and time intensive on normal CPUs, but the extreme parallelization of computations in a GPU makes it much more efficient at these opperations. We wanted to explore this increase in efficiency by making some purpose built hardware for matrix multiplication. + +## Results + +## Similarities to Graphics + +As we mentioned before, graphics opperations are essentially a subset of matrix opperations. + +## Appendix From 5cc3218ae9191eda89d962782851134fb7ba6fc7 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Fri, 8 Dec 2017 12:36:06 -0500 Subject: [PATCH 22/98] Instantiate module --- load_matrices.v | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 load_matrices.v diff --git a/load_matrices.v b/load_matrices.v new file mode 100644 index 0000000..429e515 --- /dev/null +++ b/load_matrices.v @@ -0,0 +1,3 @@ +module load_matrices(); +// TODO(arianaolson419): Implement! +endmodule \ No newline at end of file From bf59ab0f1426c952aea633f5b66c65cfaf9ae9ba Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Fri, 8 Dec 2017 12:36:31 -0500 Subject: [PATCH 23/98] Add todo --- data_memory.v | 1 + 1 file changed, 1 insertion(+) diff --git a/data_memory.v b/data_memory.v index 3be74bb..babe694 100644 --- a/data_memory.v +++ b/data_memory.v @@ -2,6 +2,7 @@ The memory where matrices are stored. */ +// TODO (arianaolson419): Allow multiple data access in some fashion. module memory #( parameter addresswidth = 32, From eaa9a218489cd418f2d8be6ac5bd650712cf44b2 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Fri, 8 Dec 2017 16:04:16 -0500 Subject: [PATCH 24/98] putting index.md in the right place --- docs/{docs => }/index.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{docs => }/index.md (100%) diff --git a/docs/docs/index.md b/docs/index.md similarity index 100% rename from docs/docs/index.md rename to docs/index.md From b914f63ebd3509f7421ec3dad9f957d4eac93507 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Fri, 8 Dec 2017 19:17:33 -0500 Subject: [PATCH 25/98] reg file done --- registers.t.v | 90 ++++++++++++++++++++++++ registers.v | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 279 insertions(+) create mode 100644 registers.t.v create mode 100644 registers.v diff --git a/registers.t.v b/registers.t.v new file mode 100644 index 0000000..4e2670a --- /dev/null +++ b/registers.t.v @@ -0,0 +1,90 @@ +`include "registers.v" + +module test_registers(); + +reg clk, wrenable; +reg[5:0] n_in, m_in, p_in; +wire[5:0] n_out, m_out, p_out; +reg[4:0] a0_in, a1_in, a2_in, a3_in, a4_in, a5_in, a6_in, a7_in, a8_in; +reg[4:0] b0_in, b1_in, b2_in, b3_in, b4_in, b5_in, b6_in, b7_in, b8_in; +reg[4:0] c0_in, c1_in, c2_in, c3_in, c4_in, c5_in, c6_in, c7_in, c8_in; +wire[4:0] a0_out, a1_out, a2_out, a3_out, a4_out, a5_out, a6_out, a7_out, a8_out; +wire[4:0] b0_out, b1_out, b2_out, b3_out, b4_out, b5_out, b6_out, b7_out, b8_out; +wire[4:0] c0_out, c1_out, c2_out, c3_out, c4_out, c5_out, c6_out, c7_out, c8_out; + +regfile dut (wrenable, n_in, m_in, p_in, + n_out, m_out, p_out, + a0_in, a1_in, a2_in, a3_in, a4_in, a5_in, a6_in, a7_in, a8_in, + b0_in, b1_in, b2_in, b3_in, b4_in, b5_in, b6_in, b7_in, b8_in, + c0_in, c1_in, c2_in, c3_in, c4_in, c5_in, c6_in, c7_in, c8_in, + a0_out, a1_out, a2_out, a3_out, a4_out, a5_out, a6_out, a7_out, a8_out, + b0_out, b1_out, b2_out, b3_out, b4_out, b5_out, b6_out, b7_out, b8_out, + c0_out, c1_out, c2_out, c3_out, c4_out, c5_out, c6_out, c7_out, c8_out, + clk); + +genvar i; +initial begin + +a0_in = 5'd0; +a1_in = 5'd1; +a2_in = 5'd2; +a3_in = 5'd3; +a4_in = 5'd4; +a5_in = 5'd5; +a6_in = 5'd6; +a7_in = 5'd7; +a8_in = 5'd8; +b0_in = 5'd9; +b1_in = 5'd10; +b2_in = 5'd11; +b3_in = 5'd12; +b4_in = 5'd13; +b5_in = 5'd14; +b6_in = 5'd15; +b7_in = 5'd16; +b8_in = 5'd17; +c0_in = 5'd18; +c1_in = 5'd19; +c2_in = 5'd20; +c3_in = 5'd21; +c4_in = 5'd22; +c5_in = 5'd23; +c6_in = 5'd24; +c7_in = 5'd25; +c8_in = 5'd26; +wrenable = 0; + +clk = 0; #5 +clk = 1; #5 +clk = 0; #5 + +if (a0_out !== 5'd0 || a1_out !== 5'd0 || a2_out !== 5'd0 || +a3_out !== 5'd0 || a4_out !== 5'd0 || a5_out !== 5'd0 || a6_out !== 5'd0 || +a7_out !== 5'd0 || a8_out !== 5'd0 || b0_out !== 5'd0 || b1_out !== 5'd0 || +b2_out !== 5'd0 || b3_out !== 5'd0 || b4_out !== 5'd0 || b5_out !== 5'd0 || +b6_out !== 5'd0 || b7_out !== 5'd0 || b8_out !== 5'd0 || c0_out !== 5'd0 || +c1_out !== 5'd0 || c2_out !== 5'd0 || c3_out !== 5'd0 || c4_out !== 5'd0 || +c5_out !== 5'd0 || c6_out !== 5'd0 || c7_out !== 5'd0 || c8_out !== 5'd0) + + $display("wrote to registers when wrenable was 0"); + +wrenable = 1; + +clk = 0; #5 +clk = 1; #5 +clk = 0; #5 + +if (a0_out !== 5'd0 || a1_out !== 5'd1 || a2_out !== 5'd2 || +a3_out !== 5'd3 || a4_out !== 5'd4 || a5_out !== 5'd5 || a6_out !== 5'd6 || +a7_out !== 5'd7 || a8_out !== 5'd8 || b0_out !== 5'd9 || b1_out !== 5'd10 || +b2_out !== 5'd11 || b3_out !== 5'd12 || b4_out !== 5'd13 || b5_out !== 5'd14 || +b6_out !== 5'd15 || b7_out !== 5'd16 || b8_out !== 5'd17 || c0_out !== 5'd18 || +c1_out !== 5'd19 || c2_out !== 5'd20 || c3_out !== 5'd21 || c4_out !== 5'd22 || +c5_out !== 5'd23 || c6_out !== 5'd24 || c7_out !== 5'd25 || c8_out !== 5'd26) + + $display("wrote to registers incorrectly"); + + +end + +endmodule diff --git a/registers.v b/registers.v new file mode 100644 index 0000000..52aa60f --- /dev/null +++ b/registers.v @@ -0,0 +1,189 @@ +module register #(parameter width = 5'd4, parameter init = {width{1'd0}}) +( + + output reg[width-1:0] q, + input[width-1:0] d, + input wrenable, + input clk +); + + initial begin + q={width{1'b0}}+init; + end + + always @(posedge clk) begin + if(wrenable) begin + q = d; + end + end + +endmodule + +module regfile +( + input wrenable, + input[5:0] n_in, m_in, p_in, + output[5:0] n_out, m_out, p_out, + input[4:0] a0_in, a1_in, a2_in, a3_in, a4_in, a5_in, a6_in, a7_in, a8_in, + input[4:0] b0_in, b1_in, b2_in, b3_in, b4_in, b5_in, b6_in, b7_in, b8_in, + input[4:0] c0_in, c1_in, c2_in, c3_in, c4_in, c5_in, c6_in, c7_in, c8_in, + output[4:0] a0_out, a1_out, a2_out, a3_out, a4_out, a5_out, a6_out, a7_out, a8_out, + output[4:0] b0_out, b1_out, b2_out, b3_out, b4_out, b5_out, b6_out, b7_out, b8_out, + output[4:0] c0_out, c1_out, c2_out, c3_out, c4_out, c5_out, c6_out, c7_out, c8_out, + input clk +); + +register #(.width(5'd6)) + n_reg(.d(n_in), + .q(n_out), + .wrenable(wrenable), + .clk(clk)); + +register #(.width(6)) + m_reg(.d(m_in), + .q(m_out), + .wrenable(wrenable), + .clk(clk)); + +register #(.width(6)) + p_reg(.d(p_in), + .q(p_out), + .wrenable(wrenable), + .clk(clk)); + +register #(.width(5)) + a0_reg(.d(a0_in), + .q(a0_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a1_reg(.d(a1_in), + .q(a1_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a2_reg(.d(a2_in), + .q(a2_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a3_reg(.d(a3_in), + .q(a3_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a4_reg(.d(a4_in), + .q(a4_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a5_reg(.d(a5_in), + .q(a5_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a6_reg(.d(a6_in), + .q(a6_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a7_reg(.d(a7_in), + .q(a7_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + a8_reg(.d(a8_in), + .q(a8_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b0_reg(.d(b0_in), + .q(b0_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b1_reg(.d(b1_in), + .q(b1_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b2_reg(.d(b2_in), + .q(b2_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b3_reg(.d(b3_in), + .q(b3_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b4_reg(.d(b4_in), + .q(b4_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b5_reg(.d(b5_in), + .q(b5_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b6_reg(.d(b6_in), + .q(b6_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b7_reg(.d(b7_in), + .q(b7_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + b8_reg(.d(b8_in), + .q(b8_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c0_reg(.d(c0_in), + .q(c0_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c1_reg(.d(c1_in), + .q(c1_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c2_reg(.d(c2_in), + .q(c2_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c3_reg(.d(c3_in), + .q(c3_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c4_reg(.d(c4_in), + .q(c4_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c5_reg(.d(c5_in), + .q(c5_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c6_reg(.d(c6_in), + .q(c6_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c7_reg(.d(c7_in), + .q(c7_out), + .wrenable(wrenable), + .clk(clk)); +register #(.width(5)) + c8_reg(.d(c8_in), + .q(c8_out), + .wrenable(wrenable), + .clk(clk)); +endmodule From 16400b0a1c903adcf876a903999eed30d3f3eef8 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 12:04:35 -0500 Subject: [PATCH 26/98] Create modules for accessing block of memory --- load_block.t.v | 29 +++++++++++++++++++++++++++++ load_block.v | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 load_block.t.v create mode 100644 load_block.v diff --git a/load_block.t.v b/load_block.t.v new file mode 100644 index 0000000..8fc72cb --- /dev/null +++ b/load_block.t.v @@ -0,0 +1,29 @@ +`include "load_block.v" +`include "data_memory.v" + +// TODO(arianaolson419): create a test memory file with matrices. Add to testing script +module load_block_TEST(); + parameter ADDRESS_WIDTH = 32; + reg[ADDRESS_WIDTH - 1:0] addr_initial; + reg[ADDRESS_WIDTH - 1:0] columns; + wire[ADDRESS_WIDTH - 1:0] addr0, addr1, addr2, addr3; + wire[ADDRESS_WIDTH - 1:0] addr4, addr5, addr6, addr7, addr8; + + address3by3block #(.MEM_ADDRESS_WIDTH(ADDRESS_WIDTH)) dut ( + .addr_initial(addr_initial), + .columns (columns), + .addr0 (addr0), + .addr1 (addr1), + .addr2 (addr2), + .addr3 (addr3), + .addr4 (addr4), + .addr5 (addr5), + .addr6 (addr6), + .addr7 (addr7), + .addr8 (addr8), + ); + + initial begin + // tests + end +endmodule \ No newline at end of file diff --git a/load_block.v b/load_block.v new file mode 100644 index 0000000..e309ce4 --- /dev/null +++ b/load_block.v @@ -0,0 +1,45 @@ +/* +Address the entries of a 3 by 3 block of memory within a matrix stored in +the data memory. Matrices are stored in the data memory such that +each word is an entry of the matrix, and entries are stored one row at a time. + +Example: +3 by 3 Matrix Data Memory +------------- ----------- +a11 a12 a13 a11 +a21 a22 a23 => a12 +a31 a32 a33 a13 + a21 + a22 + a23 + a31 + a32 + a33 + +Inputs: + - addr_initial: the address of the first entry of the block. + - columns: the number of columns of the entire matrix stored in memory. +Outputs: + - addr: the address of the xth element of the block in data memory. +Parameters: + - MEM_ADDRESS_WIDTH: the number of bits of the addressees given to the data memory. +*/ + +module address3by3block +#(parameter MEM_ADDRESS_WIDTH = 32) +( + input[MEM_ADDRESS_WIDTH - 1:0] addr_initial, + input[MEM_ADDRESS_WIDTH - 1:0] columns, + output[MEM_ADDRESS_WIDTH - 1:0] addr0, addr1, addr2, addr3, addr4, + output[MEM_ADDRESS_WIDTH - 1:0] addr5, addr6, addr7, addr8 +); + assign addr0 = addr_initial; + assign addr1 = addr_initial + 1; + assign addr2 = addr_initial + 2; + assign addr3 = addr_initial + columns; + assign addr4 = addr_initial + columns + 1; + assign addr5 = addr_initial + columns + 2; + assign addr6 = addr_initial + (2 * columns); + assign addr7 = addr_initial + (2 * columns) + 1; + assign addr8 = addr_initial + (2 * columns) + 2; +endmodule \ No newline at end of file From acc45b32093af34e7f98d36524d673194f2045c3 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 12:05:19 -0500 Subject: [PATCH 27/98] Create test memory for data_memory.t.v --- matrix_mem.dat | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 matrix_mem.dat diff --git a/matrix_mem.dat b/matrix_mem.dat new file mode 100644 index 0000000..1bb139f --- /dev/null +++ b/matrix_mem.dat @@ -0,0 +1,65 @@ +// This is the memory that should be used in the data memory test bench +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 \ No newline at end of file From db8f8262ff6096a852d53117ba35071d6a45fd36 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 12:05:42 -0500 Subject: [PATCH 28/98] Change name --- load_matrices.v | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 load_matrices.v diff --git a/load_matrices.v b/load_matrices.v deleted file mode 100644 index 429e515..0000000 --- a/load_matrices.v +++ /dev/null @@ -1,3 +0,0 @@ -module load_matrices(); -// TODO(arianaolson419): Implement! -endmodule \ No newline at end of file From 505cd491cc391a4b659eecce2a161a86f2810ff9 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 12:06:33 -0500 Subject: [PATCH 29/98] Add todo comment --- data_memory.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_memory.v b/data_memory.v index babe694..d33597c 100644 --- a/data_memory.v +++ b/data_memory.v @@ -2,7 +2,7 @@ The memory where matrices are stored. */ -// TODO (arianaolson419): Allow multiple data access in some fashion. +// TODO (arianaolson419): Allow multiple data access in some fashion. module memory #( parameter addresswidth = 32, From 745f773c07eac71fb6d9b14533da7693b608d655 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 12:08:42 -0500 Subject: [PATCH 30/98] Add build target for load block --- makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index eaeb5bf..4d2a6e4 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -all: arithmetic dot matrixmultiplication data_mem +all: arithmetic dot matrixmultiplication data_mem load_block arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -10,4 +10,7 @@ matrixmultiplication: matrixmultiplication.v matrixmultiplication.t.v dot iverilog -Wall -o matmul matrixmultiplication.t.v data_mem: data_memory.v data_memory.t.v - iverilog -Wall -o data_mem data_memory.t.v \ No newline at end of file + iverilog -Wall -o data_mem data_memory.t.v + +load_block: load_block.v load_block.t.v data_mem + iverilog -Wall -o load_block load_block.t.v \ No newline at end of file From afa73a83a60ddb210659f651aad249ec9602fe37 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 21:34:57 -0500 Subject: [PATCH 31/98] Modify to take 9 data entries at a time --- data_memory.t.v | 88 ++++++++++++++++++++++++++++++++++++++++++------- data_memory.v | 30 ++++++++++++++--- 2 files changed, 101 insertions(+), 17 deletions(-) diff --git a/data_memory.t.v b/data_memory.t.v index 774841c..21fa072 100644 --- a/data_memory.t.v +++ b/data_memory.t.v @@ -6,14 +6,27 @@ Test bench for data memory module. module memory_TEST(); parameter ENTRY_SIZE = 5; + parameter ADDRESS_WIDTH = 32; reg clk; - reg [31:0] address; + reg [ADDRESS_WIDTH - 1:0] addr0, addr1, addr2, addr3, addr4; + reg [ADDRESS_WIDTH - 1:0] addr5, addr6, addr7, addr8; reg writeEnable; - reg [ENTRY_SIZE - 1:0] dataIn; + reg [ENTRY_SIZE - 1:0] dataIn0, dataIn1, dataIn2, dataIn3, dataIn4; + reg [ENTRY_SIZE - 1:0] dataIn5, dataIn6, dataIn7, dataIn8; - wire [ENTRY_SIZE - 1:0] dataOut; + wire [ENTRY_SIZE - 1:0] data0, data1, data2, data3, data4; + wire [ENTRY_SIZE - 1:0] data5, data6, data7, data8; - memory #(.width(ENTRY_SIZE) dut(clk, dataOut, address, writeEnable, dataIn); + memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) dut( + .clk(clk), .data0(data0), .data1(data1), .data2(data2), + .data3(data3), .data4(data4), .data5(data5), .data6(data6), + .data7(data7), .data8(data8), .addr0(addr0), .addr1(addr1), + .addr2(addr2), .addr3(addr3), .addr4(addr4), .addr5(addr5), + .addr6(addr6), .addr7(addr7), .addr8(addr8), .writeEnable(writeEnable), + .dataIn0(dataIn0), .dataIn1(dataIn1), .dataIn2(dataIn2), + .dataIn3(dataIn3), .dataIn4(dataIn4), .dataIn5(dataIn5), + .dataIn6(dataIn6), .dataIn7(dataIn7), .dataIn8(dataIn8) + ); initial clk = 0; always #10 clk = !clk; @@ -21,33 +34,84 @@ module memory_TEST(); $dumpfile("memory.vcd"); $dumpvars(0, memory_TEST, dut.memory[0]); + dataIn0 = 5'b00000; dataIn1 = dataIn0; dataIn2 = dataIn0; + dataIn3 = dataIn0; dataIn4 = dataIn5; dataIn6 = dataIn0; + dataIn7 = dataIn0; dataIn8 = dataIn0; + + addr0 = 32'd0; + addr1 = addr0 + ADDRESS_WIDTH; + addr2 = addr1 + ADDRESS_WIDTH; + addr3 = addr2 + ADDRESS_WIDTH; + addr4 = addr3 + ADDRESS_WIDTH; + addr5 = addr4 + ADDRESS_WIDTH; + addr6 = addr5 + ADDRESS_WIDTH; + addr7 = addr6 + ADDRESS_WIDTH; + addr8 = addr7 + ADDRESS_WIDTH; // Test Case 1: Do not write if writeEnable is low. - writeEnable = 0; dataIn = 5'hffff; address = 5'd0; + writeEnable = 0; dataIn0 = 5'h1f; #20 - if (dataOut === dataIn) begin + if (data0 === dataIn0) begin $display("Test case 1 failed: memory was written to when writeEnable was false."); end - else if (dataOut === 5'bx) begin + else if (data0 === 5'bx) begin $display("Test case 1 failed: there is no memory at the given address."); end #1000 // Test case 2: Write to memory if writeEnable is high. - writeEnable = 1; dataIn = 5'hffff; address = 5'd0; + writeEnable = 1; + dataIn0 = 5'h1f; + dataIn1 = 5'h1e; + dataIn2 = 5'h1d; + dataIn3 = 5'h1c; + dataIn4 = 5'h1b; + dataIn5 = 5'h1a; + dataIn6 = 5'h19; + dataIn7 = 5'h18; + dataIn8 = 5'h17; + #40 - if (dataOut === 5'bx) begin + if (data0 === 5'bx) begin $display("Test case 2 failed: there is no memory at the given address."); end - if (dut.memory[0] !== dataIn) begin + if (dut.memory[0] !== dataIn0) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn"); end - if (dataOut !== dataIn) begin - $display("Test case 2 failed: memory was not written to when writeEnable was true."); + // if (data0 !== dataIn0) begin + // $display("Test case 2 failed: memory was not written to when writeEnable was true."); + // end + if (dut.memory[0] !== dataIn0) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn0"); + end + if (dut.memory[1] !== dataIn1) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn1"); + end + if (dut.memory[2] !== dataIn2) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn2"); + end + if (dut.memory[3] !== dataIn3) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn3"); + end + if (dut.memory[4] !== dataIn4) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn4"); end + if (dut.memory[5] !== dataIn5) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn5"); + end + if (dut.memory[6] !== dataIn6) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn6"); + end + if (dut.memory[7] !== dataIn7) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn7"); + end + if (dut.memory[8] !== dataIn8) begin + $display("Test case 2 failed: the memory contained at the given address does not match dataIn8"); + end + #1000 diff --git a/data_memory.v b/data_memory.v index d33597c..006e6d7 100644 --- a/data_memory.v +++ b/data_memory.v @@ -11,10 +11,13 @@ module memory ) ( input clk, - output [width-1:0] dataOut, - input [addresswidth-1:0] address, + output [width-1:0] data0, data1, data2, data3, data4, + output [width-1:0] data5, data6, data7, data8, + input [addresswidth-1:0] addr0, addr1, addr2, addr3, addr4, + input [addresswidth-1:0] addr5, addr6, addr7, addr8, input writeEnable, - input [width-1:0] dataIn + input [width-1:0] dataIn0, dataIn1, dataIn2, dataIn3, dataIn4, + input [width-1:0] dataIn5, dataIn6, dataIn7, dataIn8 ); @@ -22,9 +25,26 @@ module memory always @(negedge clk) begin if(writeEnable) - memory[address >> 2] <= dataIn; + memory[addr0 >> 2] <= dataIn0; + memory[addr1 >> 2] <= dataIn1; + memory[addr2 >> 2] <= dataIn2; + memory[addr3 >> 2] <= dataIn3; + memory[addr4 >> 2] <= dataIn4; + memory[addr5 >> 2] <= dataIn5; + memory[addr6 >> 2] <= dataIn6; + memory[addr7 >> 2] <= dataIn7; + memory[addr8 >> 2] <= dataIn8; end - assign dataOut = memory[address >> 2]; + + assign data0 = memory[addr0 >> 2]; + assign data1 = memory[addr1 >> 2]; + assign data2 = memory[addr2 >> 2]; + assign data3 = memory[addr3 >> 2]; + assign data4 = memory[addr4 >> 2]; + assign data5 = memory[addr5 >> 2]; + assign data6 = memory[addr6 >> 2]; + assign data7 = memory[addr7 >> 2]; + assign data8 = memory[addr8 >> 2]; initial $readmemh("matrix_mem.dat", memory); From 78877406fa6e2bd2d2d552d835f7f6f1eddc24ce Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 21:35:23 -0500 Subject: [PATCH 32/98] create test bench --- load_block.t.v | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/load_block.t.v b/load_block.t.v index 8fc72cb..8d79202 100644 --- a/load_block.t.v +++ b/load_block.t.v @@ -4,26 +4,49 @@ // TODO(arianaolson419): create a test memory file with matrices. Add to testing script module load_block_TEST(); parameter ADDRESS_WIDTH = 32; + parameter ENTRY_SIZE = 5; + reg[ADDRESS_WIDTH - 1:0] addr_initial; reg[ADDRESS_WIDTH - 1:0] columns; - wire[ADDRESS_WIDTH - 1:0] addr0, addr1, addr2, addr3; - wire[ADDRESS_WIDTH - 1:0] addr4, addr5, addr6, addr7, addr8; + wire[ADDRESS_WIDTH - 1:0] addrOut0, addrOut1, addrOut2, addrOut3; + wire[ADDRESS_WIDTH - 1:0] addrOut4, addrOut5, addrOut6, addrOut7, addrOut8; address3by3block #(.MEM_ADDRESS_WIDTH(ADDRESS_WIDTH)) dut ( .addr_initial(addr_initial), .columns (columns), - .addr0 (addr0), - .addr1 (addr1), - .addr2 (addr2), - .addr3 (addr3), - .addr4 (addr4), - .addr5 (addr5), - .addr6 (addr6), - .addr7 (addr7), - .addr8 (addr8), + .addr0 (addrOut0), + .addr1 (addrOut1), + .addr2 (addrOut2), + .addr3 (addrOut3), + .addr4 (addrOut4), + .addr5 (addrOut5), + .addr6 (addrOut6), + .addr7 (addrOut7), + .addr8 (addrOut8) + ); + + reg clk; + reg [ADDRESS_WIDTH - 1:0] addr0, addr1, addr2, addr3, addr4; + reg [ADDRESS_WIDTH - 1:0] addr5, addr6, addr7, addr8; + reg writeEnable; + reg [ENTRY_SIZE - 1:0] dataIn0, dataIn1, dataIn2, dataIn3, dataIn4; + reg [ENTRY_SIZE - 1:0] dataIn5, dataIn6, dataIn7, dataIn8; + + wire [ENTRY_SIZE - 1:0] data0, data1, data2, data3, data4; + wire [ENTRY_SIZE - 1:0] data5, data6, data7, data8; + + memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) mem ( + .clk(clk), .data0(data0), .data1(data1), .data2(data2), + .data3(data3), .data4(data4), .data5(data5), .data6(data6), + .data7(data7), .data8(data8), .addr0(addr0), .addr1(addr1), + .addr2(addr2), .addr3(addr3), .addr4(addr4), .addr5(addr5), + .addr6(addr6), .addr7(addr7), .addr8(addr8), .writeEnable(writeEnable), + .dataIn0(dataIn0), .dataIn1(dataIn1), .dataIn2(dataIn2), + .dataIn3(dataIn3), .dataIn4(dataIn4), .dataIn5(dataIn5), + .dataIn6(dataIn6), .dataIn7(dataIn7), .dataIn8(dataIn8) ); initial begin - // tests + // TODO(rocco): tests! end endmodule \ No newline at end of file From b9637b04b380cc9751b19a1a984b33e6489a3035 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 21:35:48 -0500 Subject: [PATCH 33/98] Create potential test data --- block_test_data.dat | 73 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 block_test_data.dat diff --git a/block_test_data.dat b/block_test_data.dat new file mode 100644 index 0000000..ae5e690 --- /dev/null +++ b/block_test_data.dat @@ -0,0 +1,73 @@ +// This is the memory that should be used in the load block test + +// 3 by 3 identity +0_0001 +0_0000 +0_0000 +0_0000 +0_0001 +0_0000 +0_0000 +0_0000 +0_0001 + +// 4 by 4 increasing +0_0000 +0_0001 +0_0010 +0_0011 +0_0100 +0_0101 +0_0110 +0_0111 +0_1000 +0_1001 +0_1010 +0_1011 +0_1100 +0_1101 +0_1110 +0_1111 + +// 7 by 3 decreasing +1_1111 +1_1110 +1_1101 +1_1100 +1_1011 +1_1010 +1_1001 +1_1000 +1_0111 +1_0110 +1_0101 +1_0100 +1_0011 +1_0010 +1_0001 +1_0000 +0_1111 +0_1110 +0_1101 +0_1100 +0_1011 + +// Extra memory +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 \ No newline at end of file From ee7f124b7a114de7e0b236d8033ac3c0c45ff621 Mon Sep 17 00:00:00 2001 From: Ariana Olson Date: Sat, 9 Dec 2017 21:40:49 -0500 Subject: [PATCH 34/98] Fix spelling typos --- docs/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8df8009..fba905e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,12 +6,12 @@ For our Computer Architecture final project, we designed computer hardware to mu ## Project Motivation and Background -After studying single cycle MIPS CPUs, we were interested in other computing architectures with different strengths and weakensses. We first looked at GPUs, which were originally designed specifically for graphics, but have recently been generalized to be fully functional CPUs. Graphics opperations are essentially a subset of matrix opperations (where the :With this added functionallity, GPUs have become increasingly usefull for machine learning algorithms and general parallel computing. Mostly, computations on matricies are complex and time intensive on normal CPUs, but the extreme parallelization of computations in a GPU makes it much more efficient at these opperations. We wanted to explore this increase in efficiency by making some purpose built hardware for matrix multiplication. +After studying single cycle MIPS CPUs, we were interested in other computing architectures with different strengths and weakenesses. We first looked at GPUs, which were originally designed specifically for graphics, but have recently been generalized to be fully functional CPUs. Graphics opperations are essentially a subset of matrix opperations (where the :With this added functionallity, GPUs have become increasingly usefull for machine learning algorithms and general parallel computing. Mostly, computations on matricies are complex and time intensive on normal CPUs, but the extreme parallelization of computations in a GPU makes it much more efficient at these opperations. We wanted to explore this increase in efficiency by making some purpose built hardware for matrix multiplication. ## Results ## Similarities to Graphics -As we mentioned before, graphics opperations are essentially a subset of matrix opperations. +As we mentioned before, graphics operations are essentially a subset of matrix opperations. ## Appendix From 2726bbd257a9060d8253d9cb9ebdc5c885cb879a Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sat, 9 Dec 2017 22:03:09 -0500 Subject: [PATCH 35/98] Fix addressing scheme --- data_memory.t.v | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/data_memory.t.v b/data_memory.t.v index 21fa072..e00b4bd 100644 --- a/data_memory.t.v +++ b/data_memory.t.v @@ -39,14 +39,15 @@ module memory_TEST(); dataIn7 = dataIn0; dataIn8 = dataIn0; addr0 = 32'd0; - addr1 = addr0 + ADDRESS_WIDTH; - addr2 = addr1 + ADDRESS_WIDTH; - addr3 = addr2 + ADDRESS_WIDTH; - addr4 = addr3 + ADDRESS_WIDTH; - addr5 = addr4 + ADDRESS_WIDTH; - addr6 = addr5 + ADDRESS_WIDTH; - addr7 = addr6 + ADDRESS_WIDTH; - addr8 = addr7 + ADDRESS_WIDTH; + addr1 = addr0 + (32'd1 << 2); + addr2 = addr1 + (32'd1 << 2); + addr3 = addr2 + (32'd1 << 2); + addr4 = addr3 + (32'd1 << 2); + addr5 = addr4 + (32'd1 << 2); + addr6 = addr5 + (32'd1 << 2); + addr7 = addr6 + (32'd1 << 2); + addr8 = addr7 + (32'd1 << 2); + // Test Case 1: Do not write if writeEnable is low. writeEnable = 0; dataIn0 = 5'h1f; #20 @@ -77,37 +78,43 @@ module memory_TEST(); $display("Test case 2 failed: there is no memory at the given address."); end - if (dut.memory[0] !== dataIn0) begin - $display("Test case 2 failed: the memory contained at the given address does not match dataIn"); + if (data0 !== dataIn0) begin + $display("Test case 2 failed: memory was not written to when writeEnable was true."); end - // if (data0 !== dataIn0) begin - // $display("Test case 2 failed: memory was not written to when writeEnable was true."); - // end if (dut.memory[0] !== dataIn0) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn0"); end + if (dut.memory[1] !== dataIn1) begin + $display("dut.memory: %b, dataIn: %b", dut.memory[8], dataIn1); $display("Test case 2 failed: the memory contained at the given address does not match dataIn1"); end + if (dut.memory[2] !== dataIn2) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn2"); end + if (dut.memory[3] !== dataIn3) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn3"); end + if (dut.memory[4] !== dataIn4) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn4"); end + if (dut.memory[5] !== dataIn5) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn5"); end + if (dut.memory[6] !== dataIn6) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn6"); end + if (dut.memory[7] !== dataIn7) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn7"); end + if (dut.memory[8] !== dataIn8) begin $display("Test case 2 failed: the memory contained at the given address does not match dataIn8"); end From 2d03fe0bd998e20f6b80c5841ffa7e6a9d647792 Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Sat, 9 Dec 2017 22:24:40 -0500 Subject: [PATCH 36/98] added tests for load_block and included them in run_tests.sh --- block_test_data.dat | 10 ++--- load_block.t.v | 97 ++++++++++++++++++++++++++++++++++++++++++++- run_tests.sh | 4 +- 3 files changed, 103 insertions(+), 8 deletions(-) diff --git a/block_test_data.dat b/block_test_data.dat index ae5e690..48330d4 100644 --- a/block_test_data.dat +++ b/block_test_data.dat @@ -1,6 +1,6 @@ // This is the memory that should be used in the load block test -// 3 by 3 identity +// 3 by 3 identity at address 0 0_0001 0_0000 0_0000 @@ -11,7 +11,7 @@ 0_0000 0_0001 -// 4 by 4 increasing +// 4 by 4 increasing at address 9 0_0000 0_0001 0_0010 @@ -29,7 +29,7 @@ 0_1110 0_1111 -// 7 by 3 decreasing +// 7 by 3 decreasing at address 25 1_1111 1_1110 1_1101 @@ -52,7 +52,8 @@ 0_1100 0_1011 -// Extra memory +// Extra memory at address 46 +0_0000 0_0000 0_0000 0_0000 @@ -70,4 +71,3 @@ 0_0000 0_0000 0_0000 -0_0000 \ No newline at end of file diff --git a/load_block.t.v b/load_block.t.v index 8d79202..9dfbec1 100644 --- a/load_block.t.v +++ b/load_block.t.v @@ -5,6 +5,7 @@ module load_block_TEST(); parameter ADDRESS_WIDTH = 32; parameter ENTRY_SIZE = 5; + parameter NUM_TESTS = 4; reg[ADDRESS_WIDTH - 1:0] addr_initial; reg[ADDRESS_WIDTH - 1:0] columns; @@ -46,7 +47,99 @@ module load_block_TEST(); .dataIn6(dataIn6), .dataIn7(dataIn7), .dataIn8(dataIn8) ); + reg[5:0] success_count = 0; + initial begin - // TODO(rocco): tests! + $dumpfile("load_block.vcd"); + $dumpvars(); + + // Test Case 1: read a 3x3 matrix from address zero + addr_initial = 0; + columns = 3; + + // cycle clock + clk = 0; + #1 clk = 1; + #1 + + if (addrOut0 === 0 & addrOut1 === 1 & addrOut2 === 2 & + addrOut3 === 3 & addrOut4 === 4 & addrOut5 === 5 & + addrOut6 === 6 & addrOut7 === 7 & addrOut8 === 8) + begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test case 1 failed: 3x3 matrix at addres 0"); + end + + // Test Case 2: read top left block of 4x4 matrix from address 9 + addr_initial = 9; + columns = 4; + + // cycle clock + clk = 0; + #1 clk = 1; + #1 + + if (addrOut0 === 9 & addrOut1 === 10 & addrOut2 === 11 & + addrOut3 === 13 & addrOut4 === 14 & addrOut5 === 15 & + addrOut6 === 17 & addrOut7 === 18 & addrOut8 === 19) + begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test case 2 failed: 4x4 matrix at address 9"); + end + + // Test Case 3: read bottom right block of 4x4 matrix + // (starting at address 14) + addr_initial = 14; + columns = 4; + + // cycle clock + clk = 0; + #1 clk = 1; + #1 + + if (addrOut0 === 14 & addrOut1 === 15 & addrOut2 === 16 & + addrOut3 === 18 & addrOut4 === 19 & addrOut5 === 20 & + addrOut6 === 22 & addrOut7 === 23 & addrOut8 === 24) + begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test case 3 failed: 4x4 matrix at address 14"); + end + + // Test Case 4: 7 column matrix at address 25 + addr_initial = 25; + columns = 7; + + // cycle clock + clk = 0; + #1 clk = 1; + #1 + + if (addrOut0 === 25 & addrOut1 === 26 & addrOut2 === 27 & + addrOut3 === 32 & addrOut4 === 33 & addrOut5 === 34 & + addrOut6 === 39 & addrOut7 === 40 & addrOut8 === 41) + begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test case 3 failed: 4x4 matrix at address 14"); + end + + if (success_count < NUM_TESTS) begin + $display("\nLoad Block Failed %d Tests\n",(NUM_TESTS-success_count)); + end + else begin + $display("Load Block Passed All %d tests", NUM_TESTS); + end + end -endmodule \ No newline at end of file +endmodule diff --git a/run_tests.sh b/run_tests.sh index 90869d5..8cac41f 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -12,4 +12,6 @@ echo "Running arithmetic tests..." echo "Running dot tests..." ./dot echo "Running matmul tests..." -./matmul \ No newline at end of file +./matmul +echo "Running load block tests..." +./load_block From 3457f3aa95dc7b0fa984314a51cd167df031febb Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Sun, 10 Dec 2017 02:45:45 -0500 Subject: [PATCH 37/98] added register tests to scripts --- makefile | 5 ++++- run_tests.sh | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 4d2a6e4..a8a0981 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -all: arithmetic dot matrixmultiplication data_mem load_block +all: arithmetic dot matrixmultiplication registers data_mem load_block arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -9,6 +9,9 @@ dot: dot.v dot.t.v arithmetic matrixmultiplication: matrixmultiplication.v matrixmultiplication.t.v dot iverilog -Wall -o matmul matrixmultiplication.t.v +registers: registers.v registers.t.v + iverilog -Wall -o registers registers.t.v + data_mem: data_memory.v data_memory.t.v iverilog -Wall -o data_mem data_memory.t.v diff --git a/run_tests.sh b/run_tests.sh index 90869d5..7c8b14c 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -12,4 +12,6 @@ echo "Running arithmetic tests..." echo "Running dot tests..." ./dot echo "Running matmul tests..." -./matmul \ No newline at end of file +./matmul +echo "Running register tests..." +./registers \ No newline at end of file From f2c2e64d94e509c26ad0c361934195546ec778f8 Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Sun, 10 Dec 2017 11:14:32 -0500 Subject: [PATCH 38/98] added fsm and tests, still need a program memory and program counter file --- fsm.t.v | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++ fsm.v | 53 +++++++++++++++++++++++ makefile | 5 ++- run_tests.sh | 2 + 4 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 fsm.t.v create mode 100644 fsm.v diff --git a/fsm.t.v b/fsm.t.v new file mode 100644 index 0000000..5f9d9eb --- /dev/null +++ b/fsm.t.v @@ -0,0 +1,116 @@ +`include "fsm.v" + +module fsm_TEST(); + parameter NUM_TESTS = 5; + + reg[4:0] command; + wire data_we; + wire weA, weB, weC, weD, weE, weF, weG, weH; + wire[1:0] jklm_sel; + + fsm dut ( + .command(command), + .data_we(data_we), + .weA(weA), .weB(weB), .weC(weC), .weD(weD), + .weE(weE), .weF(weF), .weG(weG), .weH(weH), + .jklm_select(jklm_sel) + ); + + reg[5:0] success_count = 0; + + initial begin + $dumpfile("fsm.vcd"); + $dumpvars(); + + // Test Case 1: load to block A + command = 5'b0; + #10 + + if (data_we != 0) begin + $display("Test Case 1 Failed: data_we not set correctly"); + end + else if (weA === 1 & {weB, weC, weD, weE, weF, weG, weH} === 7'b0) begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test Case 1 Failed: write enables not set correctly"); + end + + // Test Case 2: load to block C + command = 5'b00011; + #10 + + if (data_we != 0) begin + $display("Test Case 2 Failed: data_we not set correctly"); + end + else if (weD === 1 & {weA, weB, weC, weE, weF, weG, weH} === 7'b0) begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test Case 2 Failed: write enables not set correctly"); + end + + // Test Case 3: load to block H + command = 5'b00111; + #10 + + if (data_we != 0) begin + $display("Test Case 1 Failed: data_we not set correctly"); + end + else if (weH === 1 & {weA, weB, weC, weD, weE, weF, weG} === 7'b0) begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test Case 3 Failed: write enables not set correctly"); + end + + // Test Case 4: store from block J + command = 5'b01000; + #10 + + if (data_we != 1) begin + $display("Test Case 4 Failed: data_we not set correctly"); + end + else if ({weA, weB, weC, weD, weE, weF, weG, weH} != 8'b0) begin + $display("Test Case 4 Failed: block we set on store"); + end + else if (jklm_sel != 2'b00) begin + $display("Test Case 4 Failed: jklm_select not correct"); + end + else begin + // test passed + success_count = success_count+1; + end + + // Test Case 5: store from block M + command = 5'b01011; + #10 + + if (data_we != 1) begin + $display("Test Case 5 Failed: data_we not set correctly"); + end + else if ({weA, weB, weC, weD, weE, weF, weG, weH} != 8'b0) begin + $display("Test Case 5 Failed: block we set on store"); + end + else if (jklm_sel != 2'b11) begin + $display("Test Case 5 Failed: jklm_select not correct"); + end + else begin + // test passed + success_count = success_count+1; + end + + + if (success_count < NUM_TESTS) begin + $display("\nFSM Failed %d Tests\n",(NUM_TESTS-success_count)); + end + else begin + $display("FSM Passed All %d tests", NUM_TESTS); + end + + end +endmodule + diff --git a/fsm.v b/fsm.v new file mode 100644 index 0000000..00d1c55 --- /dev/null +++ b/fsm.v @@ -0,0 +1,53 @@ +/* +Manages the control signals throught the matrix multiplier based on an input command + +commad structure: + |type|block| + | 0 0|0 0 0| + +type selects between load (00) and store (01) +block selects the block matrix to either load from or store to + 000 = A ... 111 = H + x00 = J ... x11 = M + +Inputs: + - command: the command from program memory, structure explained above +Outputs: + - data_we: write enable for the data memory + - weA-weH: write enables for each input to the computation blocks + - jklm_select: select bits for mux on the output matricies +*/ + +module fsm +#( +parameter TYPE_LEN = 2, +parameter BLOCK_LEN = 3 +) +( + input[TYPE_LEN+BLOCK_LEN-1:0] command, + output data_we, + output weA, weB, weC, weD, weE, weF, weG, weH, + output[1:0] jklm_select +); + + wire[TYPE_LEN-1:0] type; + assign type = command[TYPE_LEN+BLOCK_LEN-1:BLOCK_LEN]; + assign data_we = type[0]; // modify if we need more types + + wire[BLOCK_LEN-1:0] block; + assign block = command[BLOCK_LEN-1:0]; + + assign jklm_select = block[1:0]; // last two bits of block select which matrix to store + + // decoder to enable loading of selected block + assign {weA, weB, weC, weD, weE, weF, weG, weH} = + ( block == 3'b000 & type==0) ? 8'b10000000 : + ( block == 3'b001 & type==0) ? 8'b01000000 : + ( block == 3'b010 & type==0) ? 8'b00100000 : + ( block == 3'b011 & type==0) ? 8'b00010000 : + ( block == 3'b100 & type==0) ? 8'b00001000 : + ( block == 3'b101 & type==0) ? 8'b00000100 : + ( block == 3'b110 & type==0) ? 8'b00000010 : + ( block == 3'b111 & type==0) ? 8'b00000001 : + 8'b00000000; +endmodule diff --git a/makefile b/makefile index 4d2a6e4..9f9f5ad 100644 --- a/makefile +++ b/makefile @@ -13,4 +13,7 @@ data_mem: data_memory.v data_memory.t.v iverilog -Wall -o data_mem data_memory.t.v load_block: load_block.v load_block.t.v data_mem - iverilog -Wall -o load_block load_block.t.v \ No newline at end of file + iverilog -Wall -o load_block load_block.t.v + +fsm: fsm.v fsm.t.v + iverilog -Wall -o fsm fsm.t.v diff --git a/run_tests.sh b/run_tests.sh index 8cac41f..8bd4a20 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -15,3 +15,5 @@ echo "Running matmul tests..." ./matmul echo "Running load block tests..." ./load_block +echo "running fsm tests..." +./fsm From b15a7089e6932954144010458f530cfb1b12fb71 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 12:07:45 -0500 Subject: [PATCH 39/98] Remove size registers and update tests --- registers.t.v | 34 +++++++----- registers.v | 146 ++++++++++++++++++++++---------------------------- 2 files changed, 84 insertions(+), 96 deletions(-) diff --git a/registers.t.v b/registers.t.v index 4e2670a..ae0c1b4 100644 --- a/registers.t.v +++ b/registers.t.v @@ -2,9 +2,7 @@ module test_registers(); -reg clk, wrenable; -reg[5:0] n_in, m_in, p_in; -wire[5:0] n_out, m_out, p_out; +reg clk, a_wrenable, b_wrenable, c_wrenable; reg[4:0] a0_in, a1_in, a2_in, a3_in, a4_in, a5_in, a6_in, a7_in, a8_in; reg[4:0] b0_in, b1_in, b2_in, b3_in, b4_in, b5_in, b6_in, b7_in, b8_in; reg[4:0] c0_in, c1_in, c2_in, c3_in, c4_in, c5_in, c6_in, c7_in, c8_in; @@ -12,15 +10,19 @@ wire[4:0] a0_out, a1_out, a2_out, a3_out, a4_out, a5_out, a6_out, a7_out, a8_out wire[4:0] b0_out, b1_out, b2_out, b3_out, b4_out, b5_out, b6_out, b7_out, b8_out; wire[4:0] c0_out, c1_out, c2_out, c3_out, c4_out, c5_out, c6_out, c7_out, c8_out; -regfile dut (wrenable, n_in, m_in, p_in, - n_out, m_out, p_out, - a0_in, a1_in, a2_in, a3_in, a4_in, a5_in, a6_in, a7_in, a8_in, - b0_in, b1_in, b2_in, b3_in, b4_in, b5_in, b6_in, b7_in, b8_in, - c0_in, c1_in, c2_in, c3_in, c4_in, c5_in, c6_in, c7_in, c8_in, - a0_out, a1_out, a2_out, a3_out, a4_out, a5_out, a6_out, a7_out, a8_out, - b0_out, b1_out, b2_out, b3_out, b4_out, b5_out, b6_out, b7_out, b8_out, - c0_out, c1_out, c2_out, c3_out, c4_out, c5_out, c6_out, c7_out, c8_out, - clk); +regfile #(.width(5)) dut ( + .a_wrenable(a_wrenable), .b_wrenable(b_wrenable), .c_wrenable(c_wrenable), + .a0_in (a0_in), .a1_in (a1_in), .a2_in (a2_in), .a3_in (a3_in), .a4_in (a4_in), .a5_in (a5_in), + .a6_in (a6_in), .a7_in (a7_in), .a8_in (a8_in), .b0_in (b0_in), .b1_in (b1_in), .b2_in (b2_in), + .b3_in (b3_in), .b4_in (b4_in), .b5_in (b5_in), .b6_in (b6_in), .b7_in (b7_in), .b8_in (b8_in), + .c0_in (c0_in), .c1_in (c1_in), .c2_in (c2_in), .c3_in (c3_in), .c4_in (c4_in), .c5_in (c5_in), + .c6_in (c6_in), .c7_in (c7_in), .c8_in (c8_in), .a0_out (a0_out), .a1_out (a1_out), .a2_out (a2_out), + .a3_out (a3_out), .a4_out (a4_out), .a5_out (a5_out), .a6_out (a6_out), .a7_out (a7_out), .a8_out (a8_out), + .b0_out (b0_out), .b1_out (b1_out), .b2_out (b2_out), .b3_out (b3_out), .b4_out (b4_out), .b5_out (b5_out), + .b6_out (b6_out), .b7_out (b7_out), .b8_out (b8_out), .c0_out (c0_out), .c1_out (c1_out), .c2_out (c2_out), + .c3_out (c3_out), .c4_out (c4_out), .c5_out (c5_out), .c6_out (c6_out), .c7_out (c7_out), .c8_out (c8_out), + .clk (clk) +); genvar i; initial begin @@ -52,7 +54,9 @@ c5_in = 5'd23; c6_in = 5'd24; c7_in = 5'd25; c8_in = 5'd26; -wrenable = 0; +a_wrenable = 0; +b_wrenable = 0; +c_wrenable = 0; clk = 0; #5 clk = 1; #5 @@ -68,7 +72,9 @@ c5_out !== 5'd0 || c6_out !== 5'd0 || c7_out !== 5'd0 || c8_out !== 5'd0) $display("wrote to registers when wrenable was 0"); -wrenable = 1; +a_wrenable = 1; +b_wrenable = 1; +c_wrenable = 1; clk = 0; #5 clk = 1; #5 diff --git a/registers.v b/registers.v index 52aa60f..2f30f73 100644 --- a/registers.v +++ b/registers.v @@ -20,170 +20,152 @@ module register #(parameter width = 5'd4, parameter init = {width{1'd0}}) endmodule module regfile +#(parameter width = 5) ( - input wrenable, - input[5:0] n_in, m_in, p_in, - output[5:0] n_out, m_out, p_out, - input[4:0] a0_in, a1_in, a2_in, a3_in, a4_in, a5_in, a6_in, a7_in, a8_in, - input[4:0] b0_in, b1_in, b2_in, b3_in, b4_in, b5_in, b6_in, b7_in, b8_in, - input[4:0] c0_in, c1_in, c2_in, c3_in, c4_in, c5_in, c6_in, c7_in, c8_in, - output[4:0] a0_out, a1_out, a2_out, a3_out, a4_out, a5_out, a6_out, a7_out, a8_out, - output[4:0] b0_out, b1_out, b2_out, b3_out, b4_out, b5_out, b6_out, b7_out, b8_out, - output[4:0] c0_out, c1_out, c2_out, c3_out, c4_out, c5_out, c6_out, c7_out, c8_out, + input a_wrenable, + input b_wrenable, + input c_wrenable, + input[width - 1:0] a0_in, a1_in, a2_in, a3_in, a4_in, a5_in, a6_in, a7_in, a8_in, + input[width - 1:0] b0_in, b1_in, b2_in, b3_in, b4_in, b5_in, b6_in, b7_in, b8_in, + input[width - 1:0] c0_in, c1_in, c2_in, c3_in, c4_in, c5_in, c6_in, c7_in, c8_in, + output[width - 1:0] a0_out, a1_out, a2_out, a3_out, a4_out, a5_out, a6_out, a7_out, a8_out, + output[width - 1:0] b0_out, b1_out, b2_out, b3_out, b4_out, b5_out, b6_out, b7_out, b8_out, + output[width - 1:0] c0_out, c1_out, c2_out, c3_out, c4_out, c5_out, c6_out, c7_out, c8_out, input clk ); - -register #(.width(5'd6)) - n_reg(.d(n_in), - .q(n_out), - .wrenable(wrenable), - .clk(clk)); - -register #(.width(6)) - m_reg(.d(m_in), - .q(m_out), - .wrenable(wrenable), - .clk(clk)); - -register #(.width(6)) - p_reg(.d(p_in), - .q(p_out), - .wrenable(wrenable), - .clk(clk)); - -register #(.width(5)) +register #(.width(width)) a0_reg(.d(a0_in), .q(a0_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a1_reg(.d(a1_in), .q(a1_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a2_reg(.d(a2_in), .q(a2_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a3_reg(.d(a3_in), .q(a3_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a4_reg(.d(a4_in), .q(a4_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a5_reg(.d(a5_in), .q(a5_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a6_reg(.d(a6_in), .q(a6_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a7_reg(.d(a7_in), .q(a7_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) a8_reg(.d(a8_in), .q(a8_out), - .wrenable(wrenable), + .wrenable(a_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b0_reg(.d(b0_in), .q(b0_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b1_reg(.d(b1_in), .q(b1_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b2_reg(.d(b2_in), .q(b2_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b3_reg(.d(b3_in), .q(b3_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b4_reg(.d(b4_in), .q(b4_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b5_reg(.d(b5_in), .q(b5_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b6_reg(.d(b6_in), .q(b6_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b7_reg(.d(b7_in), .q(b7_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) b8_reg(.d(b8_in), .q(b8_out), - .wrenable(wrenable), + .wrenable(b_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c0_reg(.d(c0_in), .q(c0_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c1_reg(.d(c1_in), .q(c1_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c2_reg(.d(c2_in), .q(c2_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c3_reg(.d(c3_in), .q(c3_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c4_reg(.d(c4_in), .q(c4_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c5_reg(.d(c5_in), .q(c5_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c6_reg(.d(c6_in), .q(c6_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c7_reg(.d(c7_in), .q(c7_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); -register #(.width(5)) +register #(.width(width)) c8_reg(.d(c8_in), .q(c8_out), - .wrenable(wrenable), + .wrenable(c_wrenable), .clk(clk)); endmodule From b74f8103fef92ff3b1bc1eae2bc5a48b5dcabfe7 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 12:08:51 -0500 Subject: [PATCH 40/98] Resolve TODO --- data_memory.v | 1 - 1 file changed, 1 deletion(-) diff --git a/data_memory.v b/data_memory.v index 006e6d7..71d21f0 100644 --- a/data_memory.v +++ b/data_memory.v @@ -2,7 +2,6 @@ The memory where matrices are stored. */ -// TODO (arianaolson419): Allow multiple data access in some fashion. module memory #( parameter addresswidth = 32, From c047a4ef0b5c7da81b7ca43f07c39590bffa3900 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 12:09:33 -0500 Subject: [PATCH 41/98] Add build target --- makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index 4d2a6e4..f86d6d1 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -all: arithmetic dot matrixmultiplication data_mem load_block +all: arithmetic dot matrixmultiplication data_mem load_block add_block arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -13,4 +13,7 @@ data_mem: data_memory.v data_memory.t.v iverilog -Wall -o data_mem data_memory.t.v load_block: load_block.v load_block.t.v data_mem - iverilog -Wall -o load_block load_block.t.v \ No newline at end of file + iverilog -Wall -o load_block load_block.t.v + +add_block: add3by3.v add3by3.t.v + iverilog -Wall -o add_block add3by3.t.v \ No newline at end of file From 09c04255890a74a29ff70ca3f394e26390a05b53 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 12:11:26 -0500 Subject: [PATCH 42/98] Create and test adder --- add3by3.t.v | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++ add3by3.v | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 add3by3.t.v create mode 100644 add3by3.v diff --git a/add3by3.t.v b/add3by3.t.v new file mode 100644 index 0000000..eca5117 --- /dev/null +++ b/add3by3.t.v @@ -0,0 +1,61 @@ +/* +Test bench for 3 by 3 matrix adder +*/ + +`include "add3by3.v" + +module add3by3_TEST(); + parameter ENTRY_SIZE = 9; + + reg[ENTRY_SIZE - 1:0] a0, a1, a2, a3, a4; + reg[ENTRY_SIZE - 1:0] a5, a6, a7, a8; + reg[ENTRY_SIZE - 1:0] b0, b1, b2, b3, b4; + reg[ENTRY_SIZE - 1:0] b5, b6, b7, b8; + wire[ENTRY_SIZE - 1:0] c0, c1, c2, c3, c4; + wire[ENTRY_SIZE - 1:0] c5, c6, c7, c8; + + add3by3 #(.ENTRY_SIZE(ENTRY_SIZE)) dut ( + .a0(a0), .a1(a1), .a2(a2), .a3(a3), .a4(a4), + .a5(a5), .a6(a6), .a7(a7), .a8(a8), .b0(b0), + .b1(b1), .b2(b2), .b3(b3), .b4(b4), .b5(b5), + .b6(b6), .b7(b7), .b8(b8), .c0(c0), .c1(c1), + .c2(c2), .c3(c3), .c4(c4), .c5(c5), .c6(c6), + .c7(c7), .c8(c8) + ); + + initial begin + // Add two matrices + a0 = 1; a1 = 2; a2 = 3; a3 = 4; a4 = 5; a5 = 6; a6 = 7; a7 = 8; a8 = 9; + b0 = 30; b1 = 29; b2 = 28; b3 = 27; b4 = 26; b5 = 25; b6 = 24; b7 = 23; b8 = 22; + + #50 + + if (c0 !== 5'd31) begin + $display("Test case failed.\nExpected value of c0: %b\tActual value of c0: %b", a0 + b0, c0); + end + if (c1 !== 5'd31) begin + $display("Test case failed.\nExpected value of c1: %b\tActual value of c1: %b", a1 + b1, c1); + end + if (c2 !== 5'd31) begin + $display("Test case failed.\nExpected value of c2: %b\tActual value of c2: %b", a2 + b2, c2); + end + if (c3 !== 5'd31) begin + $display("Test case failed.\nExpected value of c3: %b\tActual value of c3: %b", a3 + b3, c3); + end + if (c4 !== 5'd31) begin + $display("Test case failed.\nExpected value of c4: %b\tActual value of c4: %b", a4 + b4, c4); + end + if (c5 !== 5'd31) begin + $display("Test case failed.\nExpected value of c5: %b\tActual value of c5: %b", a5 + b5, c5); + end + if (c6 !== 5'd31) begin + $display("Test case failed.\nExpected value of c6: %b\tActual value of c6: %b", a6 + b6, c6); + end + if (c7 !== 5'd31) begin + $display("Test case failed.\nExpected value of c7: %b\tActual value of c7: %b", a7 + b7, c7); + end + if (c8 !== 5'd31) begin + $display("Test case failed.\nExpected value of c8: %b\tActual value of c8: %b", a8 + b8, c8); + end + end +endmodule \ No newline at end of file diff --git a/add3by3.v b/add3by3.v new file mode 100644 index 0000000..d10a07a --- /dev/null +++ b/add3by3.v @@ -0,0 +1,41 @@ +/* +Add two 3 by 3 matrix blocks. +Performs the operation A + B = C + +Entries 0 to 8 +of all matrices are arranged in the following order: + + x0 x1 x2 + x3 x4 x5 + x6 x7 x8 + +Inputs: + - a0, ..., a8: the entries of matrix A + - b0, ..., a8: the entries of matrix B +Outputs: + - c0, ..., c8: the entries of matrix C +Parameters: + - ENTRY_SIZE: the number of bits of each matrix entry +*/ + +module add3by3 +#( + parameter ENTRY_SIZE = 5 +)( + input[ENTRY_SIZE - 1:0] a0, a1, a2, a3, + input[ENTRY_SIZE - 1:0] a4, a5, a6, a7, a8, + input[ENTRY_SIZE - 1:0] b0, b1, b2, b3, + input[ENTRY_SIZE - 1:0] b4, b5, b6, b7, b8, + output[ENTRY_SIZE - 1:0] c0, c1, c2, c3, + output[ENTRY_SIZE - 1:0] c4, c5, c6, c7, c8 +); + assign c0 = a0 + b0; + assign c1 = a1 + b1; + assign c2 = a2 + b2; + assign c3 = a3 + b3; + assign c4 = a4 + b4; + assign c5 = a5 + b5; + assign c6 = a6 + b6; + assign c7 = a7 + b7; + assign c8 = a8 + b8; +endmodule \ No newline at end of file From f68ae6a734965cf2b37c7761242a4c4866cfe94b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 14:13:21 -0500 Subject: [PATCH 43/98] Add build targets --- makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 018c52d..3ad5780 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -all: arithmetic dot matrixmultiplication data_mem load_block add_block +all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -18,5 +18,11 @@ load_block: load_block.v load_block.t.v data_mem add_block: add3by3.v add3by3.t.v iverilog -Wall -o add_block add3by3.t.v +registers: registers.v registers.t.v + iverilog -Wall -o registers registers.t.v + +multiplier: multiplier.v multiplier.t.v registers matrixmultiplication + iverilog -Wall -o multiplier multiplier.t.v + fsm: fsm.v fsm.t.v iverilog -Wall -o fsm fsm.t.v From ecbbb459eda934604fcc492bcab8ce8b539fe3ed Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 14:15:02 -0500 Subject: [PATCH 44/98] Implement register + multiplier blocks --- multiplier.t.v | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ multiplier.v | 48 ++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 multiplier.t.v create mode 100644 multiplier.v diff --git a/multiplier.t.v b/multiplier.t.v new file mode 100644 index 0000000..db1c234 --- /dev/null +++ b/multiplier.t.v @@ -0,0 +1,79 @@ +/* +Test bench for the multiplication units +*/ + +`include "multiplier.v" + +module multiplier_TEST(); + parameter ENTRY_SIZE = 5; + parameter RESENTRY_SIZE = ENTRY_SIZE; + + reg clk; + reg a_wrenable; + reg b_wrenable; + reg [ENTRY_SIZE - 1:0] a0_in, a1_in, a2_in, a3_in; + reg [ENTRY_SIZE - 1:0] a4_in, a5_in, a6_in, a7_in, a8_in; + reg [ENTRY_SIZE - 1:0] b0_in, b1_in, b2_in, b3_in; + reg [ENTRY_SIZE - 1:0] b4_in, b5_in, b6_in, b7_in, b8_in; + wire [RESENTRY_SIZE - 1:0] c0_out, c1_out, c2_out, c3_out; + wire [RESENTRY_SIZE - 1:0] c4_out, c5_out, c6_out, c7_out, c8_out; + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) dut ( + .clk(clk), .a_wrenable(a_wrenable), .b_wrenable(b_wrenable), .a0_in(a0_in), .a1_in(a1_in), .a2_in(a2_in), + .a3_in(a3_in), .a4_in(a4_in), .a5_in(a5_in), .a6_in(a6_in), .a7_in(a7_in), .a8_in(a8_in), .b0_in(b0_in), .b1_in(b1_in), .b2_in(b2_in), + .b3_in(b3_in), .b4_in(b4_in), .b5_in(b5_in), .b6_in(b6_in), .b7_in(b7_in), .b8_in(b8_in), .c0_out(c0_out), .c1_out (c1_out), + .c2_out(c2_out), .c3_out(c3_out), .c4_out(c4_out), .c5_out(c5_out), .c6_out(c6_out), .c7_out(c7_out), .c8_out(c8_out) + ); + + initial begin + $dumpfile("multipliler.vcd"); + $dumpvars(); + clk = 0; a_wrenable = 0; b_wrenable = 0; + + a0_in = 5'd1; a1_in = 5'd0; a2_in = 5'd0; + a3_in = 5'd0; a4_in = 5'd1; a5_in = 5'd0; + a6_in = 5'd0; a7_in = 5'd0; a8_in = 5'd1; + + b0_in = 5'd1; b1_in = 5'd2; b2_in = 5'd3; + b3_in = 5'd8; b4_in = 5'd9; b5_in = 5'd10; + b6_in = 5'd15; b7_in = 5'd16; b8_in = 5'd17; + + #50 + + + a_wrenable = 1'b1; b_wrenable = 1'b1; clk = 1; + + #50 + clk = 0; #50 + clk = 1; #50 + if (c0_out !== b0_in) begin + $display("Test failed: c0_out is not the correct value."); + end + if (c1_out !== b1_in) begin + $display("Test failed: c1_out is not the correct value."); + end + if (c2_out !== b2_in) begin + $display("Test failed: c2_out is not the correct value."); + end + if (c3_out !== b3_in) begin + $display("Test failed: c3_out is not the correct value."); + end + if (c4_out !== b4_in) begin + $display("Test failed: c4_out is not the correct value."); + end + if (c5_out !== b5_in) begin + $display("Test failed: c5_out is not the correct value."); + end + if (c6_out !== b6_in) begin + $display("Test failed: c6_out is not the correct value."); + end + if (c7_out !== b7_in) begin + $display("Test failed: c7_out is not the correct value."); + end + if (c8_out !== b8_in) begin + $display("Test failed: c8_out is not the correct value."); + end + + $finish(); + end +endmodule \ No newline at end of file diff --git a/multiplier.v b/multiplier.v new file mode 100644 index 0000000..e3e3a60 --- /dev/null +++ b/multiplier.v @@ -0,0 +1,48 @@ +/* +A block containing a 3 by 3 matrix multiplier and registers +holding the data for both the operands and the result. +*/ + +`include "registers.v" +`include "matrixmultiplication.v" + +module multiplier +#( + parameter ENTRY_SIZE = 5, + parameter RESENTRY_SIZE = 5 +)( + input clk, + input a_wrenable, + input b_wrenable, + input [ENTRY_SIZE - 1:0] a0_in, a1_in, a2_in, a3_in, + input [ENTRY_SIZE - 1:0] a4_in, a5_in, a6_in, a7_in, a8_in, + input [ENTRY_SIZE - 1:0] b0_in, b1_in, b2_in, b3_in, + input [ENTRY_SIZE - 1:0] b4_in, b5_in, b6_in, b7_in, b8_in, + output [RESENTRY_SIZE - 1:0] c0_out, c1_out, c2_out, c3_out, + output [RESENTRY_SIZE - 1:0] c4_out, c5_out, c6_out, c7_out, c8_out +); + wire [ENTRY_SIZE - 1:0] a0_out, a1_out, a2_out, a3_out; + wire [ENTRY_SIZE - 1:0] a4_out, a5_out, a6_out, a7_out, a8_out; + wire [ENTRY_SIZE - 1:0] b0_out, b1_out, b2_out, b3_out; + wire [ENTRY_SIZE - 1:0] b4_out, b5_out, b6_out, b7_out, b8_out; + wire [RESENTRY_SIZE - 1:0] c0_in, c1_in, c2_in, c3_in; + wire [RESENTRY_SIZE - 1:0] c4_in, c5_in, c6_in, c7_in, c8_in; + + regfile #(.width(ENTRY_SIZE)) registers ( + .a_wrenable(a_wrenable), .b_wrenable(b_wrenable), .c_wrenable(1'b1), .a0_in(a0_in), .a1_in(a1_in), .a2_in(a2_in), + .a3_in(a3_in), .a4_in(a4_in), .a5_in(a5_in), .a6_in(a6_in), .a7_in(a7_in), .a8_in(a8_in), + .b0_in(b0_in), .b1_in(b1_in), .b2_in(b2_in), .b3_in(b3_in), .b4_in(b4_in), .b5_in(b5_in), + .b6_in(b6_in), .b7_in(b7_in), .b8_in(b8_in), .c0_in(c0_in), .c1_in(c1_in), .c2_in(c2_in), .c3_in(c3_in), + .c4_in(c4_in), .c5_in(c5_in), .c6_in(c6_in), .c7_in(c7_in), .c8_in(c8_in), .a0_out(a0_out), .a1_out(a1_out), + .a2_out(a2_out), .a3_out(a3_out), .a4_out(a4_out), .a5_out(a5_out), .a6_out(a6_out), .a7_out(a7_out), .a8_out(a8_out), + .b0_out(b0_out), .b1_out(b1_out), .b2_out(b2_out), .b3_out(b3_out), .b4_out(b4_out), .b5_out(b5_out), + .b6_out(b6_out), .b7_out(b7_out), .b8_out(b8_out), .c0_out(c0_out), .c1_out(c1_out), .c2_out(c2_out), .c3_out(c3_out), + .c4_out(c4_out), .c5_out(c5_out), .c6_out(c6_out), .c7_out(c7_out), .c8_out(c8_out), .clk(clk) + ); + + matrixmultiplication3by3 #(.ENTRY_SIZE(ENTRY_SIZE), .RESENTRY_SIZE(RESENTRY_SIZE)) mult ( + .matrixAv1({{a0_out}, {a1_out}, {a2_out}}), .matrixAv2({{a3_out}, {a4_out}, {a5_out}}), .matrixAv3({{a6_out}, {a7_out}, {a8_out}}), + .matrixBv1({{b0_out}, {b1_out}, {b2_out}}), .matrixBv2({{b3_out}, {b4_out}, {b5_out}}), .matrixBv3({{b6_out}, {b7_out}, {b8_out}}), + .matrixCv1({{c0_in}, {c1_in}, {c2_in}}), .matrixCv2({{c3_in}, {c4_in}, {c5_in}}), .matrixCv3({{c6_in}, {c7_in}, {c8_in}}) + ); +endmodule \ No newline at end of file From ad3868aa8309c47403a201b514a0d3a8486087de Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Sun, 10 Dec 2017 15:08:06 -0500 Subject: [PATCH 45/98] added a program memory and a controller which runs through program memory and outputs controll signals based on it --- controller.t.v | 90 +++++++++++++++++++++++++++++++++++++++++++++++++ controller.v | 39 +++++++++++++++++++++ makefile | 7 +++- prog_mem.dat | 65 +++++++++++++++++++++++++++++++++++ prog_memory.t.v | 73 +++++++++++++++++++++++++++++++++++++++ prog_memory.v | 25 ++++++++++++++ run_tests.sh | 4 +++ 7 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 controller.t.v create mode 100644 controller.v create mode 100644 prog_mem.dat create mode 100644 prog_memory.t.v create mode 100644 prog_memory.v diff --git a/controller.t.v b/controller.t.v new file mode 100644 index 0000000..e197b7f --- /dev/null +++ b/controller.t.v @@ -0,0 +1,90 @@ +/* +Test bench for controller module. +*/ + +`include "controller.v" + +module controller_TEST(); + parameter NUM_TESTS = 3; + + reg Clk; + + wire data_we; + wire weA, weB, weC, weD, weE, weF, weG, weH; + wire[1:0] jklm_select; + + controller dut(Clk, data_we, weA, weB, weC, weD, weE, weF, weG, weH, jklm_select); + + reg[5:0] success_count = 0; + + initial Clk = 0; + reg i; + + initial #1000 $finish; + +initial begin + $dumpfile("controller.vcd"); + $dumpvars(); + + #5 + // Test Case 1: command 1 + if (data_we != 0) begin + $display("Test Case 1 Failed: data_we not set correctly"); + end + else if (weA === 1 & {weB, weC, weD, weE, weF, weG, weH} === 7'b0) begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test Case 1 Failed: write enables not set correctly"); + end + + // cycle clock + Clk = 1; + #5 Clk=0; + #5 + + // Test Case 2: command 2 + if (data_we != 0) begin + $display("Test Case 2 Failed: data_we not set correctly"); + end + else if (weB === 1 & {weA, weC, weD, weE, weF, weG, weH} === 7'b0) begin + // test passed + success_count = success_count+1; + end + else begin + $display("Test Case 2 Failed: write enables not set correctly"); + end + + // cycle clock 9 times + for (i=0; i<10; i=i+1) begin + Clk = 1; + #5 Clk=0; + #5; + end + + // Test Case 3: command 11 + if (data_we != 1) begin + $display("Test Case 1 Failed: data_we not set correctly"); + end + else if ( {weA, weB, weC, weD, weE, weF, weG, weH} != 8'b0) begin + $display("Test Case 3 Failed: write enable set on store cmd"); + end + else if (jklm_select != 2'b10) begin + $display("Test Case 3 Failed: mux select incorrect"); + end + else begin + // test passed + success_count = success_count+1; + end + + if (success_count < NUM_TESTS) begin + $display("\nController Failed %d Tests\n",(NUM_TESTS-success_count)); + end + else begin + $display("Controller Passed All %d tests", NUM_TESTS); + end + + +end +endmodule diff --git a/controller.v b/controller.v new file mode 100644 index 0000000..fbc5b73 --- /dev/null +++ b/controller.v @@ -0,0 +1,39 @@ +`include "prog_memory.v" +`include "fsm.v" + +/* +The controller runs through commands from program memory, changing commands +every clock cycle, and outputs the control signals for the various pieces +of the multiplier + +inputs: clk +outputs: same as fsm +*/ + +module controller +#( + parameter CMD_WIDTH = 5, + parameter ADDR_WIDTH = 32 +) +( + input clk, + output data_we, + output weA, weB, weC, weD, weE, weF, weG, weH, + output[1:0] jklm_select +); + + wire[CMD_WIDTH-1:0] cmd; + reg [ADDR_WIDTH-1:0] prog_count; + + // run program counter + initial prog_count = 0; + always @(posedge clk) begin + prog_count = prog_count + 1; + end + + memory prog_mem (clk, cmd, prog_count); + + fsm state_machie (cmd, data_we, weA, weB, weC, weD, weE, weF, weG, weH, + jklm_select); + +endmodule diff --git a/makefile b/makefile index 9f9f5ad..c3b205c 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -all: arithmetic dot matrixmultiplication data_mem load_block +all: arithmetic dot matrixmultiplication data_mem load_block fsm prog_mem controller arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -17,3 +17,8 @@ load_block: load_block.v load_block.t.v data_mem fsm: fsm.v fsm.t.v iverilog -Wall -o fsm fsm.t.v +prog_mem: prog_memory.v prog_memory.t.v + iverilog -Wall -o prog_mem prog_memory.t.v + +controller: controller.v controller.t.v prog_mem fsm + iverilog -Wall -o controller controller.t.v diff --git a/prog_mem.dat b/prog_mem.dat new file mode 100644 index 0000000..52a8a64 --- /dev/null +++ b/prog_mem.dat @@ -0,0 +1,65 @@ +// This is the memory that should be used in the program memory test bench +0_0000 +0_0001 +0_0010 +0_0011 +0_0100 +0_0101 +0_0110 +0_0111 +0_1000 +0_1001 +0_1010 +0_1011 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 diff --git a/prog_memory.t.v b/prog_memory.t.v new file mode 100644 index 0000000..32ae209 --- /dev/null +++ b/prog_memory.t.v @@ -0,0 +1,73 @@ +/* +Test bench for program memory module. +*/ + +`include "prog_memory.v" + +module memory_TEST(); + parameter ENTRY_SIZE = 5; + parameter ADDRESS_WIDTH = 32; + parameter NUM_TESTS = 3; + + reg clk; + reg [ADDRESS_WIDTH - 1:0] addr; + + wire [ENTRY_SIZE - 1:0] data; + + memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) dut( + .clk(clk), .data(data), + .addr(addr) + ); + + reg[5:0] success_count = 0; + + initial clk = 0; + always #10 clk = !clk; + initial begin + $dumpfile("prog_memory.vcd"); + $dumpvars(0, memory_TEST, dut.memory[0]); + + + // Test Case 1: Read first memory element + addr = 32'd0; + #20 + if (data === 5'b0) begin + success_count = success_count + 1; + end + else begin + $display("Test case 1 failed: expected %b got %b", 5'b0, data); + end + + // Test Case 2: Read second memory element + addr = 32'd1; + #20 + if (data === 5'b1) begin + success_count = success_count + 1; + end + else begin + $display("Test case 2 failed: expected %b got %b", 5'b1, data); + end + + // Test Case 3: Read tenth memory element + addr = 32'd9; + #20 + if (data === 5'b01001) begin + success_count = success_count + 1; + end + else begin + $display("Test case 3 failed: expected %b got %b", 5'b01001, data); + end + + #10 + + if (success_count < NUM_TESTS) begin + $display("\nProgram Memory Failed %d Tests\n",(NUM_TESTS-success_count)); + end + else begin + $display("Program Memory Passed All %d tests", NUM_TESTS); + end + + + $finish; + end +endmodule diff --git a/prog_memory.v b/prog_memory.v new file mode 100644 index 0000000..5f61c61 --- /dev/null +++ b/prog_memory.v @@ -0,0 +1,25 @@ +/* +The memory where matrices are stored. +*/ + +// TODO (arianaolson419): Allow multiple data access in some fashion. +module memory +#( + parameter addresswidth = 32, + parameter depth = addresswidth * 2, + parameter width = 5 +) +( + input clk, + output [width-1:0] data, + input [addresswidth-1:0] addr +); + + + reg [width-1:0] memory [depth-1:0]; + + + initial $readmemb("prog_mem.dat", memory); + assign data = memory[addr]; + +endmodule diff --git a/run_tests.sh b/run_tests.sh index 8bd4a20..5e3a260 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -17,3 +17,7 @@ echo "Running load block tests..." ./load_block echo "running fsm tests..." ./fsm +echo "running program memory tests..." +./prog_mem +echo "running controller tests..." +./controller From 7412acd0cc24286e1d5ca27c0c9b16887361a0b9 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 15:44:55 -0500 Subject: [PATCH 46/98] Fix spelling error --- multiplier.t.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multiplier.t.v b/multiplier.t.v index db1c234..50fdb5b 100644 --- a/multiplier.t.v +++ b/multiplier.t.v @@ -26,7 +26,7 @@ module multiplier_TEST(); ); initial begin - $dumpfile("multipliler.vcd"); + $dumpfile("multiplier.vcd"); $dumpvars(); clk = 0; a_wrenable = 0; b_wrenable = 0; From 32a06c75521fd316eab3ad09fb79cfc00c895ff3 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 15:49:54 -0500 Subject: [PATCH 47/98] Implement multiplication --- multiplier_network.v | 206 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 multiplier_network.v diff --git a/multiplier_network.v b/multiplier_network.v new file mode 100644 index 0000000..f85ca74 --- /dev/null +++ b/multiplier_network.v @@ -0,0 +1,206 @@ +/* +Network of 8 multiplier units +*/ + +`include "multiplier.v" +`include "add3by3.v" +`include "multiplexer.v" + +module multiplier_network + #(parameter ENTRY_SIZE = 5)( + input clk, + input [1:0] res_sel, + input a_wrenable, + input b_wrenable, + input c_wrenable, + input d_wrenable, + input e_wrenable, + input f_wrenable, + input g_wrenable, + input h_wrenable, + input [ENTRY_SIZE - 1:0] ae0_in, ae1_in, ae2_in, + input [ENTRY_SIZE - 1:0] ae3_in, ae4_in, ae5_in, + input [ENTRY_SIZE - 1:0] ae6_in, ae7_in, ae8_in, + input [ENTRY_SIZE - 1:0] af0_in, af1_in, af2_in, + input [ENTRY_SIZE - 1:0] af3_in, af4_in, af5_in, + input [ENTRY_SIZE - 1:0] af6_in, af7_in, af8_in, + input [ENTRY_SIZE - 1:0] bg0_in, bg1_in, bg2_in, + input [ENTRY_SIZE - 1:0] bg3_in, bg4_in, bg5_in, + input [ENTRY_SIZE - 1:0] bg6_in, bg7_in, bg8_in, + input [ENTRY_SIZE - 1:0] bh0_in, bh1_in, bh2_in, + input [ENTRY_SIZE - 1:0] bh3_in, bh4_in, bh5_in, + input [ENTRY_SIZE - 1:0] bh6_in, bh7_in, bh8_in, + input [ENTRY_SIZE - 1:0] ce0_in, ce1_in, ce2_in, + input [ENTRY_SIZE - 1:0] ce3_in, ce4_in, ce5_in, + input [ENTRY_SIZE - 1:0] ce6_in, ce7_in, ce8_in, + input [ENTRY_SIZE - 1:0] cf0_in, cf1_in, cf2_in, + input [ENTRY_SIZE - 1:0] cf3_in, cf4_in, cf5_in, + input [ENTRY_SIZE - 1:0] cf6_in, cf7_in, cf8_in, + input [ENTRY_SIZE - 1:0] dg0_in, dg1_in, dg2_in, + input [ENTRY_SIZE - 1:0] dg3_in, dg4_in, dg5_in, + input [ENTRY_SIZE - 1:0] dg6_in, dg7_in, dg8_in, + input [ENTRY_SIZE - 1:0] dh0_in, dh1_in, dh2_in, + input [ENTRY_SIZE - 1:0] dh3_in, dh4_in, dh5_in, + input [ENTRY_SIZE - 1:0] dh6_in, dh7_in, dh8_in, + output [(9 * ENTRY_SIZE) - 1:0] res +); + + + wire [ENTRY_SIZE - 1:0] ae0, ae1, ae2; + wire [ENTRY_SIZE - 1:0] ae3, ae4, ae5; + wire [ENTRY_SIZE - 1:0] ae6, ae7, ae8; + wire [ENTRY_SIZE - 1:0] af0, af1, af2; + wire [ENTRY_SIZE - 1:0] af3, af4, af5; + wire [ENTRY_SIZE - 1:0] af6, af7, af8; + wire [ENTRY_SIZE - 1:0] bg0, bg1, bg2; + wire [ENTRY_SIZE - 1:0] bg3, bg4, bg5; + wire [ENTRY_SIZE - 1:0] bg6, bg7, bg8; + wire [ENTRY_SIZE - 1:0] bh0, bh1, bh2; + wire [ENTRY_SIZE - 1:0] bh3, bh4, bh5; + wire [ENTRY_SIZE - 1:0] bh6, bh7, bh8; + wire [ENTRY_SIZE - 1:0] ce0, ce1, ce2; + wire [ENTRY_SIZE - 1:0] ce3, ce4, ce5; + wire [ENTRY_SIZE - 1:0] ce6, ce7, ce8; + wire [ENTRY_SIZE - 1:0] cf0, cf1, cf2; + wire [ENTRY_SIZE - 1:0] cf3, cf4, cf5; + wire [ENTRY_SIZE - 1:0] cf6, cf7, cf8; + wire [ENTRY_SIZE - 1:0] dg0, dg1, dg2; + wire [ENTRY_SIZE - 1:0] dg3, dg4, dg5; + wire [ENTRY_SIZE - 1:0] dg6, dg7, dg8; + wire [ENTRY_SIZE - 1:0] dh0, dh1, dh2; + wire [ENTRY_SIZE - 1:0] dh3, dh4, dh5; + wire [ENTRY_SIZE - 1:0] dh6, dh7, dh8; + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) AE ( + .clk(clk), .a_wrenable(a_wrenable), .b_wrenable(e_wrenable), + .a0_in(ae0_in), .a1_in(ae1_in), .a2_in(ae2_in), .a3_in(ae3_in), + .a4_in(ae4_in), .a5_in(ae5_in), .a6_in(ae6_in), .a7_in(ae7_in), .a8_in(ae8_in), + .b0_in(ae0_in), .b1_in(ae1_in), .b2_in(ae2_in), .b3_in(ae3_in), + .b4_in(ae4_in), .b5_in(ae5_in), .b6_in(ae6_in), .b7_in(ae7_in), .b8_in(ae8_in), + .c0_out(ae0), .c1_out(ae1), .c2_out(ae2), .c3_out(ae3), + .c4_out(ae4), .c5_out(ae5), .c6_out(ae6), .c7_out(ae7), .c8_out(ae8) + ); + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) AF ( + .clk(clk), .a_wrenable(a_wrenable), .b_wrenable(f_wrenable), + .a0_in(af0_in), .a1_in(af1_in), .a2_in(af2_in), .a3_in(af3_in), + .a4_in(af4_in), .a5_in(af5_in), .a6_in(af6_in), .a7_in(af7_in), .a8_in(af8_in), + .b0_in(af0_in), .b1_in(af1_in), .b2_in(af2_in), .b3_in(af3_in), + .b4_in(af4_in), .b5_in(af5_in), .b6_in(af6_in), .b7_in(af7_in), .b8_in(af8_in), + .c0_out(af0), .c1_out(af1), .c2_out(af2), .c3_out(af3), + .c4_out(af4), .c5_out(af5), .c6_out(af6), .c7_out(af7), .c8_out(af8) + ); + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) BG ( + .clk(clk), .a_wrenable(b_wrenable), .b_wrenable(g_wrenable), + .a0_in(bg0_in), .a1_in(bg1_in), .a2_in(bg2_in), .a3_in(bg3_in), + .a4_in(bg4_in), .a5_in(bg5_in), .a6_in(bg6_in), .a7_in(bg7_in), .a8_in(bg8_in), + .b0_in(bg0_in), .b1_in(bg1_in), .b2_in(bg2_in), .b3_in(bg3_in), + .b4_in(bg4_in), .b5_in(bg5_in), .b6_in(bg6_in), .b7_in(bg7_in), .b8_in(bg8_in), + .c0_out(bg0), .c1_out(bg1), .c2_out(bg2), .c3_out(bg3), + .c4_out(bg4), .c5_out(bg5), .c6_out(bg6), .c7_out(bg7), .c8_out(bg8) + ); + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) BH ( + .clk(clk), .a_wrenable(b_wrenable), .b_wrenable(h_wrenable), + .a0_in(bh0_in), .a1_in(bh1_in), .a2_in(bh2_in), .a3_in(bh3_in), + .a4_in(bh4_in), .a5_in(bh5_in), .a6_in(bh6_in), .a7_in(bh7_in), .a8_in(bh8_in), + .b0_in(bh0_in), .b1_in(bh1_in), .b2_in(bh2_in), .b3_in(bh3_in), + .b4_in(bh4_in), .b5_in(bh5_in), .b6_in(bh6_in), .b7_in(bh7_in), .b8_in(bh8_in), + .c0_out(bh0), .c1_out(bh1), .c2_out(bh2), .c3_out(bh3), + .c4_out(bh4), .c5_out(bh5), .c6_out(bh6), .c7_out(bh7), .c8_out(bh8) + ); + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) CE ( + .clk(clk), .a_wrenable(c_wrenable), .b_wrenable(e_wrenable), + .a0_in(ce0_in), .a1_in(ce1_in), .a2_in(ce2_in), .a3_in(ce3_in), + .a4_in(ce4_in), .a5_in(ce5_in), .a6_in(ce6_in), .a7_in(ce7_in), .a8_in(ce8_in), + .b0_in(ce0_in), .b1_in(ce1_in), .b2_in(ce2_in), .b3_in(ce3_in), + .b4_in(ce4_in), .b5_in(ce5_in), .b6_in(ce6_in), .b7_in(ce7_in), .b8_in(ce8_in), + .c0_out(ce0), .c1_out(ce1), .c2_out(ce2), .c3_out(ce3), + .c4_out(ce4), .c5_out(ce5), .c6_out(ce6), .c7_out(ce7), .c8_out(ce8) + ); + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) CF ( + .clk(clk), .a_wrenable(c_wrenable), .b_wrenable(f_wrenable), + .a0_in(cf0_in), .a1_in(cf1_in), .a2_in(cf2_in), .a3_in(cf3_in), + .a4_in(cf4_in), .a5_in(cf5_in), .a6_in(cf6_in), .a7_in(cf7_in), .a8_in(cf8_in), + .b0_in(cf0_in), .b1_in(cf1_in), .b2_in(cf2_in), .b3_in(cf3_in), + .b4_in(cf4_in), .b5_in(cf5_in), .b6_in(cf6_in), .b7_in(cf7_in), .b8_in(cf8_in), + .c0_out(cf0), .c1_out(cf1), .c2_out(cf2), .c3_out(cf3), + .c4_out(cf4), .c5_out(cf5), .c6_out(cf6), .c7_out(cf7), .c8_out(cf8) + ); + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) DG ( + .clk(clk), .a_wrenable(d_wrenable), .b_wrenable(g_wrenable), + .a0_in(dg0_in), .a1_in(dg1_in), .a2_in(dg2_in), .a3_in(dg3_in), + .a4_in(dg4_in), .a5_in(dg5_in), .a6_in(dg6_in), .a7_in(dg7_in), .a8_in(dg8_in), + .b0_in(dg0_in), .b1_in(dg1_in), .b2_in(dg2_in), .b3_in(dg3_in), + .b4_in(dg4_in), .b5_in(dg5_in), .b6_in(dg6_in), .b7_in(dg7_in), .b8_in(dg8_in), + .c0_out(dg0), .c1_out(dg1), .c2_out(dg2), .c3_out(dg3), + .c4_out(dg4), .c5_out(dg5), .c6_out(dg6), .c7_out(dg7), .c8_out(dg8) + ); + + multiplier #(.ENTRY_SIZE(ENTRY_SIZE)) DH ( + .clk(clk), .a_wrenable(d_wrenable), .b_wrenable(h_wrenable), + .a0_in(dh0_in), .a1_in(dh1_in), .a2_in(dh2_in), .a3_in(dh3_in), + .a4_in(dh4_in), .a5_in(dh5_in), .a6_in(dh6_in), .a7_in(dh7_in), .a8_in(dh8_in), + .b0_in(dh0_in), .b1_in(dh1_in), .b2_in(dh2_in), .b3_in(dh3_in), + .b4_in(dh4_in), .b5_in(dh5_in), .b6_in(dh6_in), .b7_in(dh7_in), .b8_in(dh8_in), + .c0_out(dh0), .c1_out(dh1), .c2_out(dh2), .c3_out(dh3), + .c4_out(dh4), .c5_out(dh5), .c6_out(dh6), .c7_out(dh7), .c8_out(dh8) + ); + + wire [ENTRY_SIZE - 1:0] ae_bg_sum0, ae_bg_sum1, ae_bg_sum2; + wire [ENTRY_SIZE - 1:0] ae_bg_sum3, ae_bg_sum4, ae_bg_sum5; + wire [ENTRY_SIZE - 1:0] ae_bg_sum6, ae_bg_sum7, ae_bg_sum8; + wire [ENTRY_SIZE - 1:0] af_bh_sum0, af_bh_sum1, af_bh_sum2; + wire [ENTRY_SIZE - 1:0] af_bh_sum3, af_bh_sum4, af_bh_sum5; + wire [ENTRY_SIZE - 1:0] af_bh_sum6, af_bh_sum7, af_bh_sum8; + wire [ENTRY_SIZE - 1:0] ce_dg_sum0, ce_dg_sum1, ce_dg_sum2; + wire [ENTRY_SIZE - 1:0] ce_dg_sum3, ce_dg_sum4, ce_dg_sum5; + wire [ENTRY_SIZE - 1:0] ce_dg_sum6, ce_dg_sum7, ce_dg_sum8; + wire [ENTRY_SIZE - 1:0] cf_dh_sum0, cf_dh_sum1, cf_dh_sum2; + wire [ENTRY_SIZE - 1:0] cf_dh_sum3, cf_dh_sum4, cf_dh_sum5; + wire [ENTRY_SIZE - 1:0] cf_dh_sum6, cf_dh_sum7, cf_dh_sum8; + + add3by3 #(.ENTRY_SIZE(ENTRY_SIZE)) AEplusBG ( + .a0(ae0), .a1(ae1), .a2(ae2), .a3(ae3), .a4(ae4), .a5(ae5), .a6(ae6), .a7(ae7), .a8(ae8), + .b0(bg0), .b1(bg1), .b2(bg2), .b3(bg3), .b4(bg4), .b5(bg5), .b6(bg6), .b7(bg7), .b8(bg8), + .c0(ae_bg_sum0), .c1(ae_bg_sum1), .c2(ae_bg_sum2), .c3(ae_bg_sum3), .c4(ae_bg_sum4), + .c5(ae_bg_sum5), .c6(ae_bg_sum6), .c7(ae_bg_sum7), .c8(ae_bg_sum8) + ); + + add3by3 #(.ENTRY_SIZE(ENTRY_SIZE)) AFplusBH ( + .a0(af0), .a1(af1), .a2(af2), .a3(af3), .a4(af4), .a5(af5), .a6(af6), .a7(af7), .a8(af8), + .b0(bh0), .b1(bh1), .b2(bh2), .b3(bh3), .b4(bh4), .b5(bh5), .b6(bh6), .b7(bh7), .b8(bh8), + .c0(af_bh_sum0), .c1(af_bh_sum1), .c2(af_bh_sum2), .c3(af_bh_sum3), .c4(af_bh_sum4), + .c5(af_bh_sum5), .c6(af_bh_sum6), .c7(af_bh_sum7), .c8(af_bh_sum8) + ); + + add3by3 #(.ENTRY_SIZE(ENTRY_SIZE)) CEplusDG ( + .a0(ce0), .a1(ce1), .a2(ce2), .a3(ce3), .a4(ce4), .a5(ce5), .a6(ce6), .a7(ce7), .a8(ce8), + .b0(dg0), .b1(dg1), .b2(dg2), .b3(dg3), .b4(dg4), .b5(dg5), .b6(dg6), .b7(dg7), .b8(dg8), + .c0(ce_dg_sum0), .c1(ce_dg_sum1), .c2(ce_dg_sum2), .c3(ce_dg_sum3), .c4(ce_dg_sum4), + .c5(ce_dg_sum5), .c6(ce_dg_sum6), .c7(ce_dg_sum7), .c8(ce_dg_sum8) + ); + + add3by3 #(.ENTRY_SIZE(ENTRY_SIZE)) CFplusDH ( + .a0(cf0), .a1(cf1), .a2(cf2), .a3(cf3), .a4(cf4), .a5(cf5), .a6(cf6), .a7(cf7), .a8(cf8), + .b0(dh0), .b1(dh1), .b2(dh2), .b3(dh3), .b4(dh4), .b5(dh5), .b6(dh6), .b7(dh7), .b8(dh8), + .c0(cf_dh_sum0), .c1(cf_dh_sum1), .c2(cf_dh_sum2), .c3(cf_dh_sum3), .c4(cf_dh_sum4), + .c5(cf_dh_sum5), .c6(cf_dh_sum6), .c7(cf_dh_sum7), .c8(cf_dh_sum8) + ); + + `define AEBG {{ae_bg_sum0}, {ae_bg_sum1}, {ae_bg_sum2}, {ae_bg_sum3}, {ae_bg_sum4}, {ae_bg_sum5}, {ae_bg_sum6}, {ae_bg_sum7}, {ae_bg_sum8}} + `define AFBH {{af_bh_sum0}, {af_bh_sum1}, {af_bh_sum2}, {af_bh_sum3}, {af_bh_sum4}, {af_bh_sum5}, {af_bh_sum6}, {af_bh_sum7}, {af_bh_sum8}} + `define CEDG {{ce_dg_sum0}, {ce_dg_sum1}, {ce_dg_sum2}, {ce_dg_sum3}, {ce_dg_sum4}, {ce_dg_sum5}, {ce_dg_sum6}, {ce_dg_sum7}, {ce_dg_sum8}} + `define CFDH {{cf_dh_sum0}, {cf_dh_sum1}, {cf_dh_sum2}, {cf_dh_sum3}, {cf_dh_sum4}, {cf_dh_sum5}, {cf_dh_sum6}, {cf_dh_sum7}, {cf_dh_sum8}} + + multiplexer4to1 #( + .ENTRY_SIZE(ENTRY_SIZE)) chooseres (.res_sel (res_sel), .AEplusBG(`AEBG), .AFplusBH(`AFBH), + .CEplusDG(`CEDG), .CFplusDH(`CFDH), .result (res) + ); + + +endmodule // multiplier_network \ No newline at end of file From 09153109fded470e60be0e8f2f17cea7e553f1a6 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 18:02:25 -0500 Subject: [PATCH 48/98] Create multiplexer for multiplication results --- multiplexer.t.v | 44 ++++++++++++++++++++++++++++++++++++++++++++ multiplexer.v | 19 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 multiplexer.t.v create mode 100644 multiplexer.v diff --git a/multiplexer.t.v b/multiplexer.t.v new file mode 100644 index 0000000..2386d09 --- /dev/null +++ b/multiplexer.t.v @@ -0,0 +1,44 @@ +/* +Test bench for 4 to 1 multiplexer +*/ + +`include "multiplexer.v" + +module multiplexer4to1_TEST(); + parameter ENTRY_SIZE = 5; + + reg [1:0] res_sel; + reg[(ENTRY_SIZE * 9) - 1:0] A, B, C, D; + wire [(ENTRY_SIZE * 9) - 1:0] result; + + multiplexer4to1 #(.ENTRY_SIZE(ENTRY_SIZE)) dut ( + .res_sel(res_sel), .AEplusBG(A), .AFplusBH(B), .CEplusDG(C), .CFplusDH(D), .result(result) + ); + + initial begin + A = {9{5'b00001}}; B = {9{5'b00010}}; C = {9{5'b00100}}; D = {9{5'b01000}}; + res_sel = 2'b00; #50 + + if (result !== A) begin + $display("Test failed: input 0 not selected"); + end + + res_sel = 2'b01; #50 + + if (result !== B) begin + $display("Test failed: input 1 not selected"); + end + + res_sel = 2'b10; #50 + + if (result !== C) begin + $display("Test failed: input 2 not selected"); + end + + res_sel = 2'b11; #50 + + if (result !== D) begin + $display("Test failed: input 3 not selected"); + end + end +endmodule // multiplexer4to1_TEST \ No newline at end of file diff --git a/multiplexer.v b/multiplexer.v new file mode 100644 index 0000000..90eb9c2 --- /dev/null +++ b/multiplexer.v @@ -0,0 +1,19 @@ +/* +4 input multiplexer +*/ + +module multiplexer4to1 +#(parameter ENTRY_SIZE = 5)( + input[1:0] res_sel, + input [(9 * ENTRY_SIZE) - 1:0] AEplusBG, AFplusBH, CEplusDG, CFplusDH, + output reg [(9 * ENTRY_SIZE) - 1:0] result +); + always @(res_sel) begin + case (res_sel) + 2'b00: begin result = AEplusBG; end + 2'b01: begin result = AFplusBH; end + 2'b10: begin result = CEplusDG; end + 2'b11: begin result = CFplusDH; end + endcase + end +endmodule \ No newline at end of file From f018baf3f3a9d254a85f1bfbfea72eddc0029bcc Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 18:04:00 -0500 Subject: [PATCH 49/98] Add build targets --- makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 3ad5780..f367860 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,4 @@ -all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers +all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -26,3 +26,6 @@ multiplier: multiplier.v multiplier.t.v registers matrixmultiplication fsm: fsm.v fsm.t.v iverilog -Wall -o fsm fsm.t.v + +multiplexer: multiplexer.v multiplexer.t.v + iverilog -Wall -o multiplexer multiplexer.t.v From 64e5c2b1dd35905a34374270b6fa08c66bb72e53 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 18:04:39 -0500 Subject: [PATCH 50/98] Test network --- multiplier_network.t.v | 460 +++++++++++++++++++++++++++++++++++++++++ multiplier_network.v | 2 - 2 files changed, 460 insertions(+), 2 deletions(-) create mode 100644 multiplier_network.t.v diff --git a/multiplier_network.t.v b/multiplier_network.t.v new file mode 100644 index 0000000..f9a5f3c --- /dev/null +++ b/multiplier_network.t.v @@ -0,0 +1,460 @@ +/* +Test bench for multiplier network +*/ + +`include "multiplier_network.v" + +module multiplier_network_TEST(); + parameter ENTRY_SIZE = 5; + reg clk, a_wrenable, b_wrenable, c_wrenable, d_wrenable; + reg e_wrenable, f_wrenable, g_wrenable, h_wrenable; + reg [1:0] res_sel; + + reg [ENTRY_SIZE - 1:0] ae0_in, ae1_in, ae2_in; + reg [ENTRY_SIZE - 1:0] ae3_in, ae4_in, ae5_in; + reg [ENTRY_SIZE - 1:0] ae6_in, ae7_in, ae8_in; + + reg [ENTRY_SIZE - 1:0] af0_in, af1_in, af2_in; + reg [ENTRY_SIZE - 1:0] af3_in, af4_in, af5_in; + reg [ENTRY_SIZE - 1:0] af6_in, af7_in, af8_in; + + reg [ENTRY_SIZE - 1:0] bg0_in, bg1_in, bg2_in; + reg [ENTRY_SIZE - 1:0] bg3_in, bg4_in, bg5_in; + reg [ENTRY_SIZE - 1:0] bg6_in, bg7_in, bg8_in; + + reg [ENTRY_SIZE - 1:0] bh0_in, bh1_in, bh2_in; + reg [ENTRY_SIZE - 1:0] bh3_in, bh4_in, bh5_in; + reg [ENTRY_SIZE - 1:0] bh6_in, bh7_in, bh8_in; + + reg [ENTRY_SIZE - 1:0] ce0_in, ce1_in, ce2_in; + reg [ENTRY_SIZE - 1:0] ce3_in, ce4_in, ce5_in; + reg [ENTRY_SIZE - 1:0] ce6_in, ce7_in, ce8_in; + + reg [ENTRY_SIZE - 1:0] cf0_in, cf1_in, cf2_in; + reg [ENTRY_SIZE - 1:0] cf3_in, cf4_in, cf5_in; + reg [ENTRY_SIZE - 1:0] cf6_in, cf7_in, cf8_in; + + reg [ENTRY_SIZE - 1:0] dg0_in, dg1_in, dg2_in; + reg [ENTRY_SIZE - 1:0] dg3_in, dg4_in, dg5_in; + reg [ENTRY_SIZE - 1:0] dg6_in, dg7_in, dg8_in; + + reg [ENTRY_SIZE - 1:0] dh0_in, dh1_in, dh2_in; + reg [ENTRY_SIZE - 1:0] dh3_in, dh4_in, dh5_in; + reg [ENTRY_SIZE - 1:0] dh6_in, dh7_in, dh8_in; + + wire [(9 * ENTRY_SIZE) - 1:0] result; + + multiplier_network #(.ENTRY_SIZE(ENTRY_SIZE)) dut ( + .clk(clk), .a_wrenable(a_wrenable), .b_wrenable(b_wrenable), .c_wrenable(c_wrenable), + .d_wrenable(d_wrenable), .e_wrenable(e_wrenable), .f_wrenable(f_wrenable), + .g_wrenable(g_wrenable), .h_wrenable(h_wrenable), .res_sel (res_sel), .ae0_in (ae0_in), .ae1_in (ae1_in), + .ae2_in (ae2_in), .ae3_in (ae3_in), .ae4_in (ae4_in), .ae5_in (ae5_in), .ae6_in (ae6_in), .ae7_in (ae7_in), + .ae8_in (ae8_in), .af0_in (af0_in), .af1_in (af1_in), .af2_in (af2_in), .af3_in (af3_in), .af4_in (af4_in), + .af5_in (af5_in), .af6_in (af6_in), .af7_in (af7_in), .af8_in (af8_in), .bg0_in (bg0_in), .bg1_in (bg1_in), + .bg2_in (bg2_in), .bg3_in (bg3_in), .bg4_in (bg4_in), .bg5_in (bg5_in), .bg6_in (bg6_in), .bg7_in (bg7_in), + .bg8_in (bg8_in), .bh0_in (bh0_in), .bh1_in (bh1_in), .bh2_in (bh2_in), .bh3_in (bh3_in), .bh4_in (bh4_in), + .bh5_in (bh5_in), .bh6_in (bh6_in), .bh7_in (bh7_in), .bh8_in (bh8_in), .ce0_in (ce0_in), .ce1_in (ce1_in), + .ce2_in (ce2_in), .ce3_in (ce3_in), .ce4_in (ce4_in), .ce5_in (ce5_in), .ce6_in (ce6_in), .ce7_in (ce7_in), + .ce8_in (ce8_in), .cf0_in (cf0_in), .cf1_in (cf1_in), .cf2_in (cf2_in), .cf3_in (cf3_in), .cf4_in (cf4_in), + .cf5_in (cf5_in), .cf6_in (cf6_in), .cf7_in (cf7_in), .cf8_in (cf8_in), .dg0_in (dg0_in), .dg1_in (dg1_in), + .dg2_in (dg2_in), .dg3_in (dg3_in), .dg4_in (dg4_in), .dg5_in (dg5_in), .dg6_in (dg6_in), .dg7_in (dg7_in), + .dg8_in (dg8_in), .dh0_in (dh0_in), .dh1_in (dh1_in), .dh2_in (dh2_in), .dh3_in (dh3_in), .dh4_in (dh4_in), + .dh5_in (dh5_in), .dh6_in (dh6_in), .dh7_in (dh7_in), .dh8_in (dh8_in), .res (result) + ); + + `define FALSE 1'b0 + `define TRUE 1'b1 + + `define ZERO 5'b00000 + `define ONE 5'b00001 + + `define ZERO_MAT {9{`ZERO}} + `define ONE_MAT {9{`ONE}} + `define ID_MAT {{`ONE}, {`ZERO}, {`ZERO}, {`ZERO}, {`ONE}, {`ZERO}, {`ZERO}, {`ZERO}, {`ONE}} + `define MIX_MAT {{`ONE}, {`ONE}, {`ZERO}, {`ZERO}, {`ONE}, {`ZERO}, {`ZERO}, {`ONE}, {`ONE}} + + `define J 2'b00 + `define K 2'b01 + `define L 2'b10 + `define M 2'b11 + + initial begin + $dumpfile("multiplier_network.vcd"); + $dumpvars(); + a_wrenable = `FALSE; b_wrenable = `FALSE; c_wrenable = `FALSE; d_wrenable = `FALSE; + e_wrenable = `FALSE; f_wrenable = `FALSE; g_wrenable = `FALSE; h_wrenable = `FALSE; + + // Load the submatrices of matrix "A" + clk = 0; a_wrenable = `TRUE; b_wrenable = `TRUE; c_wrenable = `TRUE; d_wrenable = `TRUE; #50 + + // A + ae0_in = `ONE; ae1_in = `ZERO; ae2_in = `ZERO; + ae3_in = `ZERO; ae4_in = `ONE; ae5_in = `ZERO; + ae6_in = `ZERO; ae7_in = `ZERO; ae8_in = `ONE; + + af0_in = `ONE; af1_in = `ZERO; af2_in = `ZERO; + af3_in = `ZERO; af4_in = `ONE; af5_in = `ZERO; + af6_in = `ZERO; af7_in = `ZERO; af8_in = `ONE; + + // B + bg0_in = `ZERO; bg1_in = `ZERO; bg2_in = `ZERO; + bg3_in = `ZERO; bg4_in = `ZERO; bg5_in = `ZERO; + bg6_in = `ZERO; bg7_in = `ZERO; bg8_in = `ZERO; + + bh0_in = `ZERO; bh1_in = `ZERO; bh2_in = `ZERO; + bh3_in = `ZERO; bh4_in = `ZERO; bh5_in = `ZERO; + bh6_in = `ZERO; bh7_in = `ZERO; bh8_in = `ZERO; + + // C + ce0_in = `ZERO; ce1_in = `ZERO; ce2_in = `ZERO; + ce3_in = `ZERO; ce4_in = `ZERO; ce5_in = `ZERO; + ce6_in = `ZERO; ce7_in = `ZERO; ce8_in = `ZERO; + + cf0_in = `ZERO; cf1_in = `ZERO; cf2_in = `ZERO; + cf3_in = `ZERO; cf4_in = `ZERO; cf5_in = `ZERO; + cf6_in = `ZERO; cf7_in = `ZERO; cf8_in = `ZERO; + + // D + dg0_in = `ONE; dg1_in = `ZERO; dg2_in = `ZERO; + dg3_in = `ZERO; dg4_in = `ONE; dg5_in = `ZERO; + dg6_in = `ZERO; dg7_in = `ZERO; dg8_in = `ONE; + + dh0_in = `ONE; dh1_in = `ZERO; dh2_in = `ZERO; + dh3_in = `ZERO; dh4_in = `ONE; dh5_in = `ZERO; + dh6_in = `ZERO; dh7_in = `ZERO; dh8_in = `ONE; + + clk = 1; #50 + + a_wrenable = `FALSE; b_wrenable = `FALSE; c_wrenable = `FALSE; d_wrenable = `FALSE; + + // Test correct loading of A + if ( + {{dut.AE.a0_out}, {dut.AE.a1_out}, {dut.AE.a2_out}, + {dut.AE.a3_out}, {dut.AE.a4_out}, {dut.AE.a5_out}, + {dut.AE.a6_out}, {dut.AE.a7_out}, {dut.AE.a8_out}} !== `ID_MAT + ) begin + $display("Test failed: wrong values loaded into A of AE"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.AE.a0_out, dut.AE.a1_out, dut.AE.a2_out, + dut.AE.a3_out, dut.AE.a4_out, dut.AE.a5_out, + dut.AE.a6_out, dut.AE.a7_out, dut.AE.a8_out + ); + end + + if ( + {{dut.AF.a0_out}, {dut.AF.a1_out}, {dut.AF.a2_out}, + {dut.AF.a3_out}, {dut.AF.a4_out}, {dut.AF.a5_out}, + {dut.AF.a6_out}, {dut.AF.a7_out}, {dut.AF.a8_out}} !== `ID_MAT + ) begin + $display("Test failed: wrong values loaded into A of AF"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.AF.a0_out, dut.AF.a1_out, dut.AF.a2_out, + dut.AF.a3_out, dut.AF.a4_out, dut.AF.a5_out, + dut.AF.a6_out, dut.AF.a7_out, dut.AF.a8_out + ); + end + + // Test correct loading of B + if ( + {{dut.BG.a0_out}, {dut.BG.a1_out}, {dut.BG.a2_out}, + {dut.BG.a3_out}, {dut.BG.a4_out}, {dut.BG.a5_out}, + {dut.BG.a6_out}, {dut.BG.a7_out}, {dut.BG.a8_out}} !== `ZERO_MAT + ) begin + $display("Test failed: wrong values loaded into B of BG"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.BG.a0_out, dut.BG.a1_out, dut.BG.a2_out, + dut.BG.a3_out, dut.BG.a4_out, dut.BG.a5_out, + dut.BG.a6_out, dut.BG.a7_out, dut.BG.a8_out + ); + end + + if ( + {{dut.BH.a0_out}, {dut.BH.a1_out}, {dut.BH.a2_out}, + {dut.BH.a3_out}, {dut.BH.a4_out}, {dut.BH.a5_out}, + {dut.BH.a6_out}, {dut.BH.a7_out}, {dut.BH.a8_out}} !== `ZERO_MAT + ) begin + $display("Test failed: wrong values loaded into B of BH"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.BH.a0_out, dut.BH.a1_out, dut.BH.a2_out, + dut.BH.a3_out, dut.BH.a4_out, dut.BH.a5_out, + dut.BH.a6_out, dut.BH.a7_out, dut.BH.a8_out + ); + end + + // Test correct loading of C + if ( + {{dut.CE.a0_out}, {dut.CE.a1_out}, {dut.CE.a2_out}, + {dut.CE.a3_out}, {dut.CE.a4_out}, {dut.CE.a5_out}, + {dut.CE.a6_out}, {dut.CE.a7_out}, {dut.CE.a8_out}} !== `ZERO_MAT + ) begin + $display("Test failed: wrong values loaded into C of CE"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.CE.a0_out, dut.CE.a1_out, dut.CE.a2_out, + dut.CE.a3_out, dut.CE.a4_out, dut.CE.a5_out, + dut.CE.a6_out, dut.CE.a7_out, dut.CE.a8_out + ); + end + + if ( + {{dut.CF.a0_out}, {dut.CF.a1_out}, {dut.CF.a2_out}, + {dut.CF.a3_out}, {dut.CF.a4_out}, {dut.CF.a5_out}, + {dut.CF.a6_out}, {dut.CF.a7_out}, {dut.CF.a8_out}} !== `ZERO_MAT + ) begin + $display("Test failed: wrong values loaded into C of CF"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.CF.a0_out, dut.CF.a1_out, dut.CF.a2_out, + dut.CF.a3_out, dut.CF.a4_out, dut.CF.a5_out, + dut.CF.a6_out, dut.CF.a7_out, dut.CF.a8_out + ); + end + + // Test correct loading of D + if ( + {{dut.DG.a0_out}, {dut.DG.a1_out}, {dut.DG.a2_out}, + {dut.DG.a3_out}, {dut.DG.a4_out}, {dut.DG.a5_out}, + {dut.DG.a6_out}, {dut.DG.a7_out}, {dut.DG.a8_out}} !== `ID_MAT + ) begin + $display("Test failed: wrong values loaded into D of DG"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.DG.a0_out, dut.DG.a1_out, dut.DG.a2_out, + dut.DG.a3_out, dut.DG.a4_out, dut.DG.a5_out, + dut.DG.a6_out, dut.DG.a7_out, dut.DG.a8_out + ); + end + + if ( + {{dut.DH.a0_out}, {dut.DH.a1_out}, {dut.DH.a2_out}, + {dut.DH.a3_out}, {dut.DH.a4_out}, {dut.DH.a5_out}, + {dut.DH.a6_out}, {dut.DH.a7_out}, {dut.DH.a8_out}} !== `ID_MAT + ) begin + $display("Test failed: wrong values loaded into D of DH"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.DH.a0_out, dut.DH.a1_out, dut.DH.a2_out, + dut.DH.a3_out, dut.DH.a4_out, dut.DH.a5_out, + dut.DH.a6_out, dut.DH.a7_out, dut.DH.a8_out + ); + end + + // Load submatrices of matrix "B" + clk = 0; e_wrenable = `TRUE; f_wrenable = `TRUE; g_wrenable = `TRUE; h_wrenable = `TRUE; #50 + + // E + ae0_in = `ONE; ae1_in = `ONE; ae2_in = `ZERO; + ae3_in = `ZERO; ae4_in = `ONE; ae5_in = `ZERO; + ae6_in = `ZERO; ae7_in = `ONE; ae8_in = `ONE; + + ce0_in = `ONE; ce1_in = `ONE; ce2_in = `ZERO; + ce3_in = `ZERO; ce4_in = `ONE; ce5_in = `ZERO; + ce6_in = `ZERO; ce7_in = `ONE; ce8_in = `ONE; + + // F + af0_in = `ONE; af1_in = `ONE; af2_in = `ONE; + af3_in = `ONE; af4_in = `ONE; af5_in = `ONE; + af6_in = `ONE; af7_in = `ONE; af8_in = `ONE; + + cf0_in = `ONE; cf1_in = `ONE; cf2_in = `ONE; + cf3_in = `ONE; cf4_in = `ONE; cf5_in = `ONE; + cf6_in = `ONE; cf7_in = `ONE; cf8_in = `ONE; + + // G + bg0_in = `ONE; bg1_in = `ONE; bg2_in = `ZERO; + bg3_in = `ZERO; bg4_in = `ONE; bg5_in = `ZERO; + bg6_in = `ZERO; bg7_in = `ONE; bg8_in = `ONE; + + dg0_in = `ONE; dg1_in = `ONE; dg2_in = `ZERO; + dg3_in = `ZERO; dg4_in = `ONE; dg5_in = `ZERO; + dg6_in = `ZERO; dg7_in = `ONE; dg8_in = `ONE; + + // H + bh0_in = `ONE; bh1_in = `ONE; bh2_in = `ONE; + bh3_in = `ONE; bh4_in = `ONE; bh5_in = `ONE; + bh6_in = `ONE; bh7_in = `ONE; bh8_in = `ONE; + + dh0_in = `ONE; dh1_in = `ONE; dh2_in = `ONE; + dh3_in = `ONE; dh4_in = `ONE; dh5_in = `ONE; + dh6_in = `ONE; dh7_in = `ONE; dh8_in = `ONE; + + clk = 1; #50 + + e_wrenable = `FALSE; f_wrenable = `FALSE; g_wrenable = `FALSE; h_wrenable = `FALSE; + + clk = 0; + + // Test correct loading of E + if ( + {{dut.AE.b0_out}, {dut.AE.b1_out}, {dut.AE.b2_out}, + {dut.AE.b3_out}, {dut.AE.b4_out}, {dut.AE.b5_out}, + {dut.AE.b6_out}, {dut.AE.b7_out}, {dut.AE.b8_out}} !== `MIX_MAT + ) begin + $display("Test failed: wrong values loaded into E of AE"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.AE.b0_out, dut.AE.b1_out, dut.AE.b2_out, + dut.AE.b3_out, dut.AE.b4_out, dut.AE.b5_out, + dut.AE.b6_out, dut.AE.b7_out, dut.AE.b8_out + ); + end + + if ( + {{dut.CE.b0_out}, {dut.CE.b1_out}, {dut.CE.b2_out}, + {dut.CE.b3_out}, {dut.CE.b4_out}, {dut.CE.b5_out}, + {dut.CE.b6_out}, {dut.CE.b7_out}, {dut.CE.b8_out}} !== `MIX_MAT + ) begin + $display("Test failed: wrong values loaded into E of CE"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.CE.b0_out, dut.CE.b1_out, dut.CE.b2_out, + dut.CE.b3_out, dut.CE.b4_out, dut.CE.b5_out, + dut.CE.b6_out, dut.CE.b7_out, dut.CE.b8_out + ); + end + + // Test correct loading of F + if ( + {{dut.AF.b0_out}, {dut.AF.b1_out}, {dut.AF.b2_out}, + {dut.AF.b3_out}, {dut.AF.b4_out}, {dut.AF.b5_out}, + {dut.AF.b6_out}, {dut.AF.b7_out}, {dut.AF.b8_out}} !== `ONE_MAT + ) begin + $display("Test failed: wrong values loaded into F of AF"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.AF.b0_out, dut.AF.b1_out, dut.AF.b2_out, + dut.AF.b3_out, dut.AF.b4_out, dut.AF.b5_out, + dut.AF.b6_out, dut.AF.b7_out, dut.AF.b8_out + ); + end + + if ( + {{dut.CF.b0_out}, {dut.CF.b1_out}, {dut.CF.b2_out}, + {dut.CF.b3_out}, {dut.CF.b4_out}, {dut.CF.b5_out}, + {dut.CF.b6_out}, {dut.CF.b7_out}, {dut.CF.b8_out}} !== `ONE_MAT + ) begin + $display("Test failed: wrong values loaded into F of CF"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.CF.b0_out, dut.CF.b1_out, dut.CF.b2_out, + dut.CF.b3_out, dut.CF.b4_out, dut.CF.b5_out, + dut.CF.b6_out, dut.CF.b7_out, dut.CF.b8_out + ); + end + + + // Test correct loading of G + if ( + {{dut.BG.b0_out}, {dut.BG.b1_out}, {dut.BG.b2_out}, + {dut.BG.b3_out}, {dut.BG.b4_out}, {dut.BG.b5_out}, + {dut.BG.b6_out}, {dut.BG.b7_out}, {dut.BG.b8_out}} !== `MIX_MAT + ) begin + $display("Test failed: wrong values loaded into G of BG"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.BG.b0_out, dut.BG.b1_out, dut.BG.b2_out, + dut.BG.b3_out, dut.BG.b4_out, dut.BG.b5_out, + dut.BG.b6_out, dut.BG.b7_out, dut.BG.b8_out + ); + end + + if ( + {{dut.DG.b0_out}, {dut.DG.b1_out}, {dut.DG.b2_out}, + {dut.DG.b3_out}, {dut.DG.b4_out}, {dut.DG.b5_out}, + {dut.DG.b6_out}, {dut.DG.b7_out}, {dut.DG.b8_out}} !== `MIX_MAT + ) begin + $display("Test failed: wrong values loaded into G of DG"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.DG.b0_out, dut.DG.b1_out, dut.DG.b2_out, + dut.DG.b3_out, dut.DG.b4_out, dut.DG.b5_out, + dut.DG.b6_out, dut.DG.b7_out, dut.DG.b8_out + ); + end + + // Test correct loading of H + if ( + {{dut.BH.b0_out}, {dut.BH.b1_out}, {dut.BH.b2_out}, + {dut.BH.b3_out}, {dut.BH.b4_out}, {dut.BH.b5_out}, + {dut.BH.b6_out}, {dut.BH.b7_out}, {dut.BH.b8_out}} !== `ONE_MAT + ) begin + $display("Test failed: wrong values loaded into H of BH"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.BH.b0_out, dut.BH.b1_out, dut.BH.b2_out, + dut.BH.b3_out, dut.BH.b4_out, dut.BH.b5_out, + dut.BH.b6_out, dut.BH.b7_out, dut.BH.b8_out + ); + end + + if ( + {{dut.DH.b0_out}, {dut.DH.b1_out}, {dut.DH.b2_out}, + {dut.DH.b3_out}, {dut.DH.b4_out}, {dut.DH.b5_out}, + {dut.DH.b6_out}, {dut.DH.b7_out}, {dut.DH.b8_out}} !== `ONE_MAT + ) begin + $display("Test failed: wrong values loaded into H of DH"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + dut.DH.b0_out, dut.DH.b1_out, dut.DH.b2_out, + dut.DH.b3_out, dut.DH.b4_out, dut.DH.b5_out, + dut.DH.b6_out, dut.DH.b7_out, dut.DH.b8_out + ); + end + + clk = 0; #50 + clk = 1; + res_sel = `J; #10 + if (result !== `MIX_MAT) begin + $display("Test failed: submatrix J contains wrong values"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + result[(9 * ENTRY_SIZE) - 1: (8 * ENTRY_SIZE)], + result[(8 * ENTRY_SIZE) - 1: (7 * ENTRY_SIZE)], + result[(7 * ENTRY_SIZE) - 1: (6 * ENTRY_SIZE)], + result[(6 * ENTRY_SIZE) - 1: (5 * ENTRY_SIZE)], + result[(5 * ENTRY_SIZE) - 1: (4 * ENTRY_SIZE)], + result[(4 * ENTRY_SIZE) - 1: (3 * ENTRY_SIZE)], + result[(3 * ENTRY_SIZE) - 1: (2 * ENTRY_SIZE)], + result[(2 * ENTRY_SIZE) - 1: (1 * ENTRY_SIZE)], + result[(1 * ENTRY_SIZE) - 1: (0 * ENTRY_SIZE)] + ); + end + + res_sel = `K; #10 + if (result !== `ONE_MAT) begin + $display("Test failed: submatrix K contains wrong values"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + result[(9 * ENTRY_SIZE) - 1: (8 * ENTRY_SIZE)], + result[(8 * ENTRY_SIZE) - 1: (7 * ENTRY_SIZE)], + result[(7 * ENTRY_SIZE) - 1: (6 * ENTRY_SIZE)], + result[(6 * ENTRY_SIZE) - 1: (5 * ENTRY_SIZE)], + result[(5 * ENTRY_SIZE) - 1: (4 * ENTRY_SIZE)], + result[(4 * ENTRY_SIZE) - 1: (3 * ENTRY_SIZE)], + result[(3 * ENTRY_SIZE) - 1: (2 * ENTRY_SIZE)], + result[(2 * ENTRY_SIZE) - 1: (1 * ENTRY_SIZE)], + result[(1 * ENTRY_SIZE) - 1: (0 * ENTRY_SIZE)] + ); + end + + res_sel = `L; #10 + if (result !== `MIX_MAT) begin + $display("Test failed: submatrix L contains wrong values"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + result[(9 * ENTRY_SIZE) - 1: (8 * ENTRY_SIZE)], + result[(8 * ENTRY_SIZE) - 1: (7 * ENTRY_SIZE)], + result[(7 * ENTRY_SIZE) - 1: (6 * ENTRY_SIZE)], + result[(6 * ENTRY_SIZE) - 1: (5 * ENTRY_SIZE)], + result[(5 * ENTRY_SIZE) - 1: (4 * ENTRY_SIZE)], + result[(4 * ENTRY_SIZE) - 1: (3 * ENTRY_SIZE)], + result[(3 * ENTRY_SIZE) - 1: (2 * ENTRY_SIZE)], + result[(2 * ENTRY_SIZE) - 1: (1 * ENTRY_SIZE)], + result[(1 * ENTRY_SIZE) - 1: (0 * ENTRY_SIZE)] + ); + end + + res_sel = `M; #10 + if (result !== `ONE_MAT) begin + $display("Test failed: submatrix M contains wrong values"); + $display("\t%d\t%d\t%d\n\t%d\t%d\t%d\n\t%d\t%d\t%d", + result[(9 * ENTRY_SIZE) - 1: (8 * ENTRY_SIZE)], + result[(8 * ENTRY_SIZE) - 1: (7 * ENTRY_SIZE)], + result[(7 * ENTRY_SIZE) - 1: (6 * ENTRY_SIZE)], + result[(6 * ENTRY_SIZE) - 1: (5 * ENTRY_SIZE)], + result[(5 * ENTRY_SIZE) - 1: (4 * ENTRY_SIZE)], + result[(4 * ENTRY_SIZE) - 1: (3 * ENTRY_SIZE)], + result[(3 * ENTRY_SIZE) - 1: (2 * ENTRY_SIZE)], + result[(2 * ENTRY_SIZE) - 1: (1 * ENTRY_SIZE)], + result[(1 * ENTRY_SIZE) - 1: (0 * ENTRY_SIZE)] + ); + end + + $finish; + end +endmodule // multiplier_network_TEST \ No newline at end of file diff --git a/multiplier_network.v b/multiplier_network.v index f85ca74..d928889 100644 --- a/multiplier_network.v +++ b/multiplier_network.v @@ -201,6 +201,4 @@ module multiplier_network .ENTRY_SIZE(ENTRY_SIZE)) chooseres (.res_sel (res_sel), .AEplusBG(`AEBG), .AFplusBH(`AFBH), .CEplusDG(`CEDG), .CFplusDH(`CFDH), .result (res) ); - - endmodule // multiplier_network \ No newline at end of file From f47d703f180eaf6e96f520c8713c07e90194b068 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Sun, 10 Dec 2017 18:13:26 -0500 Subject: [PATCH 51/98] Add multiplier_network target --- makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/makefile b/makefile index 3657261..a3d23d6 100644 --- a/makefile +++ b/makefile @@ -1,5 +1,5 @@ -all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller +all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller multiplier_network arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -36,3 +36,6 @@ prog_mem: prog_memory.v prog_memory.t.v controller: controller.v controller.t.v prog_mem fsm iverilog -Wall -o controller controller.t.v + +multiplier_network: multiplier_network.v multiplier_network.t.v multiplexer multiplier add3by3 + iverilog -Wall -o multiplier_network multiplier_network.t.v From e4875416e05a9c9e5719fc51811b4af051de64ec Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 03:20:56 -0500 Subject: [PATCH 52/98] added additional things to fsm that i needed --- controller.t.v | 104 +++++++++++++++++++++++++++++-------------------- controller.v | 5 ++- data_memory.v | 6 +-- fsm.t.v | 62 ++++++++++++++++++++++------- fsm.v | 13 ++++++- makefile | 8 ++-- run_tests.sh | 20 +++++----- 7 files changed, 142 insertions(+), 76 deletions(-) diff --git a/controller.t.v b/controller.t.v index e197b7f..d9b0bef 100644 --- a/controller.t.v +++ b/controller.t.v @@ -5,77 +5,98 @@ Test bench for controller module. `include "controller.v" module controller_TEST(); - parameter NUM_TESTS = 3; - - reg Clk; + parameter NUM_TESTS = 3; + + reg Clk; wire data_we; wire weA, weB, weC, weD, weE, weF, weG, weH; wire[1:0] jklm_select; + wire next_row, column; - controller dut(Clk, data_we, weA, weB, weC, weD, weE, weF, weG, weH, jklm_select); - - reg[5:0] success_count = 0; + controller dut(Clk, data_we, weA, weB, weC, weD, weE, weF, weG, weH, jklm_select, next_row, column); + + reg[5:0] success_count = 0; - initial Clk = 0; - reg i; - - initial #1000 $finish; + initial Clk = 0; + integer i; + + initial #1000 $finish; initial begin - $dumpfile("controller.vcd"); - $dumpvars(); + $dumpfile("controller.vcd"); + $dumpvars(); - #5 - // Test Case 1: command 1 + #5 + // Test Case 1: command 1 if (data_we != 0) begin $display("Test Case 1 Failed: data_we not set correctly"); end - else if (weA === 1 & {weB, weC, weD, weE, weF, weG, weH} === 7'b0) begin - // test passed - success_count = success_count+1; + else if (weA !== 1 & {weB, weC, weD, weE, weF, weG, weH} !== 7'b0) begin + $display("Test Case 1 Failed: write enables not set correctly"); + end + else if (next_row != 0) begin + $display("Test Case 1 Failed: next row is signalled incorrectly"); + end + else if (column != 0) begin + $display("Test Case 1 Failed: column is signalled incorrectly"); end else begin - $display("Test Case 1 Failed: write enables not set correctly"); + // test passed + success_count = success_count+1; end - // cycle clock - Clk = 1; - #5 Clk=0; - #5 - // Test Case 2: command 2 + // cycle clock + Clk = 1; + #5 Clk=0; + #5 + + // Test Case 2: command 2 if (data_we != 0) begin $display("Test Case 2 Failed: data_we not set correctly"); end - else if (weB === 1 & {weA, weC, weD, weE, weF, weG, weH} === 7'b0) begin - // test passed - success_count = success_count+1; + else if (weB !== 1 & {weA, weC, weD, weE, weF, weG, weH} !== 7'b0) begin + $display("Test Case 2 Failed: write enables not set correctly"); + end + else if (next_row != 1) begin + $display("Test Case 2 Failed: next row is signalled incorrectly"); + end + else if (column != 0) begin + $display("Test Case 2 Failed: column is signalled incorrectly"); end else begin - $display("Test Case 2 Failed: write enables not set correctly"); + // test passed + success_count = success_count+1; end - // cycle clock 9 times - for (i=0; i<10; i=i+1) begin - Clk = 1; - #5 Clk=0; - #5; - end + // cycle clock 9 times + for (i=0; i<9; i=i+1) begin + Clk = 1; + #5 Clk=0; + #5; + end - // Test Case 3: command 11 + // Test Case 3: command 11 if (data_we != 1) begin - $display("Test Case 1 Failed: data_we not set correctly"); + $display("Test Case 3 Failed: data_we not set correctly"); end else if ( {weA, weB, weC, weD, weE, weF, weG, weH} != 8'b0) begin - $display("Test Case 3 Failed: write enable set on store cmd"); - end - else if (jklm_select != 2'b10) begin - $display("Test Case 3 Failed: mux select incorrect"); - end - else begin + $display("Test Case 3 Failed: write enable set on store cmd"); + end + else if (jklm_select != 2'b10) begin + $display("Test Case 3 Failed: mux select incorrect"); + end + else if (next_row != 0) begin + $display("Test Case 3 Failed: next row is signalled incorrectly"); + end + else if (column != 1) begin + $display("Test Case 3 Failed: column is signalled incorrectly"); + end + else begin // test passed success_count = success_count+1; + $display("what"); end if (success_count < NUM_TESTS) begin @@ -85,6 +106,5 @@ initial begin $display("Controller Passed All %d tests", NUM_TESTS); end - end endmodule diff --git a/controller.v b/controller.v index fbc5b73..3a59e35 100644 --- a/controller.v +++ b/controller.v @@ -19,7 +19,8 @@ module controller input clk, output data_we, output weA, weB, weC, weD, weE, weF, weG, weH, - output[1:0] jklm_select + output[1:0] jklm_select, + output next_row, column ); wire[CMD_WIDTH-1:0] cmd; @@ -34,6 +35,6 @@ module controller memory prog_mem (clk, cmd, prog_count); fsm state_machie (cmd, data_we, weA, weB, weC, weD, weE, weF, weG, weH, - jklm_select); + jklm_select, next_row, column); endmodule diff --git a/data_memory.v b/data_memory.v index 71d21f0..e134f39 100644 --- a/data_memory.v +++ b/data_memory.v @@ -9,9 +9,9 @@ module memory parameter width = 32 ) ( - input clk, - output [width-1:0] data0, data1, data2, data3, data4, - output [width-1:0] data5, data6, data7, data8, + input clk, + output [width-1:0] data0, data1, data2, data3, data4, + output [width-1:0] data5, data6, data7, data8, input [addresswidth-1:0] addr0, addr1, addr2, addr3, addr4, input [addresswidth-1:0] addr5, addr6, addr7, addr8, input writeEnable, diff --git a/fsm.t.v b/fsm.t.v index 5f9d9eb..e662e09 100644 --- a/fsm.t.v +++ b/fsm.t.v @@ -7,13 +7,17 @@ module fsm_TEST(); wire data_we; wire weA, weB, weC, weD, weE, weF, weG, weH; wire[1:0] jklm_sel; + wire next_row; + wire column; fsm dut ( .command(command), .data_we(data_we), .weA(weA), .weB(weB), .weC(weC), .weD(weD), .weE(weE), .weF(weF), .weG(weG), .weH(weH), - .jklm_select(jklm_sel) + .jklm_select(jklm_sel), + .next_row(next_row), + .column(column) ); reg[5:0] success_count = 0; @@ -29,12 +33,18 @@ module fsm_TEST(); if (data_we != 0) begin $display("Test Case 1 Failed: data_we not set correctly"); end - else if (weA === 1 & {weB, weC, weD, weE, weF, weG, weH} === 7'b0) begin - // test passed - success_count = success_count+1; + else if (weA !== 1 & {weB, weC, weD, weE, weF, weG, weH} !== 7'b0) begin + $display("Test Case 1 Failed: write enables not set correctly"); + end + else if (next_row != 0) begin + $display("Test Case 1 Failed: next row is signalled incorrectly"); + end + else if (column != 0) begin + $display("Test Case 1 Failed: column is signalled incorrectly"); end else begin - $display("Test Case 1 Failed: write enables not set correctly"); + // test passed + success_count = success_count+1; end // Test Case 2: load to block C @@ -44,12 +54,18 @@ module fsm_TEST(); if (data_we != 0) begin $display("Test Case 2 Failed: data_we not set correctly"); end - else if (weD === 1 & {weA, weB, weC, weE, weF, weG, weH} === 7'b0) begin - // test passed - success_count = success_count+1; + else if (weD !== 1 & {weA, weB, weC, weE, weF, weG, weH} !== 7'b0) begin + $display("Test Case 2 Failed: write enables not set correctly"); + end + else if (next_row != 1) begin + $display("Test Case 2 Failed: next row is signalled incorrectly"); + end + else if (column != 0) begin + $display("Test Case 2 Failed: column is signalled incorrectly"); end else begin - $display("Test Case 2 Failed: write enables not set correctly"); + // test passed + success_count = success_count+1; end // Test Case 3: load to block H @@ -57,14 +73,20 @@ module fsm_TEST(); #10 if (data_we != 0) begin - $display("Test Case 1 Failed: data_we not set correctly"); + $display("Test Case 3 Failed: data_we not set correctly"); end - else if (weH === 1 & {weA, weB, weC, weD, weE, weF, weG} === 7'b0) begin - // test passed - success_count = success_count+1; + else if (weH !== 1 & {weA, weB, weC, weD, weE, weF, weG} !== 7'b0) begin + $display("Test Case 3 Failed: write enables not set correctly"); + end + else if (next_row != 1) begin + $display("Test Case 3 Failed: next row is signalled incorrectly"); + end + else if (column != 1) begin + $display("Test Case 3 Failed: column is signalled incorrectly"); end else begin - $display("Test Case 3 Failed: write enables not set correctly"); + // test passed + success_count = success_count+1; end // Test Case 4: store from block J @@ -80,6 +102,12 @@ module fsm_TEST(); else if (jklm_sel != 2'b00) begin $display("Test Case 4 Failed: jklm_select not correct"); end + else if (next_row != 0) begin + $display("Test Case 4 Failed: next row is signalled incorrectly"); + end + else if (column != 1) begin + $display("Test Case 4 Failed: column is signalled incorrectly"); + end else begin // test passed success_count = success_count+1; @@ -98,6 +126,12 @@ module fsm_TEST(); else if (jklm_sel != 2'b11) begin $display("Test Case 5 Failed: jklm_select not correct"); end + else if (next_row != 1) begin + $display("Test Case 5 Failed: next row is signalled incorrectly"); + end + else if (column != 1) begin + $display("Test Case 5 Failed: column is signalled incorrectly"); + end else begin // test passed success_count = success_count+1; diff --git a/fsm.v b/fsm.v index 00d1c55..b6071bc 100644 --- a/fsm.v +++ b/fsm.v @@ -1,7 +1,7 @@ /* Manages the control signals throught the matrix multiplier based on an input command -commad structure: +command structure: |type|block| | 0 0|0 0 0| @@ -16,6 +16,8 @@ Outputs: - data_we: write enable for the data memory - weA-weH: write enables for each input to the computation blocks - jklm_select: select bits for mux on the output matricies + - next_row: signals to the matrix manager to go to a new row of the matrix + - column: tells the matrix manager to use the column quantity for the first matrix (0), or the second and result matrices (1) */ module fsm @@ -27,7 +29,9 @@ parameter BLOCK_LEN = 3 input[TYPE_LEN+BLOCK_LEN-1:0] command, output data_we, output weA, weB, weC, weD, weE, weF, weG, weH, - output[1:0] jklm_select + output[1:0] jklm_select, + output next_row, + output column ); wire[TYPE_LEN-1:0] type; @@ -37,6 +41,11 @@ parameter BLOCK_LEN = 3 wire[BLOCK_LEN-1:0] block; assign block = command[BLOCK_LEN-1:0]; + // signaling the next row currently only works because we only use 6x6 matrices + assign next_row = block[0]; + + assign column = (block[2] && !type[0]) || type[0]; // 1 when we are using the second matrix or result + assign jklm_select = block[1:0]; // last two bits of block select which matrix to store // decoder to enable loading of selected block diff --git a/makefile b/makefile index 3ca7f54..46c23da 100644 --- a/makefile +++ b/makefile @@ -1,4 +1,7 @@ -all: arithmetic dot matrixmultiplication registers data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller +all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller + +clean: + rm arithmetic dot matmul data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -9,9 +12,6 @@ dot: dot.v dot.t.v arithmetic matrixmultiplication: matrixmultiplication.v matrixmultiplication.t.v dot iverilog -Wall -o matmul matrixmultiplication.t.v -registers: registers.v registers.t.v - iverilog -Wall -o registers registers.t.v - data_mem: data_memory.v data_memory.t.v iverilog -Wall -o data_mem data_memory.t.v diff --git a/run_tests.sh b/run_tests.sh index a1316ae..9882c52 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -5,21 +5,23 @@ make echo "Running all module tests:" cat mem_test_data.dat > matrix_mem.dat -echo "Running data memory tests..." +echo " Running data memory tests..." ./data_mem -echo "Running arithmetic tests..." +echo " Running arithmetic tests..." ./arithmetic -echo "Running dot tests..." +echo " Running dot tests..." ./dot -echo "Running matmul tests..." +echo " Running matmul tests..." ./matmul -echo "Running register tests..." +echo " Running register tests..." ./registers -echo "Running load block tests..." +echo " Running load block tests..." ./load_block -echo "running fsm tests..." +echo " Running fsm tests..." ./fsm -echo "running program memory tests..." +echo " Running program memory tests..." ./prog_mem -echo "running controller tests..." +echo " Running controller tests..." ./controller + +make clean From 584f13037260b9a39cf8f9d5211e5571b4bc33ca Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 16:31:06 -0500 Subject: [PATCH 53/98] update targets --- makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index a3d23d6..5f9f178 100644 --- a/makefile +++ b/makefile @@ -8,7 +8,7 @@ dot: dot.v dot.t.v arithmetic iverilog -Wall -o dot dot.t.v matrixmultiplication: matrixmultiplication.v matrixmultiplication.t.v dot - iverilog -Wall -o matmul matrixmultiplication.t.v + iverilog -Wall -o matrixmultiplication matrixmultiplication.t.v data_mem: data_memory.v data_memory.t.v iverilog -Wall -o data_mem data_memory.t.v @@ -37,5 +37,5 @@ prog_mem: prog_memory.v prog_memory.t.v controller: controller.v controller.t.v prog_mem fsm iverilog -Wall -o controller controller.t.v -multiplier_network: multiplier_network.v multiplier_network.t.v multiplexer multiplier add3by3 +multiplier_network: multiplier_network.v multiplier_network.t.v multiplexer multiplier add_block iverilog -Wall -o multiplier_network multiplier_network.t.v From 4fed8984c89ca5a14182c2b118da8471934ab0d3 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 16:31:18 -0500 Subject: [PATCH 54/98] Add tests --- run_tests.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/run_tests.sh b/run_tests.sh index 5e3a260..22b81eb 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -12,12 +12,22 @@ echo "Running arithmetic tests..." echo "Running dot tests..." ./dot echo "Running matmul tests..." -./matmul +./matrixmultiplication echo "Running load block tests..." ./load_block +echo "Running add block tests..." +./add_block +echo "Running registers tests..." +./registers +echo "Running multiplier tests..." +./multiplier +echo "Running multiplexer tests..." +./multiplexer echo "running fsm tests..." ./fsm echo "running program memory tests..." ./prog_mem echo "running controller tests..." ./controller +echo "Running multiplier_network tests..." +./multiplier_network \ No newline at end of file From a928244d342361e3de497f3a0fbffbbb8fedd58e Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 17:22:09 -0500 Subject: [PATCH 55/98] Put modules together --- multiplier6by6.v | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 multiplier6by6.v diff --git a/multiplier6by6.v b/multiplier6by6.v new file mode 100644 index 0000000..e52069f --- /dev/null +++ b/multiplier6by6.v @@ -0,0 +1,53 @@ +/* +FFFFFF +*/ + +`include "controller.v" +`include "matrix_manager.v" +`include "multiplier_network.v" + +module multiplier6by6( + input clk, +); + wire data_we; + wire weA, weB, weC, weD, weE, weF, weG, weH; + wire jklm_select; + wire next_row, column; + + wire[4:0] dataOut0, dataOut1, dataOut2, dataOut3, dataOut4, dataOut5, dataOut6, dataOut7, dataOut8; + + wire[44:0] result; + + controller control (.clk(clk), .data_we(data_we), .weA(weA), + .weB(weB), .weC(weC), .weD(weD), .weE(weE), .weF(weF), + .weG(weG), .weH(weH), .jklm_select(jklm_select), + .next_row(next_row), .column(column)); + + multiplier_network network ( + .clk(clk),.res_sel(jklm_select), .a_wrenable(weA), .b_wrenable(weB), + .c_wrenable(weC), .d_wrenable(weD), .e_wrenable(weE), .f_wrenable(weF), .g_wrenable(weG), .h_wrenable(weH), + .ae0_in(dataOut0), .ae1_in(dataOut1), .ae2_in(dataOut2), .ae3_in(dataOut3), .ae4_in(dataOut4), .ae5_in(dataOut5), + .ae6_in(dataOut6), .ae7_in(dataOut7), .ae8_in(dataOut8), + .af0_in(dataOut0), .af1_in(dataOut1), .af2_in(dataOut2), .af3_in(dataOut3), .af4_in(dataOut4), .af5_in(dataOut5), + .af6_in(dataOut6), .af7_in(dataOut7), .af8_in(dataOut8), + .bg0_in(dataOut0), .bg1_in(dataOut1), .bg2_in(dataOut2), .bg3_in(dataOut3), .bg4_in(dataOut4), .bg5_in(dataOut5), + .bg6_in(dataOut6), .bg7_in(dataOut7), .bg8_in(dataOut8), + .bh0_in(dataOut0), .bh1_in(dataOut1), .bh2_in(dataOut2), .bh3_in(dataOut3), .bh4_in(dataOut4), .bh5_in(dataOut5), + .bh6_in(dataOut6), .bh7_in(dataOut7), .bh8_in(dataOut8), + .ce0_in(dataOut0), .ce1_in(dataOut1), .ce2_in(dataOut2), .ce3_in(dataOut3), .ce4_in(dataOut4), .ce5_in(dataOut5), + .ce6_in(dataOut6), .ce7_in(dataOut7), .ce8_in(dataOut8), + .cf0_in(dataOut0), .cf1_in(dataOut1), .cf2_in(dataOut2), .cf3_in(dataOut3), .cf4_in(dataOut4), .cf5_in(dataOut5), + .cf6_in(dataOut6), .cf7_in(dataOut7), .cf8_in(dataOut8), + .dg0_in(dataOut0), .dg1_in(dataOut1), .dg2_in(dataOut2), .dg3_in(dataOut3), .dg4_in(dataOut4), .dg5_in(dataOut5), + .dg6_in(dataOut6), .dg7_in(dataOut7), .dg8_in(dataOut8), + .dh0_in(dataOut0), .dh1_in(dataOut1), .dh2_in(dataOut2), .dh3_in(dataOut3), .dh4_in(dataOut4), .dh5_in(dataOut5), + .dh6_in(dataOut6), .dh7_in(dataOut7), .dh8_in(dataOut8), .res(result) + ); + + matrix_manager #(.ADDR_WIDTH = 32) manager (.clk(clk), .dm_we(data_we), + .next_row(next_row), .column(column), .n(6), .m(6), .p(6), .dataIn0 (result[4:0]), .dataIn1 (result[9:5]), + .dataIn2 (result[14:10]), .dataIn3 (result[19:15]), .dataIn4 (result[24:20]), .dataIn5 (result[29:25]), .dataIn6 (result[34:30]), + .dataIn7 (result[39:35]), .dataIn8 (result[44:40]), .dataOut0(dataOut0), .dataOut1(dataOut1), + .dataOut2(dataOut2), .dataOut3(dataOut3), .dataOut4(dataOut4), .dataOut5(dataOut5), + .dataOut6(dataOut6), .dataOut7(dataOut7), .dataOut8(dataOut8)); +endmodule \ No newline at end of file From ac2b6007977ed626a4665affeebbdbc22acf8211 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 19:54:38 -0500 Subject: [PATCH 56/98] finished matrix manager, but there is a bug in dm --- data_memory.v | 5 +++ makefile | 7 +++- matrix_manager.t.v | 72 ++++++++++++++++++++++++++++++++++ matrix_manager.v | 85 +++++++++++++++++++++++++++++++++++++++++ matrix_manager_test.dat | 65 +++++++++++++++++++++++++++++++ matrix_mem.dat | 64 +++++++++++++++---------------- run_tests.sh | 5 ++- 7 files changed, 268 insertions(+), 35 deletions(-) create mode 100644 matrix_manager.t.v create mode 100644 matrix_manager.v create mode 100644 matrix_manager_test.dat diff --git a/data_memory.v b/data_memory.v index e134f39..427f417 100644 --- a/data_memory.v +++ b/data_memory.v @@ -22,7 +22,12 @@ module memory reg [width-1:0] memory [depth-1:0]; + integer i; + always @(negedge clk) begin + // for (i = 0; i < 100; i= i+1) + // $display(memory[i]); + // $display("dm"); if(writeEnable) memory[addr0 >> 2] <= dataIn0; memory[addr1 >> 2] <= dataIn1; diff --git a/makefile b/makefile index 46c23da..94d0105 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ -all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller +all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager clean: - rm arithmetic dot matmul data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller + rm arithmetic dot matmul data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -38,3 +38,6 @@ prog_mem: prog_memory.v prog_memory.t.v controller: controller.v controller.t.v prog_mem fsm iverilog -Wall -o controller controller.t.v + +matrix_manager: matrix_manager.v matrix_manager.t.v data_mem registers load_block + iverilog -Wall -o matrix_manager matrix_manager.t.v \ No newline at end of file diff --git a/matrix_manager.t.v b/matrix_manager.t.v new file mode 100644 index 0000000..9041dda --- /dev/null +++ b/matrix_manager.t.v @@ -0,0 +1,72 @@ +`include "matrix_manager.v" + +/* +Since I dont' have direect access to the contents of memory, I can't adequately test writing data. +*/ + +module matrixmanagertest(); + +reg clk; + +reg dm_we, next_row, column; +reg[9:0] n, m, p; + +reg[4:0] dataIn0, dataIn1, dataIn2, dataIn3, dataIn4, dataIn5, dataIn6, dataIn7, dataIn8; +wire[4:0] dataOut0, dataOut1, dataOut2, dataOut3, dataOut4, dataOut5, dataOut6, dataOut7, dataOut8; + + +matrix_manager dut (.clk(clk), .dm_we(dm_we), .next_row(next_row), .column(column), +.n(n), .m(m), .p(p), +.dataIn0(dataIn0), .dataIn1(dataIn1), .dataIn2(dataIn2), .dataIn3(dataIn3), .dataIn4(dataIn4), .dataIn5(dataIn5), .dataIn6(dataIn6), .dataIn7(dataIn7), .dataIn8(dataIn8), +.dataOut0(dataOut0), .dataOut1(dataOut1), .dataOut2(dataOut2), .dataOut3(dataOut3), .dataOut4(dataOut4), .dataOut5(dataOut5), .dataOut6(dataOut6), .dataOut7(dataOut7), .dataOut8(dataOut8)); + +always #10 clk = !clk; + +initial begin + +$dumpfile("matrix_manager.vcd"); +$dumpvars(); + +clk = 1'b0; + +next_row = 1'b1; +column = 1'b0; +n = 10'd6; +m = 10'd3; +p = 10'd6; + +dm_we = 1'b0; + +#20 + +if (dataOut0 !== 5'd0 || dataOut1 !== 5'd1 || dataOut2 !== 5'd2 || + dataOut3 !== 5'd3 || dataOut4 !== 5'd4 || dataOut5 !== 5'd5 || + dataOut6 !== 5'd6 || dataOut7 !== 5'd7 || dataOut8 !== 5'd8) begin + $display("test 1 FAILED: matrix manager did not output first matrix correctly"); +end + +next_row = 1'b1; + +#20 + +if (dataOut0 !== 5'd9 || dataOut1 !== 5'd10 || dataOut2 !== 5'd11 || + dataOut3 !== 5'd12 || dataOut4 !== 5'd13 || dataOut5 !== 5'd14 || + dataOut6 !== 5'd15 || dataOut7 !== 5'd16 || dataOut8 !== 5'd17) begin + $display("test 2 FAILED: matrix manager did not output first matrix correctly"); +end + +#20 + +if (dataOut0 !== 5'd18 || dataOut1 !== 5'd19 || dataOut2 !== 5'd20 || + dataOut3 !== 5'd24 || dataOut4 !== 5'd25 || dataOut5 !== 5'd26 || + dataOut6 !== 5'd30 || dataOut7 !== 5'd31 || dataOut8 !== 5'd32) begin + $display("test 3 FAILED: matrix manager did not output second matrix correctly"); +end + +next_row = 1'b0; +column = 1'b1; +$finish; + +end + +endmodule \ No newline at end of file diff --git a/matrix_manager.v b/matrix_manager.v new file mode 100644 index 0000000..343c70e --- /dev/null +++ b/matrix_manager.v @@ -0,0 +1,85 @@ +`include "data_memory.v" +`include "registers.v" +`include "load_block.v" +/* +The Matrix Manager loads or writes matrices using 3x3 matrices at a time. Starting from (0,0), +the matrix manager iterates through the addresses of all the matrices in row major order, according +to the control signals given as input that tell when to move to the next row, and how long the rows are. +The control signals also control whether we write to memory or save to memory. + +Inputs: + - clk + - dm_we: whether we should write to memory + - next_row: signals whether we should address from the next row of 3x3 matrices + - column: signals which column size to use - the column size of the first matrix, + or the column size of the second and result matrices. + - n: number of rows on the first array + - m: number of columns on the first matrix, and number of rows on the second matrix + - p: number of columns on the second matrix + - dataIn0...dataIn8: input 3x3 array + +Outputs: + - dataOut0...dataOut8: output 3x3 array + +*/ + + +module matrix_manager #(parameter ADDR_WIDTH=10, parameter DATA_WIDTH=5) +( + input clk, dm_we, next_row, column, + input[ADDR_WIDTH-1:0] n, m, p, + input[DATA_WIDTH-1:0] dataIn0, dataIn1, dataIn2, dataIn3, dataIn4, dataIn5, dataIn6, dataIn7, dataIn8, + output[DATA_WIDTH-1:0] dataOut0, dataOut1, dataOut2, dataOut3, dataOut4, dataOut5, dataOut6, dataOut7, dataOut8 +); + +wire[ADDR_WIDTH-1:0] addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7, addr8; + +memory #( + .width(DATA_WIDTH), + .addresswidth(ADDR_WIDTH) + ) + data_mem ( + .clk(clk), + .data0(dataOut0), .data1(dataOut1), .data2(dataOut2), .data3(dataOut3), .data4(dataOut4), + .data5(dataOut5), .data6(dataOut6), .data7(dataOut7), .data8(dataOut8), + .addr0(addr0), .addr1(addr1), .addr2(addr2), .addr3(addr3), .addr4(addr4), + .addr5(addr5), .addr6(addr6), .addr7(addr7), .addr8(addr8), + .writeEnable(dm_we), + .dataIn0(dataIn0), .dataIn1(dataIn1), .dataIn2(dataIn2), .dataIn3(dataIn3), .dataIn4(dataIn4), + .dataIn5(dataIn5), .dataIn6(dataIn6), .dataIn7(dataIn7), .dataIn8(dataIn8) + ); + +reg[ADDR_WIDTH-1:0] next_addr; +reg [ADDR_WIDTH-1:0] curr_addr; + +reg[ADDR_WIDTH-1:0] num_columns; + +address3by3block #(.MEM_ADDRESS_WIDTH(ADDR_WIDTH)) addr_loader + ( + .addr_initial(curr_addr), + .columns(num_columns), + .addr0(addr0), .addr1(addr1), .addr2(addr2), .addr3(addr3), .addr4(addr4), + .addr5(addr5), .addr6(addr6), .addr7(addr7), .addr8(addr8) + ); + +initial begin + next_addr = {ADDR_WIDTH{1'b0}}; + +end + +always @(posedge clk) begin + curr_addr = next_addr; + + if (next_row == 1'b1) begin + next_addr = curr_addr + 3 + (2*num_columns); + end + else begin + next_addr = curr_addr + 3; + end + + if (column == 1'b1) + num_columns = p; + else + num_columns = m; +end +endmodule \ No newline at end of file diff --git a/matrix_manager_test.dat b/matrix_manager_test.dat new file mode 100644 index 0000000..e04cd2c --- /dev/null +++ b/matrix_manager_test.dat @@ -0,0 +1,65 @@ +// This is the memory that should be used in the matrix_manager test bench +0_0000 +0_0001 +0_0010 +0_0011 +0_0100 +0_0101 +0_0110 +0_0111 +0_1000 +0_1001 +0_1010 +0_1011 +0_1100 +0_1101 +0_1110 +0_1111 +1_0001 +1_0010 +1_0011 +1_0100 +1_0101 +1_0110 +1_0111 +1_1000 +1_1001 +1_1010 +1_1011 +1_1100 +1_1101 +1_1110 +1_1111 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 +0_0000 \ No newline at end of file diff --git a/matrix_mem.dat b/matrix_mem.dat index 1bb139f..e04cd2c 100644 --- a/matrix_mem.dat +++ b/matrix_mem.dat @@ -1,35 +1,35 @@ -// This is the memory that should be used in the data memory test bench -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 +// This is the memory that should be used in the matrix_manager test bench +0_0000 +0_0001 +0_0010 +0_0011 +0_0100 +0_0101 +0_0110 +0_0111 +0_1000 +0_1001 +0_1010 +0_1011 +0_1100 +0_1101 +0_1110 +0_1111 +1_0001 +1_0010 +1_0011 +1_0100 +1_0101 +1_0110 +1_0111 +1_1000 +1_1001 +1_1010 +1_1011 +1_1100 +1_1101 +1_1110 +1_1111 0_0000 0_0000 0_0000 diff --git a/run_tests.sh b/run_tests.sh index 9882c52..8e7777e 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -2,7 +2,7 @@ make -echo "Running all module tests:" +echo "----------Running all module tests:----------" cat mem_test_data.dat > matrix_mem.dat echo " Running data memory tests..." @@ -23,5 +23,8 @@ echo " Running program memory tests..." ./prog_mem echo " Running controller tests..." ./controller +cat matrix_manager_test.dat > matrix_mem.dat +echo " Running matrix manager tests..." +./matrix_manager make clean From 004f2f6adb14ab8a2403270e97bca3b2411efe4e Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 20:42:13 -0500 Subject: [PATCH 57/98] addressing is now correct --- matrix_manager.t.v | 5 +++-- matrix_manager.v | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/matrix_manager.t.v b/matrix_manager.t.v index 9041dda..53e8141 100644 --- a/matrix_manager.t.v +++ b/matrix_manager.t.v @@ -55,16 +55,17 @@ if (dataOut0 !== 5'd9 || dataOut1 !== 5'd10 || dataOut2 !== 5'd11 || $display("test 2 FAILED: matrix manager did not output first matrix correctly"); end +column = 1'b1; + #20 if (dataOut0 !== 5'd18 || dataOut1 !== 5'd19 || dataOut2 !== 5'd20 || dataOut3 !== 5'd24 || dataOut4 !== 5'd25 || dataOut5 !== 5'd26 || - dataOut6 !== 5'd30 || dataOut7 !== 5'd31 || dataOut8 !== 5'd32) begin + dataOut6 !== 5'd30 || dataOut7 !== 5'd31 || dataOut8 !== 5'd0) begin $display("test 3 FAILED: matrix manager did not output second matrix correctly"); end next_row = 1'b0; -column = 1'b1; $finish; end diff --git a/matrix_manager.v b/matrix_manager.v index 343c70e..eedf6bb 100644 --- a/matrix_manager.v +++ b/matrix_manager.v @@ -1,6 +1,7 @@ `include "data_memory.v" `include "registers.v" `include "load_block.v" + /* The Matrix Manager loads or writes matrices using 3x3 matrices at a time. Starting from (0,0), the matrix manager iterates through the addresses of all the matrices in row major order, according @@ -50,7 +51,7 @@ memory #( ); reg[ADDR_WIDTH-1:0] next_addr; -reg [ADDR_WIDTH-1:0] curr_addr; +reg[ADDR_WIDTH-1:0] curr_addr; reg[ADDR_WIDTH-1:0] num_columns; @@ -64,22 +65,30 @@ address3by3block #(.MEM_ADDRESS_WIDTH(ADDR_WIDTH)) addr_loader initial begin next_addr = {ADDR_WIDTH{1'b0}}; - + curr_addr = {ADDR_WIDTH{1'bx}}; end -always @(posedge clk) begin - curr_addr = next_addr; +always @(*) begin - if (next_row == 1'b1) begin - next_addr = curr_addr + 3 + (2*num_columns); + if (curr_addr === {ADDR_WIDTH{1'bx}}) begin + next_addr <= {ADDR_WIDTH{1'b0}}; + end + else if (next_row == 1'b1) begin + next_addr <= curr_addr + 3 + (2*num_columns); end else begin - next_addr = curr_addr + 3; + next_addr <= curr_addr + 3; end +end + + +always @(posedge clk) begin + curr_addr = next_addr; if (column == 1'b1) num_columns = p; else num_columns = m; end + endmodule \ No newline at end of file From fb7b8d4ddb9e0d67f0ab3ef9d4a2cce290705cbd Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 21:48:01 -0500 Subject: [PATCH 58/98] fixed bugs with matrix manager; tests pass --- data_memory.v | 2 +- matrix_manager.t.v | 19 +++++++++++++++++++ matrix_manager.v | 7 ++++--- matrix_manager_test.dat | 1 + matrix_mem.dat | 1 + 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/data_memory.v b/data_memory.v index 427f417..8c526c2 100644 --- a/data_memory.v +++ b/data_memory.v @@ -50,6 +50,6 @@ module memory assign data7 = memory[addr7 >> 2]; assign data8 = memory[addr8 >> 2]; - initial $readmemh("matrix_mem.dat", memory); + initial $readmemb("matrix_mem.dat", memory); endmodule \ No newline at end of file diff --git a/matrix_manager.t.v b/matrix_manager.t.v index 53e8141..f5e904a 100644 --- a/matrix_manager.t.v +++ b/matrix_manager.t.v @@ -66,6 +66,25 @@ if (dataOut0 !== 5'd18 || dataOut1 !== 5'd19 || dataOut2 !== 5'd20 || end next_row = 1'b0; + +#20 + +if (dataOut0 !== 5'd21 || dataOut1 !== 5'd22 || dataOut2 !== 5'd23 || + dataOut3 !== 5'd27 || dataOut4 !== 5'd28 || dataOut5 !== 5'd29 || + dataOut6 !== 5'd0 || dataOut7 !== 5'd0 || dataOut8 !== 5'd0) begin + $display("test 4 FAILED: matrix manager did not output second matrix correctly"); +end + +next_row = 1'b1; + +#20 + +if (dataOut0 !== 5'd0 || dataOut1 !== 5'd0 || dataOut2 !== 5'd0 || + dataOut3 !== 5'd0 || dataOut4 !== 5'd0 || dataOut5 !== 5'd0 || + dataOut6 !== 5'd0 || dataOut7 !== 5'd0 || dataOut8 !== 5'd0) begin + $display("test 5 FAILED: matrix manager did not output second matrix correctly"); +end + $finish; end diff --git a/matrix_manager.v b/matrix_manager.v index eedf6bb..11ef5fc 100644 --- a/matrix_manager.v +++ b/matrix_manager.v @@ -37,14 +37,15 @@ wire[ADDR_WIDTH-1:0] addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7, add memory #( .width(DATA_WIDTH), - .addresswidth(ADDR_WIDTH) + .addresswidth(ADDR_WIDTH), + .depth(1024) ) data_mem ( .clk(clk), .data0(dataOut0), .data1(dataOut1), .data2(dataOut2), .data3(dataOut3), .data4(dataOut4), .data5(dataOut5), .data6(dataOut6), .data7(dataOut7), .data8(dataOut8), - .addr0(addr0), .addr1(addr1), .addr2(addr2), .addr3(addr3), .addr4(addr4), - .addr5(addr5), .addr6(addr6), .addr7(addr7), .addr8(addr8), + .addr0(addr0<<2), .addr1(addr1<<2), .addr2(addr2<<2), .addr3(addr3<<2), .addr4(addr4<<2), + .addr5(addr5<<2), .addr6(addr6<<2), .addr7(addr7<<2), .addr8(addr8<<2), .writeEnable(dm_we), .dataIn0(dataIn0), .dataIn1(dataIn1), .dataIn2(dataIn2), .dataIn3(dataIn3), .dataIn4(dataIn4), .dataIn5(dataIn5), .dataIn6(dataIn6), .dataIn7(dataIn7), .dataIn8(dataIn8) diff --git a/matrix_manager_test.dat b/matrix_manager_test.dat index e04cd2c..977c778 100644 --- a/matrix_manager_test.dat +++ b/matrix_manager_test.dat @@ -15,6 +15,7 @@ 0_1101 0_1110 0_1111 +1_0000 1_0001 1_0010 1_0011 diff --git a/matrix_mem.dat b/matrix_mem.dat index e04cd2c..977c778 100644 --- a/matrix_mem.dat +++ b/matrix_mem.dat @@ -15,6 +15,7 @@ 0_1101 0_1110 0_1111 +1_0000 1_0001 1_0010 1_0011 From 915ffdc2992992b453ef9f07c6ad9f1b0e407a54 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 22:51:34 -0500 Subject: [PATCH 59/98] added writing tests for matrix_manager; updated scripts so they actually run all the tests --- controller.t.v | 1 - makefile | 3 +-- matrix_manager.t.v | 53 ++++++++++++++++++++++++++++++++++++++++++---- run_tests.sh | 51 +++++++++++++++++++++++++------------------- 4 files changed, 79 insertions(+), 29 deletions(-) diff --git a/controller.t.v b/controller.t.v index d9b0bef..634f58e 100644 --- a/controller.t.v +++ b/controller.t.v @@ -96,7 +96,6 @@ initial begin else begin // test passed success_count = success_count+1; - $display("what"); end if (success_count < NUM_TESTS) begin diff --git a/makefile b/makefile index 3260f87..af90300 100644 --- a/makefile +++ b/makefile @@ -1,8 +1,7 @@ - all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager multiplier_network clean: - rm arithmetic dot matmul data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager + rm arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager multiplier_network arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v diff --git a/matrix_manager.t.v b/matrix_manager.t.v index f5e904a..900597c 100644 --- a/matrix_manager.t.v +++ b/matrix_manager.t.v @@ -35,10 +35,14 @@ n = 10'd6; m = 10'd3; p = 10'd6; +// A * C D = E F +// B G H + dm_we = 1'b0; #20 +// A if (dataOut0 !== 5'd0 || dataOut1 !== 5'd1 || dataOut2 !== 5'd2 || dataOut3 !== 5'd3 || dataOut4 !== 5'd4 || dataOut5 !== 5'd5 || dataOut6 !== 5'd6 || dataOut7 !== 5'd7 || dataOut8 !== 5'd8) begin @@ -49,6 +53,7 @@ next_row = 1'b1; #20 +// B if (dataOut0 !== 5'd9 || dataOut1 !== 5'd10 || dataOut2 !== 5'd11 || dataOut3 !== 5'd12 || dataOut4 !== 5'd13 || dataOut5 !== 5'd14 || dataOut6 !== 5'd15 || dataOut7 !== 5'd16 || dataOut8 !== 5'd17) begin @@ -59,6 +64,7 @@ column = 1'b1; #20 +// C if (dataOut0 !== 5'd18 || dataOut1 !== 5'd19 || dataOut2 !== 5'd20 || dataOut3 !== 5'd24 || dataOut4 !== 5'd25 || dataOut5 !== 5'd26 || dataOut6 !== 5'd30 || dataOut7 !== 5'd31 || dataOut8 !== 5'd0) begin @@ -69,6 +75,7 @@ next_row = 1'b0; #20 +// D if (dataOut0 !== 5'd21 || dataOut1 !== 5'd22 || dataOut2 !== 5'd23 || dataOut3 !== 5'd27 || dataOut4 !== 5'd28 || dataOut5 !== 5'd29 || dataOut6 !== 5'd0 || dataOut7 !== 5'd0 || dataOut8 !== 5'd0) begin @@ -76,17 +83,55 @@ if (dataOut0 !== 5'd21 || dataOut1 !== 5'd22 || dataOut2 !== 5'd23 || end next_row = 1'b1; +dm_we = 1'b1; + +dataIn0 = 5'd0; +dataIn1 = 5'd1; +dataIn2 = 5'd2; +dataIn3 = 5'd3; +dataIn4 = 5'd4; +dataIn5 = 5'd5; +dataIn6 = 5'd6; +dataIn7 = 5'd7; +dataIn8 = 5'd8; + +#10 // go to negedge + +//E +if (dataOut0 !== 5'd0 || dataOut1 !== 5'd1 || dataOut2 !== 5'd2 || + dataOut3 !== 5'd3 || dataOut4 !== 5'd4 || dataOut5 !== 5'd5 || + dataOut6 !== 5'd6 || dataOut7 !== 5'd7 || dataOut8 !== 5'd8) begin + $display("test 5 FAILED: matrix manager did not write result matrix correctly"); +end + +next_row = 1'b0; + +dataIn0 = 5'd10; +dataIn1 = 5'd11; +dataIn2 = 5'd12; +dataIn3 = 5'd13; +dataIn4 = 5'd14; +dataIn5 = 5'd15; +dataIn6 = 5'd16; +dataIn7 = 5'd17; +dataIn8 = 5'd18; #20 -if (dataOut0 !== 5'd0 || dataOut1 !== 5'd0 || dataOut2 !== 5'd0 || - dataOut3 !== 5'd0 || dataOut4 !== 5'd0 || dataOut5 !== 5'd0 || - dataOut6 !== 5'd0 || dataOut7 !== 5'd0 || dataOut8 !== 5'd0) begin - $display("test 5 FAILED: matrix manager did not output second matrix correctly"); +if (dataOut0 !== 5'd10 || dataOut1 !== 5'd11 || dataOut2 !== 5'd12 || + dataOut3 !== 5'd13 || dataOut4 !== 5'd14 || dataOut5 !== 5'd15 || + dataOut6 !== 5'd16 || dataOut7 !== 5'd17 || dataOut8 !== 5'd18) begin + $display("test 6 FAILED: matrix manager did not write result matrix correctly"); end + + + + $finish; + + end endmodule \ No newline at end of file diff --git a/run_tests.sh b/run_tests.sh index 3bba193..f3e2edf 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -4,41 +4,48 @@ make echo "----------Running all module tests:----------" -cat mem_test_data.dat > matrix_mem.dat -echo " Running data memory tests..." -./data_mem echo " Running arithmetic tests..." ./arithmetic + echo " Running dot tests..." ./dot -echo "Running matmul tests..." + +echo " Running matrixmultiplication tests..." ./matrixmultiplication -echo "Running load block tests..." + +cat mem_test_data.dat > matrix_mem.dat +echo " Running data_mem tests..." +./data_mem + +echo " Running load_block tests..." ./load_block -echo "Running add block tests..." + +echo " Running add_block tests..." ./add_block -echo "Running registers tests..." -./registers -echo "Running multiplier tests..." + +echo " Running multiplier tests..." ./multiplier -echo "Running multiplexer tests..." -./multiplexer -echo "running fsm tests..." -echo " Running matmul tests..." -./matmul -echo " Running register tests..." + +echo " Running registers tests..." ./registers -echo " Running load block tests..." -./load_block -echo " Running program memory tests..." + +echo " Running multiplexer tests..." +./multiplexer + +echo " Running fsm tests..." +./fsm + +echo " Running prog_mem tests..." ./prog_mem -echo " Running controller tests..." -echo "Running multiplier_network tests..." -./multiplier_network +echo " Running controller tests..." +./controller cat matrix_manager_test.dat > matrix_mem.dat -echo " Running matrix manager tests..." +echo " Running matrix_manager tests..." ./matrix_manager +echo " Running multiplier_network tests..." +./multiplier_network + make clean From 94e38266acdb741eeda6a7dc6a0a06b28a672cd4 Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Mon, 11 Dec 2017 17:56:23 -0500 Subject: [PATCH 60/98] added a useful python script, probably --- setup_memory.py | 77 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 setup_memory.py diff --git a/setup_memory.py b/setup_memory.py new file mode 100644 index 0000000..2a91dda --- /dev/null +++ b/setup_memory.py @@ -0,0 +1,77 @@ +""" +Setup the memory to do a matrix multiplication with our verilog simulation + +- formats matricies correctly and stores them in memory +- Sets up program memory to multiply the matricies together with our hardware +""" + +import numpy as np + +WORD_LEN = 5 + +# currently we only support 6x6 matricies +matrixA = [[1, 2, 3, 3, 2, 1], + [2, 3, 3, 2, 1, 1], + [1, 3, 1, 1, 2, 1], + [2, 1, 2, 0, 0, 1], + [3, 1, 0, 3, 2, 2], + [1, 2, 3, 2, 3, 2]] + +matrixB = [[1, 2, 3, 3, 2, 1], + [2, 3, 3, 2, 1, 1], + [1, 3, 1, 1, 2, 1], + [2, 1, 2, 0, 0, 1], + [3, 1, 0, 3, 2, 2], + [1, 2, 3, 2, 3, 2]] + +# format matrices to store in data memory +Astr = '' +for row in matrixA: + for val in row: + bin_val = bin(val)[2:] + extended_val = '0'*(WORD_LEN-len(bin_val)) + bin_val + Astr += extended_val + '\n' + +Bstr = '' +for row in matrixB: + for val in row: + bin_val = bin(val)[2:] + extended_val = '0'*(WORD_LEN-len(bin_val)) + bin_val + Bstr += extended_val + '\n' + +# get expected output and print calculation +expected = np.dot(matrixA, matrixB) + +print "a:\n", np.array(matrixA) +print "\nb:\n", np.array(matrixB) +print "\nexpected result:\n", expected +print "(max: {})".format(np.amax(expected)) + + +# write data memory +used_mem = Astr + Bstr +unused_mem = ('0'*WORD_LEN+'\n')*(1024-used_mem.count('\n')) +mem = used_mem + unused_mem[:-1] +f = open("test.dat", 'w') +f.write(mem) +f.close() + +# write program memory +# this would need to be more complicated to support larger matrices + +load_8_chunks = "00000\n00001\n00010\n00011\n00100\n00101\n00110\n00111\n" +store_4_chunks = "01000\n01001\n01010\n01011\n" +multiply6by6 = load_8_chunks + store_4_chunks + +full_program = multiply6by6 + +prog_mem = full_program + "00000\n"*(64-full_program.count('\n')) +f2 = open("prog_test.dat", 'w') +f2.write(prog_mem) +f2.close() + + + + + + From cf9bf3b15b78b9a3d91cc55cda21fb5520ad71d6 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:33:09 -0500 Subject: [PATCH 61/98] Change module name --- data_memory.t.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_memory.t.v b/data_memory.t.v index e00b4bd..8de56f8 100644 --- a/data_memory.t.v +++ b/data_memory.t.v @@ -17,7 +17,7 @@ module memory_TEST(); wire [ENTRY_SIZE - 1:0] data0, data1, data2, data3, data4; wire [ENTRY_SIZE - 1:0] data5, data6, data7, data8; - memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) dut( + data_memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) dut( .clk(clk), .data0(data0), .data1(data1), .data2(data2), .data3(data3), .data4(data4), .data5(data5), .data6(data6), .data7(data7), .data8(data8), .addr0(addr0), .addr1(addr1), From 369425537861725e0cf7929b0454f0c1ef4ac430 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:35:44 -0500 Subject: [PATCH 62/98] change module name --- data_memory.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_memory.v b/data_memory.v index 8c526c2..0f83d65 100644 --- a/data_memory.v +++ b/data_memory.v @@ -2,7 +2,7 @@ The memory where matrices are stored. */ -module memory +module data_memory #( parameter addresswidth = 32, parameter depth = addresswidth * 2, @@ -26,7 +26,7 @@ module memory always @(negedge clk) begin // for (i = 0; i < 100; i= i+1) - // $display(memory[i]); + // $display(memory[i]); // $display("dm"); if(writeEnable) memory[addr0 >> 2] <= dataIn0; From 9ac55b1ff71211f56d3bcc1f60dd8e957b961a47 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:36:39 -0500 Subject: [PATCH 63/98] Change module name --- load_block.t.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/load_block.t.v b/load_block.t.v index 9dfbec1..d9c057b 100644 --- a/load_block.t.v +++ b/load_block.t.v @@ -36,7 +36,7 @@ module load_block_TEST(); wire [ENTRY_SIZE - 1:0] data0, data1, data2, data3, data4; wire [ENTRY_SIZE - 1:0] data5, data6, data7, data8; - memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) mem ( + data_memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) mem ( .clk(clk), .data0(data0), .data1(data1), .data2(data2), .data3(data3), .data4(data4), .data5(data5), .data6(data6), .data7(data7), .data8(data8), .addr0(addr0), .addr1(addr1), From 152b3c4198e78135eafbf7068bce39ce1d23b64b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:37:10 -0500 Subject: [PATCH 64/98] Change module name --- matrix_manager.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix_manager.v b/matrix_manager.v index 11ef5fc..769cdf8 100644 --- a/matrix_manager.v +++ b/matrix_manager.v @@ -1,5 +1,4 @@ `include "data_memory.v" -`include "registers.v" `include "load_block.v" /* @@ -35,7 +34,7 @@ module matrix_manager #(parameter ADDR_WIDTH=10, parameter DATA_WIDTH=5) wire[ADDR_WIDTH-1:0] addr0, addr1, addr2, addr3, addr4, addr5, addr6, addr7, addr8; -memory #( +data_memory #( .width(DATA_WIDTH), .addresswidth(ADDR_WIDTH), .depth(1024) @@ -66,7 +65,8 @@ address3by3block #(.MEM_ADDRESS_WIDTH(ADDR_WIDTH)) addr_loader initial begin next_addr = {ADDR_WIDTH{1'b0}}; - curr_addr = {ADDR_WIDTH{1'bx}}; + curr_addr = {ADDR_WIDTH{1'b0}}; + num_columns = m; end always @(*) begin From 2e1317e31cb4e2e5008e9454daf5c12261b3ae67 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:37:33 -0500 Subject: [PATCH 65/98] Add target for 6by6 --- makefile | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/makefile b/makefile index af90300..0fb133a 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ -all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager multiplier_network +all: arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager multiplier_network multiplier6by6 clean: - rm arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager multiplier_network + rm arithmetic dot matrixmultiplication data_mem load_block add_block multiplier registers multiplexer fsm prog_mem controller matrix_manager multiplier_network multiplier6by6 arithmetic: arithmetic.v arithmetic.t.v iverilog -Wall -o arithmetic arithmetic.t.v @@ -44,3 +44,6 @@ multiplier_network: multiplier_network.v multiplier_network.t.v multiplexer mult matrix_manager: matrix_manager.v matrix_manager.t.v data_mem registers load_block iverilog -Wall -o matrix_manager matrix_manager.t.v + +multiplier6by6: multiplier6by6.v multiplier6by6.t.v controller matrix_manager multiplier_network + iverilog -Wall -o multiplier6by6 multiplier6by6.t.v From d5ee09b8467a8b390716a0fb0b638ff449e9dae8 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:38:51 -0500 Subject: [PATCH 66/98] Add header comment --- multiplier6by6.v | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/multiplier6by6.v b/multiplier6by6.v index e52069f..0a84aed 100644 --- a/multiplier6by6.v +++ b/multiplier6by6.v @@ -1,5 +1,8 @@ /* -FFFFFF +The full 6 by 6 multiplier. + +Inputs: + -clk: the system clock */ `include "controller.v" @@ -7,11 +10,11 @@ FFFFFF `include "multiplier_network.v" module multiplier6by6( - input clk, + input clk ); wire data_we; wire weA, weB, weC, weD, weE, weF, weG, weH; - wire jklm_select; + wire[1:0] jklm_select; wire next_row, column; wire[4:0] dataOut0, dataOut1, dataOut2, dataOut3, dataOut4, dataOut5, dataOut6, dataOut7, dataOut8; @@ -44,7 +47,7 @@ module multiplier6by6( .dh6_in(dataOut6), .dh7_in(dataOut7), .dh8_in(dataOut8), .res(result) ); - matrix_manager #(.ADDR_WIDTH = 32) manager (.clk(clk), .dm_we(data_we), + matrix_manager #(.ADDR_WIDTH(32)) manager (.clk(clk), .dm_we(data_we), .next_row(next_row), .column(column), .n(6), .m(6), .p(6), .dataIn0 (result[4:0]), .dataIn1 (result[9:5]), .dataIn2 (result[14:10]), .dataIn3 (result[19:15]), .dataIn4 (result[24:20]), .dataIn5 (result[29:25]), .dataIn6 (result[34:30]), .dataIn7 (result[39:35]), .dataIn8 (result[44:40]), .dataOut0(dataOut0), .dataOut1(dataOut1), From 91d549955e776dd954fd72a33c6ddc385fb9357e Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:39:32 -0500 Subject: [PATCH 67/98] Change module name --- prog_memory.t.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prog_memory.t.v b/prog_memory.t.v index 32ae209..347a45d 100644 --- a/prog_memory.t.v +++ b/prog_memory.t.v @@ -14,7 +14,7 @@ module memory_TEST(); wire [ENTRY_SIZE - 1:0] data; - memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) dut( + prog_memory #(.width(ENTRY_SIZE), .addresswidth(ADDRESS_WIDTH)) dut( .clk(clk), .data(data), .addr(addr) ); From 071012da89d25c1fc769b796c4ab7cff2084c9dc Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:39:50 -0500 Subject: [PATCH 68/98] Change module name --- prog_memory.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prog_memory.v b/prog_memory.v index 5f61c61..5ef161c 100644 --- a/prog_memory.v +++ b/prog_memory.v @@ -3,7 +3,7 @@ The memory where matrices are stored. */ // TODO (arianaolson419): Allow multiple data access in some fashion. -module memory +module prog_memory #( parameter addresswidth = 32, parameter depth = addresswidth * 2, From a0e8be417674a852a55b0fb6b55c40147565c363 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:40:32 -0500 Subject: [PATCH 69/98] change module name and fix typo --- controller.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller.v b/controller.v index 3a59e35..1a9a216 100644 --- a/controller.v +++ b/controller.v @@ -32,9 +32,9 @@ module controller prog_count = prog_count + 1; end - memory prog_mem (clk, cmd, prog_count); + prog_memory prog_mem (clk, cmd, prog_count); - fsm state_machie (cmd, data_we, weA, weB, weC, weD, weE, weF, weG, weH, + fsm state_machine (cmd, data_we, weA, weB, weC, weD, weE, weF, weG, weH, jklm_select, next_row, column); endmodule From fe677510f3b085ed6783de4040daf4f14b2115b5 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:40:51 -0500 Subject: [PATCH 70/98] Change memory file to write to --- run_tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/run_tests.sh b/run_tests.sh index f3e2edf..22bbe4d 100755 --- a/run_tests.sh +++ b/run_tests.sh @@ -35,6 +35,7 @@ echo " Running multiplexer tests..." echo " Running fsm tests..." ./fsm +cat prog_mem_unit_test.dat > prog_mem.dat echo " Running prog_mem tests..." ./prog_mem From 8d9f57821f41111f6a9abd039e8e72841af4e5a9 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:41:24 -0500 Subject: [PATCH 71/98] Create test script for main test --- 6by6multiply.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100755 6by6multiply.sh diff --git a/6by6multiply.sh b/6by6multiply.sh new file mode 100755 index 0000000..62209d2 --- /dev/null +++ b/6by6multiply.sh @@ -0,0 +1,11 @@ +#!/bin/bash +python2 setup_memory.py + +cat data_test.dat > matrix_mem.dat +cat prog_test.dat > prog_mem.dat + +echo "Running the BIG test..." +make +./multiplier6by6 + +make clean \ No newline at end of file From cdb259e3f098d062450570400a9d6c8e5f755870 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:41:52 -0500 Subject: [PATCH 72/98] Change file to write to --- setup_memory.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup_memory.py b/setup_memory.py index 2a91dda..356c40d 100644 --- a/setup_memory.py +++ b/setup_memory.py @@ -52,7 +52,7 @@ used_mem = Astr + Bstr unused_mem = ('0'*WORD_LEN+'\n')*(1024-used_mem.count('\n')) mem = used_mem + unused_mem[:-1] -f = open("test.dat", 'w') +f = open("data_test.dat", 'w') f.write(mem) f.close() From 9d4393eda68e592df84ef191c8f55d9245132e47 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:42:21 -0500 Subject: [PATCH 73/98] write new data --- matrix_mem.dat | 1090 +++++++++++++++++++++++++++++++++++++++++++++--- prog_mem.dat | 129 +++--- 2 files changed, 1088 insertions(+), 131 deletions(-) diff --git a/matrix_mem.dat b/matrix_mem.dat index 977c778..5b2f3e0 100644 --- a/matrix_mem.dat +++ b/matrix_mem.dat @@ -1,66 +1,1024 @@ -// This is the memory that should be used in the matrix_manager test bench -0_0000 -0_0001 -0_0010 -0_0011 -0_0100 -0_0101 -0_0110 -0_0111 -0_1000 -0_1001 -0_1010 -0_1011 -0_1100 -0_1101 -0_1110 -0_1111 -1_0000 -1_0001 -1_0010 -1_0011 -1_0100 -1_0101 -1_0110 -1_0111 -1_1000 -1_1001 -1_1010 -1_1011 -1_1100 -1_1101 -1_1110 -1_1111 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 \ No newline at end of file +00001 +00010 +00011 +00011 +00010 +00001 +00010 +00011 +00011 +00010 +00001 +00001 +00001 +00011 +00001 +00001 +00010 +00001 +00010 +00001 +00010 +00000 +00000 +00001 +00011 +00001 +00000 +00011 +00010 +00010 +00001 +00010 +00011 +00010 +00011 +00010 +00001 +00010 +00011 +00011 +00010 +00001 +00010 +00011 +00011 +00010 +00001 +00001 +00001 +00011 +00001 +00001 +00010 +00001 +00010 +00001 +00010 +00000 +00000 +00001 +00011 +00001 +00000 +00011 +00010 +00010 +00001 +00010 +00011 +00010 +00011 +00010 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 \ No newline at end of file diff --git a/prog_mem.dat b/prog_mem.dat index 52a8a64..ad8f8f8 100644 --- a/prog_mem.dat +++ b/prog_mem.dat @@ -1,65 +1,64 @@ -// This is the memory that should be used in the program memory test bench -0_0000 -0_0001 -0_0010 -0_0011 -0_0100 -0_0101 -0_0110 -0_0111 -0_1000 -0_1001 -0_1010 -0_1011 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 -0_0000 +00000 +00001 +00010 +00011 +00100 +00101 +00110 +00111 +01000 +01001 +01010 +01011 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 +00000 From 246d88e4f83e8c24a9a64c2b5c12f36d87e18b3b Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 19:42:42 -0500 Subject: [PATCH 74/98] Make test bench --- multiplier6by6.t.v | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 multiplier6by6.t.v diff --git a/multiplier6by6.t.v b/multiplier6by6.t.v new file mode 100644 index 0000000..93e610a --- /dev/null +++ b/multiplier6by6.t.v @@ -0,0 +1,55 @@ +/* +Test bench for the full 6 by 6 multiplier +*/ + +`include "multiplier6by6.v" + +module multiplier6by6_TEST(); + `define CLK_DELAY #50 + parameter NUM_TESTS = 1; + + reg clk; + + reg[5:0] success_count; + + multiplier6by6 dut (.clk(clk)); + + initial begin + $dumpfile("multiplier6by6.vcd"); + $dumpvars(); + clk = 0; `CLK_DELAY + clk = 0; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + clk = !clk; `CLK_DELAY + + $finish(); + end +endmodule \ No newline at end of file From a30ac03675b18701891404a6318eab577309c2cf Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Mon, 11 Dec 2017 20:00:04 -0500 Subject: [PATCH 75/98] I FOUND IT, not quite all working, but I FOUNT IT --- data_memory.v | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/data_memory.v b/data_memory.v index 0f83d65..18359dc 100644 --- a/data_memory.v +++ b/data_memory.v @@ -28,7 +28,7 @@ module data_memory // for (i = 0; i < 100; i= i+1) // $display(memory[i]); // $display("dm"); - if(writeEnable) + if(writeEnable == 1) begin memory[addr0 >> 2] <= dataIn0; memory[addr1 >> 2] <= dataIn1; memory[addr2 >> 2] <= dataIn2; @@ -38,6 +38,7 @@ module data_memory memory[addr6 >> 2] <= dataIn6; memory[addr7 >> 2] <= dataIn7; memory[addr8 >> 2] <= dataIn8; + end end assign data0 = memory[addr0 >> 2]; @@ -52,4 +53,4 @@ module data_memory initial $readmemb("matrix_mem.dat", memory); -endmodule \ No newline at end of file +endmodule From 03274067b7faf483b745474ab0f5d5dcf9a8eb4f Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 23:57:19 -0500 Subject: [PATCH 76/98] Starting testing --- multiplier6by6.t.v | 54 +++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/multiplier6by6.t.v b/multiplier6by6.t.v index 93e610a..2a4386d 100644 --- a/multiplier6by6.t.v +++ b/multiplier6by6.t.v @@ -6,6 +6,11 @@ Test bench for the full 6 by 6 multiplier module multiplier6by6_TEST(); `define CLK_DELAY #50 + + `define EXPECTED_AEBG 45'b101011100010101100111101111001100011001110010 + `define EXPECTED_AFBH 45'b100101000101111101001001001110100100111001100 + `define EXPECTED_CEDG 45'b001110111101110100111001011000101111101010110 + `define EXPECTED_CFDH 45'b011000110000111101011000101111101111011010010 parameter NUM_TESTS = 1; reg clk; @@ -14,41 +19,26 @@ module multiplier6by6_TEST(); multiplier6by6 dut (.clk(clk)); + `define AEplusBG dut.network.chooseres.AEplusBG + `define AFplusBH dut.network.chooseres.AFplusBH + `define CEplusBG dut.network.chooseres.CEplusDG + `define CFplusDH dut.network.chooseres.CFplusDH + + initial clk = 0; + always `CLK_DELAY clk = !clk; + initial begin $dumpfile("multiplier6by6.vcd"); $dumpvars(); - clk = 0; `CLK_DELAY - clk = 0; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY - clk = !clk; `CLK_DELAY + + #50 + #5000 + + if (dut.network.chooseres.AEplusBG[44:40] === 5'd21) $display("success"); + $display("AE + BG %b", dut.network.chooseres.AEplusBG); + $display("AF + BH %b", dut.network.chooseres.AFplusBH); + $display("CE + DG %b", dut.network.chooseres.CEplusDG); + $display("CF + DH %b", dut.network.chooseres.CFplusDH); $finish(); end From 07cd74bf4da6615debac1de2ac1363d8223292da Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Tue, 12 Dec 2017 04:35:23 -0500 Subject: [PATCH 77/98] added a lot of stuff to the webpage --- docs/index.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/docs/index.md b/docs/index.md index fba905e..bdbe974 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,16 +2,82 @@ ## Abstract -For our Computer Architecture final project, we designed computer hardware to multiply two matricies (final constrints here). Matrix multiplication is a complex and time intensive opperation for normal computer architectures becuase there are a large number of individual computations; however, it is used frequently for machine learning and ???. Because each value in the result matrix can be computed independently from any other result, matrix multiplication is an excellent candidate for parallelization. We wanted to explore the potential efficiency gain from using a purpose built matrix multiplier, and see how a computer architecture which splits a work load among a large number of computing units would actually work. +For our Computer Architecture final project, we designed computer hardware to optimize multiplying two 6x6 matrices. Matrix multiplication is a complex and time intensive operation for normal computer architectures because there are a large number of individual computations; however, it is used frequently for machine learning and ???. Because each value in the result matrix can be computed independently from any other result, matrix multiplication is an excellent candidate for parallelization. We wanted to explore the potential efficiency gain from using a purpose built matrix multiplier, and see how a computer architecture which splits a workload among a large number of computing units would actually work. ## Project Motivation and Background -After studying single cycle MIPS CPUs, we were interested in other computing architectures with different strengths and weakenesses. We first looked at GPUs, which were originally designed specifically for graphics, but have recently been generalized to be fully functional CPUs. Graphics opperations are essentially a subset of matrix opperations (where the :With this added functionallity, GPUs have become increasingly usefull for machine learning algorithms and general parallel computing. Mostly, computations on matricies are complex and time intensive on normal CPUs, but the extreme parallelization of computations in a GPU makes it much more efficient at these opperations. We wanted to explore this increase in efficiency by making some purpose built hardware for matrix multiplication. +After studying single cycle MIPS CPUs, we were interested in other computing architectures with different strengths and weaknesses. We first looked at GPUs, which were originally designed specifically for graphics, but have recently been generalized to have all the functionality of CPUs. Graphics operations are essentially a subset of matrix operations (where the :With this added functionality, GPUs have become increasingly useful for machine learning algorithms and general parallel computing. In particular, computations on matrices are complex and time intensive on normal CPUs, but the extreme parallelization of computations in a GPU makes these operations much more efficient. We wanted to explore this increase in efficiency by making some purpose built hardware for matrix multiplication. -## Results +## How to use -## Similarities to Graphics +We made custom architecture that can multiply two 6x6 arrays of 5 bit unsigned integers (or smaller arrays, if you pad the rest of the matrices with zeros). -As we mentioned before, graphics operations are essentially a subset of matrix opperations. +To run the program, clone the [repository](https://github.com/poosomooso/FinalProject) and run `./6by6multiply.sh`. If you wish to try different matrices, you can change the matrices in`setup_memory.py`. + +## Implementation + + + +The heart of our algorithm is the matrix multiplication unit, or the multiplier. It takes two 3x3 matrices and multiplies them. It consists of 9 dot product modules that dot product length 3 vectors, and the dot products happen in parallel. The multiplier also contains a small collection of registers that temporarily store the input and output matrices until other modules use the result. + + + +Each 6x6 matrix is broken down into 4 3x3 matrices. The figure above shows the algorithm we use to multiply the broken up matrices, where each 3x3 matrix is represented with a capital letter. We are basically breaking up the dot products of each row and column vector into 3x3 chunks, and adding them together. This is a simplified version of the [divide and conquer algorithm](https://en.wikipedia.org/wiki/Matrix_multiplication_algorithm#Divide_and_conquer_algorithm), which is preferred over performing each dot product, generally because of caching (though not relevant in our case). In our case, we preferred it because it allowed us to have constant size multiplication blocks (the aforementioned 3x3 matrix multiplication unit), so we didn’t have to make variable size dot product modules. Although we currently constrained ourselves to 6x6 matrices, using the 3x3 modules allows us to scale in the future. + +The algorithm is performed and parallelized in the multiplier network. The multiplier network contains 8 multipliers, one for each pair of broken up matrices that need to be multiplied. It also contains four 3x3 matrix adders. Each 3x3 matrix in the result matrix of the above figure uses 2 of these multipliers and one matrix adder, so all of the resultant 3x3 matrices are calculated independent of each other. + +We use the matrix manager to break down the matrices and populate the multiplier network correctly. The matrix manager manages loads and stores to data memory. It also computes and keeps track of the index of the first element of the 3x3 arrays, and uses a load block module to retrieve the 3x3 array starting from the computed starting index. The output from the matrix manager goes to the network of multipliers. The output from the multiplier network is fed back into the matrix manager to store into memory. We store the matrices as a vector in data memory, as follows: + +|3 by 3 Matrix | Data Memory | +| --------- | -------- | +|a11 / a12 / a13 | a11 | +|a21 / a22 / a23 | a12 | +|a31 / a32 / a33 | a13 | +| | a21 | +| | a22 | +| | a23 | +| | a31 | +| | a32 | +| | a33 | + +These matrices are stored sequentially in memory, and the resultant matrix is stored directly following the second matrix in memory. + + +Finally we have the controller. The controller reads in commands from a file and writes them to the FSM. The FSM breaks down the command into two sections: the *type*, which is either ‘00’ for loading a matrix, or ‘01’ for saving a matrix, and the *block*, which represents a particular 3x3 matrix: + +| Matrix | Block Code | +| --- | --- | +| A | 000 | +| B | 001 | +| C | 010 | +| D | 011 | +| E | 100 | +| F | 101 | +| G | 110 | +| H | 111 | +| J | X00 | +| K | X01 | +| L | X10 | +| M | X11 | + +We can generate all the control signals through these two codes. We use *type* to tell us whether we are working with input matrices or the resultant matrix. From the two input matrices, we can tell which one we are using by looking at the MSB of *block*. And we can tell when we need to move to the next row of 3x3 matrices by looking at the LSB of *block* — all the blocks on the left side of the matrix have a 0 in the LSB, and all the blocks on the right side of the matrix have a one in the LSB. + +That last trick only works because we are dealing with 6x6 matrices, so they get broken down into 2x2 (i.e. binary) squares. If we were to scale the size of the matrices, we would have to come up with a new way of detecting when to go to the next row of 3x3 matrices. + +We use a Python script to generate the program memory and the initial data memory. The Python script has two numpy arrays hardcoded, that can be changed at any time. It then converts the numpy arrays to be binary encoded, and writes the array to a file.It also writes the program memory to a file, which for the 6x6 multiplier, should be the same every time, since the instructions are only dependent on the size of the matrix. + +## Reflection + +While being constrained to only a 6x6 matrix falls a bit short of our goals, we did not anticipate how complicated it would be to design all the small modules in the design and wire them up together properly. However, we did stay on track with our workplan and reach a version of our planned goal. Our workplan was intentionally vague, since at the beginning of the project, we knew there were a lot of options to explore, and we didn’t know how this project would manifest. Overall, we learned a lot about implementing matrix multiplication, and techniques for parallelizing. + +One thing that we hoped to implement, but was not able due to time, was full parallelization of loading data. Currently, our matrix manager only loads one 3x3x matrix at a time, but the multiplier could be much more efficient if it could load all the matrices to the multipliers at the same time, and then write back all the results at the same time. A lot of our architecture that we built in the beginning (data memory, load block) assumed we would only be loading 9 entries at a time, since each multiplier unit was using 9 entries of each particular matrix. However, it wasn’t until later that we realized that our design would be much more efficient if we could load multiple 3x3 blocks at once. By then, so much of our design depended on individually loading these 9-entry blocks that it was difficult to go back and retroactively make changes. If we did this again, we would spend a little more time in the beginning, working on block diagrams. + +## Future Extensions + +I think the next logical step is to scale this up, where each dimension is an arbitrary multiple of 3. Then, multiplying matrices of any size, by padding the matrix with zeros until the dimensions become a multiple of 3. + +Another extension is to apply the matrix algorithm to actual science or graphics applications, and make customized hardware for a specific application. ## Appendix + + From d00daa5e5f052000718897df06e46c7ca7cbed23 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Mon, 11 Dec 2017 23:58:45 -0500 Subject: [PATCH 78/98] Nonblocking equals --- multiplexer.v | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/multiplexer.v b/multiplexer.v index 90eb9c2..ac051e1 100644 --- a/multiplexer.v +++ b/multiplexer.v @@ -10,10 +10,10 @@ module multiplexer4to1 ); always @(res_sel) begin case (res_sel) - 2'b00: begin result = AEplusBG; end - 2'b01: begin result = AFplusBH; end - 2'b10: begin result = CEplusDG; end - 2'b11: begin result = CFplusDH; end + 2'b00: begin result <= AEplusBG; end + 2'b01: begin result <= AFplusBH; end + 2'b10: begin result <= CEplusDG; end + 2'b11: begin result <= CFplusDH; end endcase end endmodule \ No newline at end of file From 7bfef076bb90fcd3b2c2fa02c0f194d466f37f0d Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 18:59:03 -1000 Subject: [PATCH 79/98] Update index.md --- docs/index.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/index.md b/docs/index.md index bdbe974..7473385 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,6 @@ +--- +--- + # Matrix Multiplication ## Abstract From ba34bf439090d1da3813c5143e31cdacdfce1d9a Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 19:02:58 -1000 Subject: [PATCH 80/98] added pics --- docs/3 by 3 mulltiplier.jpg | Bin 0 -> 89942 bytes docs/Add Block.jpg | Bin 0 -> 85182 bytes docs/Controller.jpg | Bin 0 -> 31653 bytes docs/Full Multiplier.jpg | Bin 0 -> 54160 bytes docs/Load Block.jpg | Bin 0 -> 65717 bytes docs/Matrix Manager.jpg | Bin 0 -> 56505 bytes docs/Multiplier Network.jpg | Bin 0 -> 116597 bytes docs/Multiplier with registers.jpg | Bin 0 -> 28681 bytes docs/dot.jpg | Bin 0 -> 24973 bytes docs/matrices.PNG | Bin 0 -> 60860 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/3 by 3 mulltiplier.jpg create mode 100644 docs/Add Block.jpg create mode 100644 docs/Controller.jpg create mode 100644 docs/Full Multiplier.jpg create mode 100644 docs/Load Block.jpg create mode 100644 docs/Matrix Manager.jpg create mode 100644 docs/Multiplier Network.jpg create mode 100644 docs/Multiplier with registers.jpg create mode 100644 docs/dot.jpg create mode 100644 docs/matrices.PNG diff --git a/docs/3 by 3 mulltiplier.jpg b/docs/3 by 3 mulltiplier.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0b9ead88eae095790e5bbf2e712c17cdbe71770 GIT binary patch literal 89942 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 literal 0 HcmV?d00001 diff --git a/docs/Add Block.jpg b/docs/Add Block.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3ef44cc399cbc4b065eb13fcead5fd26d71810ac GIT binary patch literal 85182 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 XfnRgr*BtmY2Y$_gf6pAC{@njx{>#ff literal 0 HcmV?d00001 diff --git a/docs/Controller.jpg b/docs/Controller.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e41d16fce54b840280247a645aa5b8cf7846c9df GIT binary patch literal 31653 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

KIGeL@@woXrq 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

QpchV#{XjYjm$ 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 I_0#Bo0jM-3zyJUM literal 0 HcmV?d00001 diff --git a/docs/Multiplier with registers.jpg b/docs/Multiplier with registers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..749117c851a93ca1e608da3f80c8c65a8b8bb274 GIT binary patch literal 28681 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 TzW3928Tc*(Kgj?UV(9+?|Djkc literal 0 HcmV?d00001 diff --git a/docs/dot.jpg b/docs/dot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..237b1ebf79786b54bde292fd78419ff842c8e255 GIT binary patch literal 24973 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,N(|&iN>*K{7_QGu@1%E6qLDbqydIB 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 Go8NhA?Qbna=_0FtPE9hLM0Q|82X73( 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 literal 0 HcmV?d00001 From 882c47c0e0a72851937d12407970c8163fbe6439 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Tue, 12 Dec 2017 00:17:37 -0500 Subject: [PATCH 81/98] Flipped order of writing data --- multiplier6by6.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/multiplier6by6.v b/multiplier6by6.v index 0a84aed..c02b7b1 100644 --- a/multiplier6by6.v +++ b/multiplier6by6.v @@ -48,9 +48,9 @@ module multiplier6by6( ); matrix_manager #(.ADDR_WIDTH(32)) manager (.clk(clk), .dm_we(data_we), - .next_row(next_row), .column(column), .n(6), .m(6), .p(6), .dataIn0 (result[4:0]), .dataIn1 (result[9:5]), - .dataIn2 (result[14:10]), .dataIn3 (result[19:15]), .dataIn4 (result[24:20]), .dataIn5 (result[29:25]), .dataIn6 (result[34:30]), - .dataIn7 (result[39:35]), .dataIn8 (result[44:40]), .dataOut0(dataOut0), .dataOut1(dataOut1), + .next_row(next_row), .column(column), .n(6), .m(6), .p(6), .dataIn0 (result[44:40]), .dataIn1 (result[39:35]), + .dataIn2 (result[34:30]), .dataIn3 (result[29:25]), .dataIn4 (result[24:20]), .dataIn5 (result[19:15]), .dataIn6 (result[14:10]), + .dataIn7 (result[9:5]), .dataIn8 (result[4:0]), .dataOut0(dataOut0), .dataOut1(dataOut1), .dataOut2(dataOut2), .dataOut3(dataOut3), .dataOut4(dataOut4), .dataOut5(dataOut5), .dataOut6(dataOut6), .dataOut7(dataOut7), .dataOut8(dataOut8)); endmodule \ No newline at end of file From 5788b4627d8ee3312eaac4906abc9bad068fdc7f Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Tue, 12 Dec 2017 05:01:47 -0500 Subject: [PATCH 82/98] added pics --- .../3by3mulltiplier.jpg} | Bin docs/{Add Block.jpg => img/AddBlock.jpg} | Bin docs/{ => img}/Controller.jpg | Bin .../FullMultiplier.jpg} | Bin docs/{Load Block.jpg => img/LoadBlock.jpg} | Bin .../MatrixManager.jpg} | Bin .../MultiplierNetwork.jpg} | Bin .../MultiplierwithRegisters.jpg} | Bin docs/{ => img}/dot.jpg | Bin docs/{ => img}/matrices.PNG | Bin docs/index.md | 25 ++++++++++++++++-- 11 files changed, 23 insertions(+), 2 deletions(-) rename docs/{3 by 3 mulltiplier.jpg => img/3by3mulltiplier.jpg} (100%) rename docs/{Add Block.jpg => img/AddBlock.jpg} (100%) rename docs/{ => img}/Controller.jpg (100%) rename docs/{Full Multiplier.jpg => img/FullMultiplier.jpg} (100%) rename docs/{Load Block.jpg => img/LoadBlock.jpg} (100%) rename docs/{Matrix Manager.jpg => img/MatrixManager.jpg} (100%) rename docs/{Multiplier Network.jpg => img/MultiplierNetwork.jpg} (100%) rename docs/{Multiplier with registers.jpg => img/MultiplierwithRegisters.jpg} (100%) rename docs/{ => img}/dot.jpg (100%) rename docs/{ => img}/matrices.PNG (100%) diff --git a/docs/3 by 3 mulltiplier.jpg b/docs/img/3by3mulltiplier.jpg similarity index 100% rename from docs/3 by 3 mulltiplier.jpg rename to docs/img/3by3mulltiplier.jpg diff --git a/docs/Add Block.jpg b/docs/img/AddBlock.jpg similarity index 100% rename from docs/Add Block.jpg rename to docs/img/AddBlock.jpg diff --git a/docs/Controller.jpg b/docs/img/Controller.jpg similarity index 100% rename from docs/Controller.jpg rename to docs/img/Controller.jpg diff --git a/docs/Full Multiplier.jpg b/docs/img/FullMultiplier.jpg similarity index 100% rename from docs/Full Multiplier.jpg rename to docs/img/FullMultiplier.jpg diff --git a/docs/Load Block.jpg b/docs/img/LoadBlock.jpg similarity index 100% rename from docs/Load Block.jpg rename to docs/img/LoadBlock.jpg diff --git a/docs/Matrix Manager.jpg b/docs/img/MatrixManager.jpg similarity index 100% rename from docs/Matrix Manager.jpg rename to docs/img/MatrixManager.jpg diff --git a/docs/Multiplier Network.jpg b/docs/img/MultiplierNetwork.jpg similarity index 100% rename from docs/Multiplier Network.jpg rename to docs/img/MultiplierNetwork.jpg diff --git a/docs/Multiplier with registers.jpg b/docs/img/MultiplierwithRegisters.jpg similarity index 100% rename from docs/Multiplier with registers.jpg rename to docs/img/MultiplierwithRegisters.jpg diff --git a/docs/dot.jpg b/docs/img/dot.jpg similarity index 100% rename from docs/dot.jpg rename to docs/img/dot.jpg diff --git a/docs/matrices.PNG b/docs/img/matrices.PNG similarity index 100% rename from docs/matrices.PNG rename to docs/img/matrices.PNG diff --git a/docs/index.md b/docs/index.md index 7473385..065663e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,16 +19,34 @@ To run the program, clone the [repository](https://github.com/poosomooso/FinalPr ## Implementation - +![][img/FullMultiplier.jpg] + +Figure 1 : High level block diagram of the system (components explained below). + +![][img/3by3multiplier.jpg] +![][img/MultiplerwithRegisters.jpg] + +Figure 2 : Our core multiplier - multiplies two 3x3 matrices. The left shows the module that multiplies the matrices, and the right shows the module that contain the left module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. The heart of our algorithm is the matrix multiplication unit, or the multiplier. It takes two 3x3 matrices and multiplies them. It consists of 9 dot product modules that dot product length 3 vectors, and the dot products happen in parallel. The multiplier also contains a small collection of registers that temporarily store the input and output matrices until other modules use the result. - +![][img/matrices.PNG] + +Figure 3 : the algorithm we use to multiply the 6x6 matrix, where each capital letter represents the 3x3 section of the matrix. Each 6x6 matrix is broken down into 4 3x3 matrices. The figure above shows the algorithm we use to multiply the broken up matrices, where each 3x3 matrix is represented with a capital letter. We are basically breaking up the dot products of each row and column vector into 3x3 chunks, and adding them together. This is a simplified version of the [divide and conquer algorithm](https://en.wikipedia.org/wiki/Matrix_multiplication_algorithm#Divide_and_conquer_algorithm), which is preferred over performing each dot product, generally because of caching (though not relevant in our case). In our case, we preferred it because it allowed us to have constant size multiplication blocks (the aforementioned 3x3 matrix multiplication unit), so we didn’t have to make variable size dot product modules. Although we currently constrained ourselves to 6x6 matrices, using the 3x3 modules allows us to scale in the future. +![][img/MultiplierNetwork.jpg] + +Figure 4 : The multiplier network that parallelizes the 8 dot products and 4 additions necessary to multiply the 6x6 matrix. + The algorithm is performed and parallelized in the multiplier network. The multiplier network contains 8 multipliers, one for each pair of broken up matrices that need to be multiplied. It also contains four 3x3 matrix adders. Each 3x3 matrix in the result matrix of the above figure uses 2 of these multipliers and one matrix adder, so all of the resultant 3x3 matrices are calculated independent of each other. +![][img/LoadBlock.jpg] +![][img/MatrixManager.jpg] + +Figure 5 : The matrix manager that handles the main memory and breaks down the matrices. The left is the load block module which generates the addresses for the 3x3 block in memory. The right is the full matrix manager, which uses the load block, data memory, and an address register. It also has a block for determining the next address, which is mostly muxes and arithmetic. + We use the matrix manager to break down the matrices and populate the multiplier network correctly. The matrix manager manages loads and stores to data memory. It also computes and keeps track of the index of the first element of the 3x3 arrays, and uses a load block module to retrieve the 3x3 array starting from the computed starting index. The output from the matrix manager goes to the network of multipliers. The output from the multiplier network is fed back into the matrix manager to store into memory. We store the matrices as a vector in data memory, as follows: |3 by 3 Matrix | Data Memory | @@ -45,6 +63,9 @@ We use the matrix manager to break down the matrices and populate the multiplier These matrices are stored sequentially in memory, and the resultant matrix is stored directly following the second matrix in memory. +![][img/Controller.jpg] + +Figure 6 : The module generating the control signals, backed by an FSM that generates signals based on a series of instructions. Finally we have the controller. The controller reads in commands from a file and writes them to the FSM. The FSM breaks down the command into two sections: the *type*, which is either ‘00’ for loading a matrix, or ‘01’ for saving a matrix, and the *block*, which represents a particular 3x3 matrix: From 15b69c390d3537d591aabbc63da55da6c8d55284 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Tue, 12 Dec 2017 05:06:22 -0500 Subject: [PATCH 83/98] picture formatting that actually works --- docs/index.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/index.md b/docs/index.md index 065663e..a37cafd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,33 +19,33 @@ To run the program, clone the [repository](https://github.com/poosomooso/FinalPr ## Implementation -![][img/FullMultiplier.jpg] +![](img/FullMultiplier.jpg) -Figure 1 : High level block diagram of the system (components explained below). +**Figure 1** : High level block diagram of the system (components explained below). -![][img/3by3multiplier.jpg] -![][img/MultiplerwithRegisters.jpg] +![](img/3by3multiplier.jpg) +![](img/MultiplerwithRegisters.jpg) -Figure 2 : Our core multiplier - multiplies two 3x3 matrices. The left shows the module that multiplies the matrices, and the right shows the module that contain the left module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. +**Figure 2** : Our core multiplier - multiplies two 3x3 matrices. The left shows the module that multiplies the matrices, and the right shows the module that contain the left module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. The heart of our algorithm is the matrix multiplication unit, or the multiplier. It takes two 3x3 matrices and multiplies them. It consists of 9 dot product modules that dot product length 3 vectors, and the dot products happen in parallel. The multiplier also contains a small collection of registers that temporarily store the input and output matrices until other modules use the result. -![][img/matrices.PNG] +![](img/matrices.PNG) -Figure 3 : the algorithm we use to multiply the 6x6 matrix, where each capital letter represents the 3x3 section of the matrix. +**Figure 3** : the algorithm we use to multiply the 6x6 matrix, where each capital letter represents the 3x3 section of the matrix. Each 6x6 matrix is broken down into 4 3x3 matrices. The figure above shows the algorithm we use to multiply the broken up matrices, where each 3x3 matrix is represented with a capital letter. We are basically breaking up the dot products of each row and column vector into 3x3 chunks, and adding them together. This is a simplified version of the [divide and conquer algorithm](https://en.wikipedia.org/wiki/Matrix_multiplication_algorithm#Divide_and_conquer_algorithm), which is preferred over performing each dot product, generally because of caching (though not relevant in our case). In our case, we preferred it because it allowed us to have constant size multiplication blocks (the aforementioned 3x3 matrix multiplication unit), so we didn’t have to make variable size dot product modules. Although we currently constrained ourselves to 6x6 matrices, using the 3x3 modules allows us to scale in the future. -![][img/MultiplierNetwork.jpg] +![](img/MultiplierNetwork.jpg) -Figure 4 : The multiplier network that parallelizes the 8 dot products and 4 additions necessary to multiply the 6x6 matrix. +**Figure 4** : The multiplier network that parallelizes the 8 dot products and 4 additions necessary to multiply the 6x6 matrix. The algorithm is performed and parallelized in the multiplier network. The multiplier network contains 8 multipliers, one for each pair of broken up matrices that need to be multiplied. It also contains four 3x3 matrix adders. Each 3x3 matrix in the result matrix of the above figure uses 2 of these multipliers and one matrix adder, so all of the resultant 3x3 matrices are calculated independent of each other. -![][img/LoadBlock.jpg] -![][img/MatrixManager.jpg] +![](img/LoadBlock.jpg) +![](img/MatrixManager.jpg) -Figure 5 : The matrix manager that handles the main memory and breaks down the matrices. The left is the load block module which generates the addresses for the 3x3 block in memory. The right is the full matrix manager, which uses the load block, data memory, and an address register. It also has a block for determining the next address, which is mostly muxes and arithmetic. +**Figure 5** : The matrix manager that handles the main memory and breaks down the matrices. The left is the load block module which generates the addresses for the 3x3 block in memory. The right is the full matrix manager, which uses the load block, data memory, and an address register. It also has a block for determining the next address, which is mostly muxes and arithmetic. We use the matrix manager to break down the matrices and populate the multiplier network correctly. The matrix manager manages loads and stores to data memory. It also computes and keeps track of the index of the first element of the 3x3 arrays, and uses a load block module to retrieve the 3x3 array starting from the computed starting index. The output from the matrix manager goes to the network of multipliers. The output from the multiplier network is fed back into the matrix manager to store into memory. We store the matrices as a vector in data memory, as follows: @@ -63,9 +63,9 @@ We use the matrix manager to break down the matrices and populate the multiplier These matrices are stored sequentially in memory, and the resultant matrix is stored directly following the second matrix in memory. -![][img/Controller.jpg] +![](img/Controller.jpg) -Figure 6 : The module generating the control signals, backed by an FSM that generates signals based on a series of instructions. +**Figure 6** : The module generating the control signals, backed by an FSM that generates signals based on a series of instructions. Finally we have the controller. The controller reads in commands from a file and writes them to the FSM. The FSM breaks down the command into two sections: the *type*, which is either ‘00’ for loading a matrix, or ‘01’ for saving a matrix, and the *block*, which represents a particular 3x3 matrix: From 1a6baee0fc3b832c3bd6e51e1f6e189b7934676b Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Tue, 12 Dec 2017 05:13:11 -0500 Subject: [PATCH 84/98] small formatting things --- docs/index.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/index.md b/docs/index.md index a37cafd..1e57794 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,7 @@ ## Abstract -For our Computer Architecture final project, we designed computer hardware to optimize multiplying two 6x6 matrices. Matrix multiplication is a complex and time intensive operation for normal computer architectures because there are a large number of individual computations; however, it is used frequently for machine learning and ???. Because each value in the result matrix can be computed independently from any other result, matrix multiplication is an excellent candidate for parallelization. We wanted to explore the potential efficiency gain from using a purpose built matrix multiplier, and see how a computer architecture which splits a workload among a large number of computing units would actually work. +We designed computer hardware to optimize multiplying two 6x6 matrices. Matrix multiplication is a complex and time intensive operation for normal computer architectures because there are a large number of individual computations; however, it is used frequently for machine learning and computer graphics. Because each value in the result matrix can be computed independently from any other result, matrix multiplication is an excellent candidate for parallelization. We wanted to explore the potential efficiency gain from using a purpose built matrix multiplier, and see how to split a workload among a large number of computing units. ## Project Motivation and Background @@ -23,8 +23,7 @@ To run the program, clone the [repository](https://github.com/poosomooso/FinalPr **Figure 1** : High level block diagram of the system (components explained below). -![](img/3by3multiplier.jpg) -![](img/MultiplerwithRegisters.jpg) +![](img/3by3multiplier.jpg) ![](img/MultiplerwithRegisters.jpg) **Figure 2** : Our core multiplier - multiplies two 3x3 matrices. The left shows the module that multiplies the matrices, and the right shows the module that contain the left module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. @@ -42,8 +41,7 @@ Each 6x6 matrix is broken down into 4 3x3 matrices. The figure above shows the a The algorithm is performed and parallelized in the multiplier network. The multiplier network contains 8 multipliers, one for each pair of broken up matrices that need to be multiplied. It also contains four 3x3 matrix adders. Each 3x3 matrix in the result matrix of the above figure uses 2 of these multipliers and one matrix adder, so all of the resultant 3x3 matrices are calculated independent of each other. -![](img/LoadBlock.jpg) -![](img/MatrixManager.jpg) +![](img/LoadBlock.jpg) ![](img/MatrixManager.jpg) **Figure 5** : The matrix manager that handles the main memory and breaks down the matrices. The left is the load block module which generates the addresses for the 3x3 block in memory. The right is the full matrix manager, which uses the load block, data memory, and an address register. It also has a block for determining the next address, which is mostly muxes and arithmetic. @@ -102,6 +100,6 @@ I think the next logical step is to scale this up, where each dimension is an ar Another extension is to apply the matrix algorithm to actual science or graphics applications, and make customized hardware for a specific application. -## Appendix + From f612049bc013254d7e6570a2058ac519cfaa1ddb Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 19:51:09 -1000 Subject: [PATCH 85/98] Update index.md --- docs/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 1e57794..0046bd8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,7 +23,7 @@ To run the program, clone the [repository](https://github.com/poosomooso/FinalPr **Figure 1** : High level block diagram of the system (components explained below). -![](img/3by3multiplier.jpg) ![](img/MultiplerwithRegisters.jpg) + **Figure 2** : Our core multiplier - multiplies two 3x3 matrices. The left shows the module that multiplies the matrices, and the right shows the module that contain the left module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. @@ -41,7 +41,7 @@ Each 6x6 matrix is broken down into 4 3x3 matrices. The figure above shows the a The algorithm is performed and parallelized in the multiplier network. The multiplier network contains 8 multipliers, one for each pair of broken up matrices that need to be multiplied. It also contains four 3x3 matrix adders. Each 3x3 matrix in the result matrix of the above figure uses 2 of these multipliers and one matrix adder, so all of the resultant 3x3 matrices are calculated independent of each other. -![](img/LoadBlock.jpg) ![](img/MatrixManager.jpg) + **Figure 5** : The matrix manager that handles the main memory and breaks down the matrices. The left is the load block module which generates the addresses for the 3x3 block in memory. The right is the full matrix manager, which uses the load block, data memory, and an address register. It also has a block for determining the next address, which is mostly muxes and arithmetic. From 257bda1693270af815dbd3dde6982b505beff880 Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Tue, 12 Dec 2017 00:55:31 -0500 Subject: [PATCH 86/98] got memory to output to a file and added a python script for reading from that memory output --- matrix_mem.dat | 10 +++++----- multiplier6by6.t.v | 10 +++++++++- read_6by6result.py | 20 ++++++++++++++++++++ setup_memory.py | 10 +++++----- 4 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 read_6by6result.py diff --git a/matrix_mem.dat b/matrix_mem.dat index 5b2f3e0..52a8280 100644 --- a/matrix_mem.dat +++ b/matrix_mem.dat @@ -37,12 +37,12 @@ 00001 00010 00011 -00011 +00010 00010 00001 00010 00011 -00011 +00000 00010 00001 00001 @@ -54,21 +54,21 @@ 00001 00010 00001 -00010 +00001 00000 00000 00001 00011 00001 00000 -00011 00010 +00011 00010 00001 00010 00011 00010 -00011 +00001 00010 00000 00000 diff --git a/multiplier6by6.t.v b/multiplier6by6.t.v index 2a4386d..3d3a818 100644 --- a/multiplier6by6.t.v +++ b/multiplier6by6.t.v @@ -27,6 +27,8 @@ module multiplier6by6_TEST(); initial clk = 0; always `CLK_DELAY clk = !clk; + integer mem_out, i; + initial begin $dumpfile("multiplier6by6.vcd"); $dumpvars(); @@ -40,6 +42,12 @@ module multiplier6by6_TEST(); $display("CE + DG %b", dut.network.chooseres.CEplusDG); $display("CF + DH %b", dut.network.chooseres.CFplusDH); + mem_out = $fopen("memory_out.txt"); + for (i=0; i<1024; i=i+1) begin + $fdisplay(mem_out, "%d", dut.manager.data_mem.memory[i]); + end + $fclose(mem_out); + $finish(); end -endmodule \ No newline at end of file +endmodule diff --git a/read_6by6result.py b/read_6by6result.py new file mode 100644 index 0000000..c6355ba --- /dev/null +++ b/read_6by6result.py @@ -0,0 +1,20 @@ +""" +pull out the part of memory holding the matrix +and format it as a numpy array to make it easy +to read +""" +import numpy as np + + +f = open("memory_out.txt") +fullstr = f.read() +f.close() + +full_mem = fullstr.split('\n') +res_mem = full_mem[72:108] + +matrix = [] +for i in range(6): + matrix.append([int(val) for val in res_mem[i*6:(i+1)*6]]) + +print np.array(matrix) diff --git a/setup_memory.py b/setup_memory.py index 356c40d..14c1a9e 100644 --- a/setup_memory.py +++ b/setup_memory.py @@ -17,12 +17,12 @@ [3, 1, 0, 3, 2, 2], [1, 2, 3, 2, 3, 2]] -matrixB = [[1, 2, 3, 3, 2, 1], - [2, 3, 3, 2, 1, 1], +matrixB = [[1, 2, 3, 2, 2, 1], + [2, 3, 0, 2, 1, 1], [1, 3, 1, 1, 2, 1], - [2, 1, 2, 0, 0, 1], - [3, 1, 0, 3, 2, 2], - [1, 2, 3, 2, 3, 2]] + [2, 1, 1, 0, 0, 1], + [3, 1, 0, 2, 3, 2], + [1, 2, 3, 2, 1, 2]] # format matrices to store in data memory Astr = '' From 8cee9d8287117f45d8c4427dcfd877e7e3c9c309 Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 19:59:33 -1000 Subject: [PATCH 87/98] fucking github pages is the worst --- docs/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/index.md b/docs/index.md index 0046bd8..6f1ae00 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,9 +23,9 @@ To run the program, clone the [repository](https://github.com/poosomooso/FinalPr **Figure 1** : High level block diagram of the system (components explained below). - +![](img/3by3mulltiplier.jpg) -**Figure 2** : Our core multiplier - multiplies two 3x3 matrices. The left shows the module that multiplies the matrices, and the right shows the module that contain the left module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. +**Figure 2** : Our core multiplier - multiplies two 3x3 matrices. The core multiplier contains a matrix multiplication module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. The heart of our algorithm is the matrix multiplication unit, or the multiplier. It takes two 3x3 matrices and multiplies them. It consists of 9 dot product modules that dot product length 3 vectors, and the dot products happen in parallel. The multiplier also contains a small collection of registers that temporarily store the input and output matrices until other modules use the result. @@ -41,9 +41,9 @@ Each 6x6 matrix is broken down into 4 3x3 matrices. The figure above shows the a The algorithm is performed and parallelized in the multiplier network. The multiplier network contains 8 multipliers, one for each pair of broken up matrices that need to be multiplied. It also contains four 3x3 matrix adders. Each 3x3 matrix in the result matrix of the above figure uses 2 of these multipliers and one matrix adder, so all of the resultant 3x3 matrices are calculated independent of each other. - + -**Figure 5** : The matrix manager that handles the main memory and breaks down the matrices. The left is the load block module which generates the addresses for the 3x3 block in memory. The right is the full matrix manager, which uses the load block, data memory, and an address register. It also has a block for determining the next address, which is mostly muxes and arithmetic. +**Figure 5** : The matrix manager that handles the main memory and breaks down the matrices. The top is the load block module which generates the addresses for the 3x3 block in memory. The bottom is the full matrix manager, which uses the load block, data memory, and an address register. It also has a block for determining the next address, which is mostly muxes and arithmetic. We use the matrix manager to break down the matrices and populate the multiplier network correctly. The matrix manager manages loads and stores to data memory. It also computes and keeps track of the index of the first element of the 3x3 arrays, and uses a load block module to retrieve the 3x3 array starting from the computed starting index. The output from the matrix manager goes to the network of multipliers. The output from the multiplier network is fed back into the matrix manager to store into memory. We store the matrices as a vector in data memory, as follows: From c7192b579370ca4a7f2430ec85428e43c1f703af Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 20:07:11 -1000 Subject: [PATCH 88/98] still the worst --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 6f1ae00..8fae289 100644 --- a/docs/index.md +++ b/docs/index.md @@ -23,7 +23,7 @@ To run the program, clone the [repository](https://github.com/poosomooso/FinalPr **Figure 1** : High level block diagram of the system (components explained below). -![](img/3by3mulltiplier.jpg) +![](img/MultiplierwithRegisters.jpg) **Figure 2** : Our core multiplier - multiplies two 3x3 matrices. The core multiplier contains a matrix multiplication module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. From 97f76bb490bf98b9de4bccb808dcdab75f6c4a5e Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 20:11:53 -1000 Subject: [PATCH 89/98] Updated loadblock --- docs/img/LoadBlock.jpg | Bin 65717 -> 65835 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/img/LoadBlock.jpg b/docs/img/LoadBlock.jpg index c39ed669a9df9b3d88da1848f93e70c87a916bf3..8cb4767cdb433a40fb4ca9325f37701182d87d19 100644 GIT binary patch delta 27721 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 From 935c32082d78f0d164de4f4406edeaa8cc574fb9 Mon Sep 17 00:00:00 2001 From: Ariana Olson Date: Tue, 12 Dec 2017 01:13:21 -0500 Subject: [PATCH 90/98] Small wording/grammar fixes. --- docs/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index 8fae289..793c4ea 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,7 +15,7 @@ After studying single cycle MIPS CPUs, we were interested in other computing arc We made custom architecture that can multiply two 6x6 arrays of 5 bit unsigned integers (or smaller arrays, if you pad the rest of the matrices with zeros). -To run the program, clone the [repository](https://github.com/poosomooso/FinalProject) and run `./6by6multiply.sh`. If you wish to try different matrices, you can change the matrices in`setup_memory.py`. +To run the program, clone the [repository](https://github.com/poosomooso/FinalProject), run the command `chmod 755 ./6by6multiply` and then run `./6by6multiply.sh`.If you wish to try different matrices, you can change the matrices in`setup_memory.py`. ## Implementation @@ -23,11 +23,11 @@ To run the program, clone the [repository](https://github.com/poosomooso/FinalPr **Figure 1** : High level block diagram of the system (components explained below). -![](img/MultiplierwithRegisters.jpg) +![](img/3by3mulltiplier.jpg) **Figure 2** : Our core multiplier - multiplies two 3x3 matrices. The core multiplier contains a matrix multiplication module and a collection of registers to store the matrices. A and B are the input matrices, and C is the result. -The heart of our algorithm is the matrix multiplication unit, or the multiplier. It takes two 3x3 matrices and multiplies them. It consists of 9 dot product modules that dot product length 3 vectors, and the dot products happen in parallel. The multiplier also contains a small collection of registers that temporarily store the input and output matrices until other modules use the result. +The heart of our algorithm is the matrix multiplication unit, or the multiplier. It takes two 3x3 matrices and multiplies them. It consists of 9 dot product modules that dot product vectors of length 3. The dot products happen in parallel. The multiplier also contains a small collection of registers that temporarily store the input and output matrices until other modules use the result. ![](img/matrices.PNG) From 54d7c1a827b81457e17f7a9c69df5e91874b8472 Mon Sep 17 00:00:00 2001 From: rdiverdi Date: Tue, 12 Dec 2017 01:18:02 -0500 Subject: [PATCH 91/98] added some text to go with the overall diagram --- docs/index.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 0046bd8..661552c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -9,19 +9,20 @@ We designed computer hardware to optimize multiplying two 6x6 matrices. Matrix m ## Project Motivation and Background -After studying single cycle MIPS CPUs, we were interested in other computing architectures with different strengths and weaknesses. We first looked at GPUs, which were originally designed specifically for graphics, but have recently been generalized to have all the functionality of CPUs. Graphics operations are essentially a subset of matrix operations (where the :With this added functionality, GPUs have become increasingly useful for machine learning algorithms and general parallel computing. In particular, computations on matrices are complex and time intensive on normal CPUs, but the extreme parallelization of computations in a GPU makes these operations much more efficient. We wanted to explore this increase in efficiency by making some purpose built hardware for matrix multiplication. +After studying single cycle MIPS CPUs, we were interested in other computing architectures with different strengths and weaknesses. We first looked at GPUs, which were originally designed specifically for graphics, but have recently been generalized to have all the functionality of CPUs. Graphics operations are essentially a subset of matrix operations, so GPUs with the ability to perform the same operations as CPUs have become increasingly useful for machine learning algorithms and general parallel computing. In particular, computations on matrices are complex and time intensive on normal CPUs, but the extreme parallelization of computations in a GPU makes these operations much more efficient. We wanted to explore this increase in efficiency by making some purpose built hardware for matrix multiplication. ## How to use We made custom architecture that can multiply two 6x6 arrays of 5 bit unsigned integers (or smaller arrays, if you pad the rest of the matrices with zeros). -To run the program, clone the [repository](https://github.com/poosomooso/FinalProject) and run `./6by6multiply.sh`. If you wish to try different matrices, you can change the matrices in`setup_memory.py`. +To run the program, clone the [repository](https://github.com/poosomooso/FinalProject) and run `./6by6multiply.sh`. If you wish to try different matrices, you can change the matrices in`setup_memory.py`. The final memory is written to `memory_out.txt`, and the result matrix can be read easily using `read_6by6result.py`. (this just takes the chunk of memory storing the result matrix and formats it nicely). ## Implementation ![](img/FullMultiplier.jpg) **Figure 1** : High level block diagram of the system (components explained below). +The overall system consists of a controller, which steps through a program described in program memory, A multiplier network which has all of the hardware to multiply two 6 by 6 matrices together, and a memory manager to load a matrix from memory and store the result back. This hardware requires a data memory preloaded with the matrices to be multiplied and a program memory preloaded with all of the steps required to multiply the matrices. Because we limited our scope to multiplying 6 by 6 matrices, the program memory is always the same; however, it is structured as program memory so that the fuctionality of our hardware could be extended more easily. From ce4cfe6602edb67089fbcdb830aeeaf3ebf2140a Mon Sep 17 00:00:00 2001 From: Serena Chen Date: Mon, 11 Dec 2017 20:23:18 -1000 Subject: [PATCH 92/98] added a thing about dependencies --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 7441351..646769e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,6 +15,8 @@ After studying single cycle MIPS CPUs, we were interested in other computing arc We made custom architecture that can multiply two 6x6 arrays of 5 bit unsigned integers (or smaller arrays, if you pad the rest of the matrices with zeros). +Before you run the program, download [numpy](https://www.scipy.org/scipylib/download.html). And make sure you have Python2 and Verilog. + To run the program, clone the [repository](https://github.com/poosomooso/FinalProject) and run `./6by6multiply.sh`. If you wish to try different matrices, you can change the matrices in`setup_memory.py`. The final memory is written to `memory_out.txt`, and the result matrix can be read easily using `read_6by6result.py`. (this just takes the chunk of memory storing the result matrix and formats it nicely). ## Implementation From d226dddef0d0081b89632b3b969ee86e33bd6b5a Mon Sep 17 00:00:00 2001 From: Ariana Olson Date: Tue, 12 Dec 2017 01:27:30 -0500 Subject: [PATCH 93/98] hopefully add working link --- docs/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/index.md b/docs/index.md index 646769e..c5941cd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -19,6 +19,8 @@ Before you run the program, download [numpy](https://www.scipy.org/scipylib/down To run the program, clone the [repository](https://github.com/poosomooso/FinalProject) and run `./6by6multiply.sh`. If you wish to try different matrices, you can change the matrices in`setup_memory.py`. The final memory is written to `memory_out.txt`, and the result matrix can be read easily using `read_6by6result.py`. (this just takes the chunk of memory storing the result matrix and formats it nicely). +For information about how to run unit tests and build on the current work, please use this [reference](testing.md) + ## Implementation ![](img/FullMultiplier.jpg) From 917a4503f2c733938a9ddd13190062f4580dad06 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Tue, 12 Dec 2017 01:29:29 -0500 Subject: [PATCH 94/98] move to docs --- testing.md | 59 ------------------------------------------------------ 1 file changed, 59 deletions(-) delete mode 100644 testing.md diff --git a/testing.md b/testing.md deleted file mode 100644 index 04c941f..0000000 --- a/testing.md +++ /dev/null @@ -1,59 +0,0 @@ -# How to Run Tests -## Getting Started -Before being able to run tests, you must compile the verilog files. -To do this, at the command line enter the command `make` This will -compile any of the necessary verilog files to create the test executables. If a file has already been compiled and no changes have been made to it or its dependencies, the file will not be recompiled. - -## Run Single Test -Enter the command -```bash -./ -``` - -To run a single file once it has been compiled. If all unit tests pass, nothing will be printed to the terminal. A notice that one or more tests failed will be printed to the terminal otherwise. - -## Run All Tests -The script `run_tests.sh` will compile and run all of the tests at once - -If you are running the script for the first time, you will need to type -```bash -chmod 755 run_tests.sh -``` -In order to gain permission to run the script. - -Once you have gained permission run: -```bash -./run_tests.sh -``` - -If all tests pass, the only output to the terminal from the script will be any commands run from the makefile and any notifications about .vcd files being opened for output. Otherwise, notice that one or more tests failed will be printed to the terminal. - -## Add a Test to Run -If a new testbench binary is created, it must be added to the script in order to be run. To do this, add the following lines to `run_tests.sh`: -```bash -echo "Running tests..." -./ -``` - -# How to Edit the Makefile -## Adding build targets -To add a build target for a new testbench, add the following lines to the makefile: -``` -: ... - iverilog -Wall -o -``` - -As a style choice, the binary name should match the target name. Dependencies can either be other build targets or verilog files. An example build target might look like: - -``` -dot: dot.v dot.t.v arithmetic - iverilog -Wall -o dot dot.t.v -``` - -In addition, the new build target must be added to the all build target at the top of the makefile, otherwise it will not be built automatically. - -``` -all: arithmetic dot matrixmultiplication -``` - - \ No newline at end of file From c8807fa711be38211e90ad8ac6d4cba7a157f878 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Tue, 12 Dec 2017 01:30:17 -0500 Subject: [PATCH 95/98] add python memory checking script --- 6by6multiply.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/6by6multiply.sh b/6by6multiply.sh index 62209d2..d174934 100755 --- a/6by6multiply.sh +++ b/6by6multiply.sh @@ -8,4 +8,6 @@ echo "Running the BIG test..." make ./multiplier6by6 +python2 read_6by6result.py + make clean \ No newline at end of file From a1ab4b868997cf3a37bb85b134de1dd1c9bdc0e9 Mon Sep 17 00:00:00 2001 From: arianaolson419 Date: Tue, 12 Dec 2017 01:32:52 -0500 Subject: [PATCH 96/98] Moved to docs --- docs/testing.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 docs/testing.md diff --git a/docs/testing.md b/docs/testing.md new file mode 100644 index 0000000..04c941f --- /dev/null +++ b/docs/testing.md @@ -0,0 +1,59 @@ +# How to Run Tests +## Getting Started +Before being able to run tests, you must compile the verilog files. +To do this, at the command line enter the command `make` This will +compile any of the necessary verilog files to create the test executables. If a file has already been compiled and no changes have been made to it or its dependencies, the file will not be recompiled. + +## Run Single Test +Enter the command +```bash +./ +``` + +To run a single file once it has been compiled. If all unit tests pass, nothing will be printed to the terminal. A notice that one or more tests failed will be printed to the terminal otherwise. + +## Run All Tests +The script `run_tests.sh` will compile and run all of the tests at once + +If you are running the script for the first time, you will need to type +```bash +chmod 755 run_tests.sh +``` +In order to gain permission to run the script. + +Once you have gained permission run: +```bash +./run_tests.sh +``` + +If all tests pass, the only output to the terminal from the script will be any commands run from the makefile and any notifications about .vcd files being opened for output. Otherwise, notice that one or more tests failed will be printed to the terminal. + +## Add a Test to Run +If a new testbench binary is created, it must be added to the script in order to be run. To do this, add the following lines to `run_tests.sh`: +```bash +echo "Running tests..." +./ +``` + +# How to Edit the Makefile +## Adding build targets +To add a build target for a new testbench, add the following lines to the makefile: +``` +: ... + iverilog -Wall -o +``` + +As a style choice, the binary name should match the target name. Dependencies can either be other build targets or verilog files. An example build target might look like: + +``` +dot: dot.v dot.t.v arithmetic + iverilog -Wall -o dot dot.t.v +``` + +In addition, the new build target must be added to the all build target at the top of the makefile, otherwise it will not be built automatically. + +``` +all: arithmetic dot matrixmultiplication +``` + + \ No newline at end of file From 1e3f1457b7d791428b591dd5fd7705b060dd0815 Mon Sep 17 00:00:00 2001 From: Ariana Olson Date: Tue, 12 Dec 2017 01:45:10 -0500 Subject: [PATCH 97/98] Add section on integration test --- docs/testing.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/testing.md b/docs/testing.md index 04c941f..93fb2dc 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -34,6 +34,20 @@ If a new testbench binary is created, it must be added to the script in order to echo "Running tests..." ./ ``` +## Run the integration test +The script `6by6multiply.sh` will compile and run the integration test, which tests the entire multiplier. The test works by writing the data contained at the memory addressing corresponding to the multiplied matrix to a data file. The python script `6by6multiply.sh` reads this data file and formats the data into a matrix,which is printed to the terminal. This matrix can be compared to the expected multiplication result, which is printed to the terminal by `setup_memory.py`. + +If you are running the script for the first time, you will need to type +```bash +chmod 755 6by6multiply.sh +``` +In order to gain permission to run the script. + +Once you have gained permission run: +```bash +./6by6multiplys.sh +``` +When run, you will see the input matrices (set in `setup_memory.py`) printed to the terminal along with the expected multiplication result. At the end, the actual output of the multiplier will be printed to the terminal. # How to Edit the Makefile ## Adding build targets @@ -56,4 +70,4 @@ In addition, the new build target must be added to the all build target at the t all: arithmetic dot matrixmultiplication ``` - \ No newline at end of file + From 4f48db1055f8653670cb1c82a578d39e0561e266 Mon Sep 17 00:00:00 2001 From: Ariana Olson Date: Tue, 12 Dec 2017 01:53:39 -0500 Subject: [PATCH 98/98] Remove unnecessary lines --- multiplier6by6.t.v | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/multiplier6by6.t.v b/multiplier6by6.t.v index 3d3a818..eab15b2 100644 --- a/multiplier6by6.t.v +++ b/multiplier6by6.t.v @@ -7,23 +7,10 @@ Test bench for the full 6 by 6 multiplier module multiplier6by6_TEST(); `define CLK_DELAY #50 - `define EXPECTED_AEBG 45'b101011100010101100111101111001100011001110010 - `define EXPECTED_AFBH 45'b100101000101111101001001001110100100111001100 - `define EXPECTED_CEDG 45'b001110111101110100111001011000101111101010110 - `define EXPECTED_CFDH 45'b011000110000111101011000101111101111011010010 - parameter NUM_TESTS = 1; - reg clk; - reg[5:0] success_count; - multiplier6by6 dut (.clk(clk)); - `define AEplusBG dut.network.chooseres.AEplusBG - `define AFplusBH dut.network.chooseres.AFplusBH - `define CEplusBG dut.network.chooseres.CEplusDG - `define CFplusDH dut.network.chooseres.CFplusDH - initial clk = 0; always `CLK_DELAY clk = !clk; @@ -33,15 +20,8 @@ module multiplier6by6_TEST(); $dumpfile("multiplier6by6.vcd"); $dumpvars(); - #50 #5000 - if (dut.network.chooseres.AEplusBG[44:40] === 5'd21) $display("success"); - $display("AE + BG %b", dut.network.chooseres.AEplusBG); - $display("AF + BH %b", dut.network.chooseres.AFplusBH); - $display("CE + DG %b", dut.network.chooseres.CEplusDG); - $display("CF + DH %b", dut.network.chooseres.CFplusDH); - mem_out = $fopen("memory_out.txt"); for (i=0; i<1024; i=i+1) begin $fdisplay(mem_out, "%d", dut.manager.data_mem.memory[i]);

=`c?%vE<2!->S}`|tiOY7X`08b8TIXE; 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 E04V-zs{jB1 literal 0 HcmV?d00001 diff --git a/docs/Full Multiplier.jpg b/docs/Full Multiplier.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ae3c041763d157b5fe5b6675170463e01ca6b49d GIT binary patch literal 54160 zcmeEv1z1$;y8j?0CEY3ANH>E42uOE{2$BNQB@7A((v36{(j_G&N_TficXtiLf3fd5 z=Wf{hp0oG4=ec*E```F19f!5ntZ&UX-}}D5c;|BTat4GYBPlHjg1ZF*!2y3jmlL3e zpxa1D$ViB{k&%&6P;R55<6)qqp`jDw;9}yDlTcESlaP^7(Xum8QM1yJkumZ!vEJk4 z;o+fV5EK>Q5@F}&;kr5r9102wIvP3=1_lw=U9!7ezx(I%8wmS0{3yZ?csOd%Eo?Y= zY`Dut5G8P(h;Tpsfd29WcMBc?5efM=3Mv|~Lm3w6792eMEd+Q(L<9t2Z+GDLAOvhg zoV%R&k#Lm^kg09(xZZ?)yiN0<_&dIG-wrMJbKAEls04&W#3Xd|42(?7JiL7T0)j#h zA4y0`J(iYHQB_md(A3g4GY zo?VR#4g~)n!vg;PkAdA77d9}iTL=j72*_9Cg1hAeZ1C6!h<7=WaPBK18`$7dbG^BZ z_aN+J@plv&Zsi^P=eB*Q1hhP}bh}qW`)OpqZD4QzsgeC{VE;L;aS%E@9PsABV}rn; z<1@xoPt-rRKj=Lu&>oQu&>RsFKX%fN+2RN%ipG$c!+UhjgW*|R6;iWd7kmIW*ry5E zdA~Znzn^yrnpxYw1O@k9f^H`zUV^|vJ+M24;FC>|mC~O({do)ioCSY=5U$n&-K3JV z`{~-_KeVRSa=F$BY+(DUl~FRaou=P%TUFoYNzv3gM1qtg@cwN#bqb$L(A^N+OVFqs z_#pg81q{k^~6ve|R%EDS?R}U4o8qi!MR^Uo32kpjww8 zDmTbE$|z)2m$y#PSKr{VfAL0p!DbixJn5; zMYz9h_)=Pfl3^d$NMZxJ2ps!$UEIpIM>C3(#+pD+Q;T3jbA@N{rqd^UF_)mQtaAv9=vrJ zgMXu^$8bru31y8Ex)P38wr;chD*=bCSA4L$Cm#Dv6!1g#7AOS5x!(G$#oy@kbgbO# z=XVQ9Paf`6Hx9d=uk*)nnPG_=d-C8&(1t(G>nj5J>LQ_YNm&UkfZPcs41oJ;4nE+s z03WaQT!I3XE_|{sLA_%@t~;FzhH(PxxH{z#LE0tgp>fG2$OCx(q=|A=JLCc*uIJ(m zcxoOGSa<&MX`+1R6;82VKfDAz>qx%98*D4ZkeGG21bJtwN6?T`u!v9^!h$XQhH5Yi zRy`K6N??}_aLK>j#{)qhvung&B+vH6v4-gyeN0M(}@Hb z?{Ft2+O<5z{FpnH+f`_vj4kKjHkb80Q0`6&J5`B=FhbF*5n5m1l~rnbpaDxOVZ-zhdif=&PxjZRDxB|J z&nf%_5J}}5EXbp?1&LkE3omxafy#}& ze}3dY@tEl5I}~;EJ^a;VfyjduNOnZ)F1$Cu2L&XPd0+xaE5$Ud-jVW51HZv+Odc4j$ zR4FwIcL_goR1JDRsoy!?B>mj^dz)dh(m^ic3+8Y5Gzb*$D(eu;j?_umdP_# zSlE1~EE&srZeDhmKG`PCtU_DW)xEwgtKrp3_IY_LVyH_VcvP`+Cahc3ya;M?38H53 zgKQAnU4l~MJo#DL=wp=1V^oG8n43qBPvlM)_T=`A@ydn`e(%U)=C1~YSI)vmzOR;E|B6I<>s$$m&W~p1}_m#$3N_8jGkCpAP zl`5SO2*DW3B7WXD~#~*dRA>a)*@eAd0xhv|75aN31 z`uBn+hQl2nX)0{5(ohJeZl*sE26e-C7)^EgKz>@4JKwT@DJwO0j>^m(NcCvc%gc(tCP{aQR+{C|BS%D$QIy@!l;AN!-lZ$8ygFN?xe>p)nMkBodt(E zvRdaC_?z?R!5+1rKh%?Hm&XLXy?uzxQ-@Vbx{d3MrrvijMj+hbH`2j6@zB!YdFAF8 zCjI6b>zPYX0|(yd$y>eWYioKG<9B(BEnKL>rS){v*l#*DWU#}3=o_-i|0zdAAwhvz69xfCpn6loyOKzm=~4a zluv%upnw`gM4|J#^2Img3vY#&4k?)Gc~ZL`Z}9iWq;nobq<@t~ZoTzn-t0MN!tQYS zxkmgXkavzgW$A@{<`vv7L#r;W2sszCrh|542R6Mfs#zBP(gbpqz{k(C#z^OU3^PnO z2Wp%jRJP{YAjVYx|Mqq>9_QT**uVM;zbFBIfo%Oj8I|A2c3of1)E5m-6ky`Vlt;LA z0B%=#6)As~9u+|We2bdnZ}}Gh0o+)^e!lmA^YNdt>ld*r`XnTO`owAWs5ocU>w@og zq@?54Smltc;V7qAf`%WIcz4^McK1=7QGk1%_LI*&w5Y9GMBz=}9TmA+l0U$IITR?& zFbbl7KNp2R|4J?D-9z|6>`4vY8Fv=>0sDYY#YJUh99chdiSDXS60E5yz7hn1kW+|K z&>$04As48wJr@^OFv9`FY7KnAv<^N#0)UE;;j7BvqWTJ~$h-n8CcrST)X^3IR6Ixm zc89zKfQpNsN`rrNmN)EmS?TQ4I|1f>GbU~wCU3SN{fIUs6~Sfs8Vx_Fi;};`h3jC5 z%}RbGZGKMEVI3bm@n+f(Ty8Oxdt)BjmAP~$a2%3btD0H9marppO)q9W8jov2FeQ5S zk}Lb$w$Jj9S`y%dXDm})4hy=pB{DA}+G}F*6Ap#dzFjcFJN`E(?_U$OKPU0cNeudB zRRH;^DsZZr+N;(X&!SVbZ7foQUwe$d1i|>qxuPB4ld;CglT9(Vv?f@w0Bi>nGRg(OT@q}+4wU@g#(SgYUY%~!20OKR5tr~`_K!Q3woXK+Nj z2S@m4f@E40`?kI|xmntkDAgM8z0epZSyNYj<#v_m^HMejkt*&YH%uAI_P;-W*~b+0 z&~mzL$bb1FYrR^kz|2d{01F1~E(%i->IDmBvU4a{u5T zG0BI;%x+^p?U|R8*u0bcYI0EBB>B0QAY4;dz3DOQLknS-9TaIg zP?jhf#GX>ce`xcm<49qu&ic6fw{y{p;g2G7(g&4=G&Mf3xvao~Ib3r?N68-_fIOdy zD$pxT!o>OYWW~FK5*PF67|CuL-Wo$R+zryuTk;@5as`>bf609RbFSZ<>%R!W0JQH7 z1PDx-r=RY}y5bC;s`B64g_ zNx^(XO<=IGOVI8axWa+*4DT@c{2YMbTh?v;K@G5}LCA{AFl2i(`4U8#cJ8DEz^4j; z%%iRx0`;i4iZcJ`9N%K}2bBq}PbA7rcera8OTHb0S8oAeLyK#7E&w)YD$GpD3)^H) zGS&s9-3wc+=n9{B1s*jy>T)f+Nl$^S91HmdU#sNnI2$&z-HFeUA1-`dWR5LuMdQhw zn2AC4n&T|XZdi-p&k0y=-wih! zV0UUP;4j>Y&pD(FVo8mp9WXNuPV#4Ama}E7xla-K+^|;Cq^JEeR%iAhb0CC6n^e}O zJ|Rax>S_BGljWaj}K47$Nl$2`VK#!6bQU-Oa%pr1oFnW!c47X^Y#|5I`?_jAy$14 z{Pu*tP_YDl?0I#6e%OcY)lP zr+52V%is+hvL+hrskwRNPgsZ$qQ$&WUBn{cG9`>S{CT84yOj-oyqD%Ty0A4VDLyem zYb&r|r_xZcs)6lNH2t0SIlQfwKGh=>#IK%j#Zr2aeDFIV^){KGs;YGT*7nxW4AK2< z3*v?Lw3T{$})X0{xvt1{Y&jh>`-SBPYCKtE~eg< zFz+3BgC1bRq;15Jp?5v57$=J>#_4w5NgQ|WWK0Bu4&A;5tV0MsoA;K1Ie!LaJC_^&d6|3c7* z%KZes?D(8$zt;a!+{2;vCJ(YE+3>l!873mu#TNYcLM*r-!*fnci^;lAKas1Q|Pr&exw+ zQtmJE!#uCvLu)|onZgcKpq|+L<`eMdW0(zU37XsIMEKyhjt_0F1ooUr z9&nu9TAe;YO`es4(zp^{z}as@5fygwg_!oFiYc}7q1)TWCO`j88VtJ@4dz+p1iO`a zqMnFnD^=ufT(MtQ8=Jfnw4#52I8e8P53UdS`Kh(-mD(u2AI430!;Xw0_52?py@UYr z|4sE0gbJP|?X6ou%Y@7@LwwBoq-fochb!i_Nh0f+c}8LJiDGeFY*rLsHn2th!r)j_a+FzYEo=kP ziT8%gsy0Cwuh`i;PQ~@K#J17}$|iDjtUz4l0J0jdtFu`!GJK;9?YC>urV;8-(nZNv+cWO@4WFm;&I=@iDnwNR^8KlpYPU( zh7qu1*EQ4B1nSg0AHPE8{pBRUO)&^8c4&^@xXGyoOMc{&kFUr`#Z*+vW(g+k^o z0W$5=RcN5ZGpC^2ne^4>yabu+JVuznV>AjQ(42-(VVvq;Q` zJS$c(t`~`V6DM)!6^ig%rtM)*Q6c{{r#wx~cx<~@H2nLw*}f{jZeiBEgG_eIrA21H z{3O;cW7XLGez-L4E>E0!7<_1S8>2dyYVmE7aKtDecUx1{U?cR;vn)8A=;$)0`83vK z$q{vAqF$zj7pghWR_zs>R;xAe+In_MUqw!=LkZK4%GjHSJwV{;C%zYGRFoSL>*C~y z_}|RLnCfbaisQD`D$2t3u@s);=XbcL^0?e;yeFn!@Ac)(ZTLsV{5JZkkoPcu+y|`` zDtTpM+Q-}joes*`m!MnJoLt-;MTKe{6_%ClOK;`o%SI9mDs*&Pg!rIM~mLo!j%To7JEP9xi4wS+>ML?E(; zVqbgOd0r-1cTfy}x07MEJY)_NXIctx#54Ov;F8pjZ_LzhrN6DfrQBKaU*J{n(|#m& zXPCE(YerW(vw7_8VzVTxOQfxS7Vni=EqQ5u3oK$3uJa~v-ygKG4%U1Jv!JSSE_2}z z;UdlRTM7wneT-0Wf8A>!lhN?$QUVXI$yusi zjO5GCQy&o+MgNOvIkBl9QlEojKQyO@%j`+#C*Q~)c${wl!T-BCfH@`FxQ^!26aW71 zA1oH8WpvmLs0fd`@+$?DzAZ!?(pNDz^wuqK&H*-pOjx*1?@x-wKa2=a({&sAP6SvD z4fp}_RMvkoPt*zakb(%PXW}nGt8`6(Bjum7n!x#50F}#d{*|JY&`kcL1;Lz%mCJu``1pi52eoDXBWRWp8YVbQluF zetJj8#q@%7LA4DOIPd7{AJ94iS)l_$G(1rEuaT9N`H*OYaEI$dR+8=H{X6$~r_WH# zrcVF~DbzKD2FPhsqOZ~qOaK4H9DEzIJgUK~Au@+D)F8Scdk>YAkrY=FLW^BoMc^jyBukGl$@XTOk>2P2_k+Te!M<0vp z`Uypts)lxd(!m&ertyeD`3HnGBjf=qySUn?PByGQ*7-i;t@G+;DhdRRH6K3QYY2{Q zwhLy==EvD_HXX6#FRP=BxFC!ZMd-rm3@!Deb70NVw0g!Fj{J%X%&A0om=K1dyoMB% zzUTEG4sk!I^00^KFb{$+GOT_yo?j}*Ivm`NEh&rqz!NfU%zdJ6m7F2^uFfKjxkOu> zP;sAgFBp2X9y;-)+vLG>+WS?M` zNMq|1WcpHzfE`QN6!+t@2+j8&bf`(eC7UnqifwHiQpyjFt7P&sPQ}ifGUMygxVc7C@2xzH0fxYYTj!quzuEH^*(pT2b$nL1)W#6b_w3i(Ffjp(L_2e(L47+|lDWiAF^(QmE38=>ki z{X{&BaLWizcYe_@VlT->*S1)l2rn!j^>>FPhr^MHJYlgL7hE*kz%i!D=o2w`ba(cY0o;Hgi+z`%s z>{yk+Z`*={HLNI^M~egL;cnH-B<7uP&J|a{J$ZTwdgSJ16=UPqnG^57hxsH#X83ka zXL}04q93_ODcsy}^6u^gDnwplU#y$5`D+x#L)xEF=Tu;^f0Kx&d{Wjej1azw#B&4y#7Igkd`kbPvJv zLHRvQa+Z?aX=p?b4j|ZJUcVB5+v6!Be|WlD;p+5Ggm+$#0GIybC$mtxsVaw>QpSvd zi^cPfEllmX1Me@TJDCmcdWV8MwPHU=Thr?_3DnBNCVg0mu;4)&PS!6+dhNZD5U_5G zV41=X)1CvdUt~*s7)Qu`w(2Z+1k=F#`kEx*=x_K&yJ3r&@Rkj$P(>&2>5aZ}I zB7DNL%40@yNB)$WLKD2z>5q9nw6PLE;v<2YmI4n_#AEyh!ZZi%%97ubqilB6$4m`O zA_O{o+4h~&eVpJ3r|Q!RNjPdO+To96^H2wiG;v=Nhu<^=-r*J`A0VrbuT>0J&AD-q71^vH- za`~(J;qU%ibT|!o<_ux=)_`X&2EX!V^aPA;zeD?+cVVIwAy>3d<*BRNM%{!!SHA5i z$~_7f?*1kpwPVoUVThMhx_}l^GQkoR%x`2!^9*S+or3Tcpdu!TeL7C6c;wM16wlGp zv0Ti&rf=2@Da}jUmz{`B4GQKbuS9hhoXcvNd%QHXVQJ`1YLV*@(=&CfHI%49v33P8 zR;I1`K7Q+_8sT0XoBl?cwmH8|Swa6paZjxwq@HU1qu!{LGmaTMLg*9R3mJBNRZJrU z5Bd_Tj0pV^sNj&ifV>%#C`a0e$>H zRjtu|c|Y_&;34h3K|6sT&q?MVr@>p{NyIlywv=p<-yQyBZEd;f9cP);Bcvub8oeyg zwoFW!Xa=d521<8}s}P!g2_nhAnSm(8f9xTY`LXA82tLZ8D2PesglXOs`v%2=X5_oDvKL3@YHDhsCUAcunjhJp=V80q(ADZDp)Z&iyPw92a{+)_O_%27Ot(>i1!zArIA z_ZBSZxA-EApGxk&^!G7j(x9H8u* z?ts9Awe3|F-P?|eU=k;npxA%3uTuNDZ<+5NM+>yGXH&N43}g;I-kZMa*>U4V22z7H zCPnkWVIJTmW61UE4Y_vYFaSV)o!vBm1^@*HH}|>nKFpIOdqp#Ed({ zO*go9E)f9e8z}CU#5Yv55gxhM2b3{CZ;77f6l?}h83SA--OXi)fmmOfM6#BSAVZpe zKqGU`N`oKs=v`jS@%x+(<7bu8L^Ns-N&H3&bg`q`5R#-249P9h^Wu~5j84f3SL@O` zA@gIkaI@Nx87?WhdBQbwPxHv}7Zn}eMca2jQW%k%h9N6C=w#=EOA4Z&QJu?3*@RTJ z&!n8a-gsBUdYCBl;#?%6C|>c)TQ|vZI9V6s4_WhBk0%Pjybc=U?&WEjvWBmGH}=^3 za~x+Jzms!5v83-R%;ylvlQScgLP7RX2CW`YW*=rp(*6h>52g-e8n>xF(Bsv2>pLa; z;p5`s#;U9!R^B-I7zMlK$d*77WJ25w!XF)$tMlF5B!5Dv(Hd|!^bxy`v8)vhMJ$8= zaHc#vb7v2+dZP5cN}sFde`NB%!g2rB_B{7)aziXP$fN6wh{ zNhV5OG@fW~2_W!YWhFTYHortIIXdTz*`2)6j&ag{}T^x@VnBxrqR|^HOAbTBUtfcj31>8V~xjvtzu=z!wu*BDx2`=thmw)>AemJ zz^_oH`ZLA;m&ww9l|=pQ`QK{-y8c=E^*$K?XHy*f_mHJ&=Xd111;%g3EVXC7afrs% zC-E>ELXnHfB`k-8H`xc2I7z+TcX15EnY0<695yf^z)zaQ#nKPI8)P7o-`hWRiJC1B zD-Gx%I^<7MT6z?*MPc+P7>?#7h9;?&CDFH$AJfhvw?jC?n^VHtiNHgNrCIO&F><^9 z33fqMcl)$LIl)o!?RkU*qi|_K+K4vVW04`_Ui+4!FU1x-d=*@=86gbli(a@RgQ)Kx z$PWu;KWA*}7-#u(&N8;WU*5t(c@$aYeNQ*Yc(FMiVUI3qyydf$i>!%Vfh&kJiLlJE z++VpHpIY$&BegO5e8?PCLb6JP8V8Ro>3UCDXUY4{=Uh9JZ3L<~;=)8Gh#|`w&wSWs z9ve;`T2y?p|(uO^kQ84}g@m1z%A_XozQ>%9*94GgFTtsC*b5B(}Pn~$CiFF7!n zG&d{~(qCDKd%`VVw3AflPLPOFttT`)tWN3R{qnxrd5%;O{?zsE0?J3PHk6y@aLnY^ zm%7@QX!{Q%EOX3uC5+3D2V|zr%tk-cCQwEgqrhL}X(&htN_~jqonjedSYLRtc4j{! z#4(nqMX-cR7QK0QhU*>;t)syABl?p0oq>rp*C%0*lV6m*!Eq3rqLIv_0Vf12e8KNm zk{$?fdeK0rj`d1G3euzlBkf!`NJLtePvUbYlna+goSX`X#xY1p*xWnwbTz5aUS~{A zpi0eqU+5R*VkZkpUYni)qKuN~KZ)>P^}YDLeJg%r@26il*8cZ;F&V7a?Gf#?TzCV8 zfHXUc?R5<3s(;DvF*@LPnU{|{j09LlsQ8aRmhcWtow@a~rg6dKE4K=h7O7%-j!f5t zFbYn9fXH%q8BxBhdhd>Hq-vSAWwjfJ`oW$ks{j6CzqfXyV}*K^-e9qr`jWyX z@;Jgf>42zH1(gIC{*)HAl;JJO&{S6QTlKa9EfPlunJAT3fyDx*eHE;QkoC%_n{Y}O z_cTLr8Ms(yqEkNJq^>(LwPoANCXmLYE^}V{sRvM;i%$sy26o`i1r7<)8j^5@S6OW9 zFI_Pc*MHl$yk2*J0kA2ez}nVD)^Yam2zRS)hYn^8FfG@9M{(o8&boApdiN0+LS5%T zYKh2&6YLEj{XhnaCgQXnfE6MISRpr{FpLw7Iq(`)r~;s&m{V_nM*%KsB&q`DD{40U z!l(B5C}V1KLw(n!s0oLbnOoi>C{+jMKhz%|Sn!%MYQZLRE7+ce$dsoOGx7DJTK5*q7ywU zw+Sh5ZhG#VW5%;$>ELI`C2hKqA>L*{jSs&I;n>T|7nXCwa2$Eiz*|G-fO9hI7t%o^ z_DLam%}gduxhx>VJ8;!aiaqFJqOfCID633P%tf8idebPZiuy@<@;8zSU5>X~o6X7T z55^1p``r@>H-IJxGvtYAF1}&Yi_1w-Q!1Ha&Xa*w zuimO16(W2=Te?^R1s?NqMnCyyczfQm@8#Yh1Y0Y?!>B!l04QT4fgw^BTI{Eg}u7DZnJ#j%H842h3QFc z%Ym2s3wb7vFDln-bu!C^hGUNOmM@SGDbJ6AlA<}M?Ap9mv3b(Yn}Kf>Gg;T#3G2A3 zbznfP3@4HG?|fe~n&5+`3fQ`$NEKFsSZ9yai+mK}r`f0L*;P)Iz&C00OLbaqnn<0}zwKBt*dq1h;15V+&}L^!cRe zC&C>87#sCXAmgS6V``i_cVt51*awGmtgW1i&o3Q=;#i2MoS3LQ+r7!Kq$naG)?=5T z9&)Km5Ml)-RDuK<>XiXVU?%D=7{g1~G`KbRv$E=~2wa7&uI|k=U{FsI3W1?nflvIw z*Kz#Pl}s}y*w;Nl;BK&-j{s_P;~OWZoH&B)w*cV!cgvPb5H=uuy*glLDGgelc|%;tUR^C@kN!GOpg}sPK&m~pl0@6rRon5HXWg?z%9_6K!-TIg z{N1w!r`EzpFEo_%;8eaNys|)R+HJw~d@UYEor=M=jG6}WSk2K+97>)sL;diAnCX7` z(TKHZ9lUF$EX#RE*V8rry1_ofTIVq8l81MCoe`lWC;NJO8l|88Tc1!*ov&&exAk;R znYFW(JvSZl5$K53t1Z7!;X2IMcBkHXEWd725*sdZ$M^|8@%sKPsaY-AJo9XG)`dzH zh-rm_6IGCh0m%!2W~A4x@jJZz=0bV}S!_P-#RU8Ljm`q6F#DL~1{?($DyP(C<1s91UH&zLJ% z|KITQ|4swp^;O--ml@l}@U&^T+2F0U_m$#mtq2MG{hq>cEFXG# z$vwv1WjdO$CpJE-MYE~n?|n?-LJ@w$V8|}GOgU`H&>}`M!ZF;UFq9fS``xrRmmv;W z*~b$zt~1XQxy2eUdDeP9ssrUiADpv9it0MA!34?VC&Yhz-cwB3) zd04c-Z}KE%Sal#)-oxVjFP&X-thu&d|f?<$`A7 z)oGxB)*mH+>`z=R)ltAwO{jWWMYgM&zs(O(IH3os;)^!`D=S(?2_@Er?Ak+~X#p|B z5{My48kA5y!WirIElM`ZC5SDcQn(T!p5N+$xtW7cxB&P6+zRa5RTLQyfuR?GPpUZB zr$;8qN+Gcq9hac+D}~_(8u)Y*2qH7>^OvB2wCe}gR73P%+4jLqjyYhDfub8+#0rqf z+{d6OIt`fJ}fIH05A@EG~87w#o~MKRYMo;v{) zGmd)VeG?N5pU)E$xvbAhUUzp(Ki3S`1eEqk3a&{BYT=KD!xN>YUrqp@``8bE#k8(t zbm|lL)L8A_tZ-Sx?LN&gbeT!UZn1Vk5C0TzOTlYXs}MPff1NRTG`@;6nO_j^_o#(dL>%5`!HN5NK_&JK7B9k7XK^9xzwbGMT@;jn3zfzPY^4EoZfLe3nX@yA~0;x^m=S z!(3QjbsCsGY$SXovZG7pfnO{qE&4uNM)e?O35X1zjDKr6`D^?ASz`WmW?cQN5$_Dq z8>qo8JPDE5#UFIFsUD&q%qw8O)0*k8%L&&5kcU_b8Lo0tyfyqxpPdb(xB`G!UF8q7-=zR&|YHbMP`dAf7xs z>qU+;jRwq{^(edeHR+vINqM^S+lH@*bK>wX$`cD-3&fqxQpqNx2RJ9Gcp<-qi zYGF6yM^gJdmqmYNH^MXgmOxegJ?ck9I3=H!C$5UfA>*q~gbi+Rsp-!g1z7C zexFLqhT!znuru|T_caewoKpwt&mixtHVd{dL8Y4}75<}dkHYSDlw>X4Bc$>Q{!*y; zNOQ!TQE3G9JeIr$`|+L>y6JYu=PbmpnYAG2PVnv;WFws)7Q{0_TG4w5Ce$%cx>wqp z;VwTnyIII;7*=55q10Q9`28tg;5<>2n??j7bWfqSZY!jA{qXoxhb2OH2rFl6t8HF8 zihd@b{sj9RwC0OQ?7)!DRRfU1+-T{Ku*q`J=qIxn%uq+y`)eKJlw^IG(cnBs7gVzT z(mkLPcsJ!9ZV>Q6%quk;KU;-LhGo;T%cHd2Edp)0DqFI3_z2341B+==RbZx6(qW!) zu&MF`%j9>gl`|CHWUt&7)a-XLYT{}W{Utjq6j?j?JQOv#nJ;A0lIvrH*bLT$$1L5T zLH;aB<-6oV(5z@7{Wy{__Rq&~Vp1k(qlYMftM;QA1)iB9cB?9Z_(XZ~ljBq_KRC^^#Zp2iArZoREj%2q6KP=&S)QZ#wTe)P^A>Bx zWkS8}70xcKFBsxJxslFJs8j)3A9~8aZ+@#k>#|;kxN%=|yIng5P^W~8dad);C0=ZF z-mtpi-SEr-)zRZ4%)DWk({Tw?4e!S&D${Y-h)M01FrcOC90bYPqoqFX0;+8TNP7pktq#MbdAnRb)wyh1>J2ExtPHK zD&cy5NBK}$sVKU#J07Q8C|?dQ=E4pP_0;g$6SUGfqYT`fte1v@WylHUrj@G`51b30 z#8?W+9o2i^vK7;HEGYM9PD3R31NamRLHolC9q288#+-ZC^UmMc)b20Zl0S7KKL@D( z-eVSmOOSl6o}^m`UPYo+{xDjA%cALLymDeaH9xTMEzZ@}{2V43ex3}q0VhfIH=pD( zMy1iWd=_FeMgu#Gy`WSTwCD~3XX=bQi5spMLwWr7^0&wF^Xb|eZK!VhJ9j%;K{ZG8 zB_3uHc~NZRTOsyz7|wqt&&JweAbe%B+)NMVhdajnW{jzcd)8Q7bl{w z*g|{nTkD(GS$C8;$K;XWSD0Oyno-$T{J+Ew`3F|HUV;+q;NvWXT9g1CE62Sx|3s%8`@Lj~_|aYUWDHaj0^$mdY`AJ0y)f`TX`p_ZW4BnnBW?+xV_mLz1sm&s%^U;VEfGmss$xvhMuQd`R>q zj!vq?iHbJRi&ln9e)53atiloz^>thMMoi(Voz>qr0%hBYHT~5O0}x5qY&zE*Jc7y3 zjuc@IfS@oe^JXVf6=~~&52FxMO$s5lfVUpL-33xlOLkvBCEP{(v8FDU2{D<(#(nT4 z{&jgP0tIHJ3Diumbko?3OoWb*!;D-Mf`R$y)9L%Nc-KwcEx{SX0<)p-)AXNS^UsyP zo$Ir7`e7yYCbo6l?%f^G(fod@-Qo(-OQC{|MN5sj?v2lHQ;HC)&<{VI7H=Bw6QaIq z5ykwNr;jBxZWisDW4AZ zomo%ZDDl*Bm0^g?Hq$_|P-POwoud5(`B@1(bziEV=Ucz?@t^GS?_!rVkIxQ-tST`Q zC&QW$qPrL!k%he&TLut@n^gEf>r7dvzARR~FI#evx*@1n1_CAf!Q@hHt&0oc$d|k> zhoU5~tv&-6!*J)#6JdR`yLR0!^PmI95IKmgAL*2LLrs{KSNt0e!qlNq3ZrBVA=TmrJwM zvbO$CxT*dD3BW`%ftz!+Z}c)ySz57c>aVCtynxIQC;xockP~Shjx!9vWQdnM{})ts zcV7vnaa;&{bd@eeTs1uy23&`4q+vWadk2-)(Y*fZ%S^5{*8xqYk5Pw5;qY zz3FY4O^?K{+KF`d-K*n?Q_BH`GhD#Oj8@*NzklpT=8HuA3G(yw-wWTk3lL zkf`#UeU@XJf0=kJq`EqAS#;OGt7JFZSGJTNwE{OI-EOkvG4{kOhT9)KjK6h@DYbr2 zU%&6bEa*rtvnE=HTbf#wKEgp4yr#n@`l8$?-S5c&$SFmT&gR$&-9+%HNx#p^q^5Vn z%IfX=r8ne932z@Giy~^rS+&+XyVQ&HLxh?srJq3l@6eeO?Gf zfy8D?{C!(P-*wr|jT2p0E-vZ!V;YF913f2xQvUosV?(JO$0~ABvIDS6a_nE>kkCIL~={SAgG$c!ws>k1G3drpkt7Z+525g@%-kN3-Gdr_Hq^bnPp zyf}f8m?6YG?HWynub^Hz$Z=q?&REKF7(Vyoab!*O31Z}%1lfVO=?upoK2@(W5tehE z#tMOK{oJDm=DY?zVY|X%8LzW>1F4Bu{95Z@*|^B@i!7CL4DpI*_UoSD13lZP)Vp63 zvreoVT{X+U2Co8N-65QxkVVh8W)nrRK}f#dtED!W3sT*=PexL|``V^qh7ybRahBJU z%KEHtlvU<(@@L?0{oD{;Im!GhidI`RFvRRKmwTP0YNSJ$m{fA11b*xjO%G^yfTI z&2hr<-PxtkmM>zr=fDcvcB6J_`TF_|v-Xw6_ByNDQ`m{N)#+h)yTDxF<(>B3v^v72 z-Q}9#P2+h97tW_^@cE9-petoIB2BN(#;UbV&a`fQ2yUv(UD7931vPok4i)dXnXD^y z2=jDjYM?I?H_=AOciC^2*B+K1G4lJFR1fjcmW-E=$WSbBEd=dWQ=gMHpPs2*Jk)>J zpcbHTk0-o}Dwq{YSFB^>gIx zO!F#q?dmYmq4xSUoX2?ClAwqLuJFvHT(47f6jkYCx}Mu>5;{||yVb4}kdxNl2N^nbmlwKcxYA9?-Tino({wxBKAIh?V7*8h7bJV*sTGL}U8~VXP@IZ2 ztgh00Qpi6R6-j^8W*Ewk9WIa3tRNrd(cCYLhGroUK(slh8CtyH142LFRYMd$Z`OQo zaB3;-2qYo;A4Tz$w8?&ZpSJ60((i1te3KRgnnj=i%_0~8(^(v3m9F-uUJ-w!uO!32 zP74AF#Rz19b2j80r4AOZ``f+_40}?i$-$DXX7wwRVp?HN*jq4jmsdl%VqxboE;yd- zlk^ML#+G9wcjQCfdGxDc5TxnlVA-_>565ADp*&q$yekI zjw6g*pYul*gmlV}I`^!EjX?L#3?PZ-O0wai0cTx0I)Ii_W;!g{FimT<2X`X(oj;rv z8lP>-GQ(iFG=0jKovEnKlIZY7gD;i?6X}f-Oxsb%+kqyv7C?6@OAD0e%-MEK!m+uj z+8L{r((L$8zS_KbLCwu@TzoeF$)(x6>g0L7K$<^cr9ZFFGl$^kU(MNHk?xBGQrPII z0)4O=G~+tVxLH^DEFA}M`I?lkO~}}6TO@>F`ZTPGqP-f zPwAx&GhZ==QkjPy6R=viMymDdgG~ z3h2#SxsX^6Z9Zn@A>=aC&S*w_;_P-*wBw5w{GNW`{T6O^CD( z9o=(i?IyD4iL2_ZvQ>(+)sSL_-5q+gt4V7kIuiS;kjHWHyJkC__mA5Q&OMzrUh56M z?+d%SqpbS0o6iDG@6#5&d2?FvY>zb6e%UMT$CrMd^K>TB1TKvK*WP!>HIc6W1_42& zh)S<3AWe!$kuIx%fHXmRQ$Pq1dPfY1ARry-2uN?CNbk~n@1ge^iqfRSJMKAqkHI}2 zckkZc-E-GJ_#`t-CX;ub_nr5Bo^M%{kHVT1y0pu^xn4oQHg`mcMy06!Gwy|WTURU# z>GlxUF5tm1lbtJnh=iqu6`Qs8=4>j74dj>`NiBG-et0-?3yt0q>zdW z0B|_#BI4FE{@~7`<;|5w5h-=npnUGw1xBigJ&h+dIZJ#%vEIL~C_iM9ba0Y+VIn?c za8TrF)$P`2&JX2@`c_nL=&Yy=t72!+w=SB2{4<>tY^E@brnpxM$0$O7itZ!B4R*p; zN1LFwDLk@v%%a5vfk2cX<~lBU6(gOZbG0m%1<0D*(#6ru&}NPJ5g1~TQMO=eNv>Ca zzvN~UVZl`YHjG0QAW3+d8DD-30H&NWbFjPeUNoW1f zNB)z`a^o8iZWP+B)8Xa`Iv@r}07c%Aj0fN!J$#>e|N8)vi|0#zY{!S)sl&4?QwM;p z-SOi<)E{RGMA_& zkOAN=$UOob4(mp~zy$YFtVXIR78-=*)TopLT(^Ia`%aVj0LxDRZS#e#5vn@>ZxwSd z`?Yy%kFcb-(odtwXl?qc7ome^TGYG-B2SV%o`q+4FatNyQ2!ICI0|tK%QGyuamst~ zK8=zg?@W10=KLMu62oMX_xeSAfPRY)Z?4fS{VWJG?#;@4!IKc0eM%(GhKs61X1Y7! z&zXLpvmhd>&O*NM0*!Hrw_;q})^xUpbQm;sZVZWeLL4^S_WR^)>;4QI;jM58$Z-MQTQPCoLlKfWl;&6ZR=DlRYpVi(_R6pvDb)BfnGv$AvXfFuXGg4uZ+FYBQ zsF?|d)B9Z6@E;teHqY&F-~-=%v;Hml)r9% z%{j~iCNUE-#v)$%zA`>Gc-h4DZGKj}QODq5Ma3Gd!s&GtQM0Cey0*zS7?LqT zFU1BYBQc7c5lSo*bg>Z5g4Pe)=pH!8R{+x(8FN2`pJ9G$qp}IJAgOAd^ed+rc_bd< zBNq$>C#uTb`UEL3fNZp~I7beN`vej=8zEX%*2K9MfUNNZf2oT>G|Ty!O3?*oh|!;SQJ(PLG?;vnn8KtFcw*St##)mu3Q zc(B69>IPh+uQSg|y(?`!#L0`hGGHKXyA@E_R!{4b?M(+Pr&(ycou3Fq)FbREo*^~V zWq1e8%$ZV#MaJAj4w|JW`m-PPbB~!~pC@HYR7;w){yF^}#{N6>XwU+O`EL03+4wB= z0~uAR3p`cu$~`?9w0ZqY@ljf5gkJ{i=KpPP)*lOGRWGxp{z~Sgk%_DAFHK1whFRke zDTDk12(A+o?Yj##>jZ<{UXW0XVC7?j=H;;LW8$XL(F z*-<6r9Q$8HBc*-)+)tY{dgV(F_{G!~lZo?*V7`o+Us^3S~PZd>I~5D=I&Tfij6a zJ*T7^d2sM>t%&rq2Md<=ZlAe+LNpKfCX<_wVsUnq1m5 zFzolX3*VM4XC~1je@@G>`8_!2XyLztFqp~G0%4XGDP)Avqhp34yVi|yKN?(~fVU=6}V8YhtV zt`?Af7gv7Ro*(u^COd*_&<+`~Y9njP(+#kYuOesr&0~z>8T17U0HLeZ3E}*q!WtBA z&;uBB-gywPX8@Q(N#4?=CY5^9H3E6&JK0PG79s%j8clcpG1PDp+5-h}JT>;fdetNlg@yE4&OUeL z#UG+RMc;{_Hczs!vSH{R&A9`n_kH6Vne^1&O`r^M=Sw;?`4@CTZ$L#Bpj_p$TAbiJ zhxHF4Q~QpfGl59>C7>|g50ut)R7DRdiPF?VQMVsZjr!|)QO9Qi!yhW;@LPy3ro;js ze?#tIQ}Qtx2L}g^FbfDix*+B?scW}zK=dI{u3NN3$4UvUv%<{RLJ*L;j<@BlgdxnY zjOK%HGaK@Eq2u3L<-)5XkPVgWh1h;%k6W3RO;zm{+99K#wgvuhL!7c}XA3Tk)w(86 zz_r?4se&cps_ZEqSsq?m%#_vy3M?CGvlMJ}iqD32E7KQ>;#Sfgow?GWk0r9yNqVSo zwuneZy2e#rUZ%MquGfIRnQ{(asQ@TA;!EBX^84V?sQs^w`k#i&U;qF288+!kOMUy` znm+StGd|~A5WUK{AyAx#t?WxuV37g`3WmunMmUbBT4K|cz_D}BB=@5-MF|1*IXJSp z{$+;)BZ6dds7103I^~)buvXJoE&yuTz8WKvl*~8MLhhLb>x{YNc2({cW3QL;(e*56 zxfJ~T6ipN2ndc6KFL3H{Uz7)rcmzqN^H`U43L@#NSt|OviK7G7*5t)Q>AJ;s84RdX zruy6j1pbZ27bgOB=*T;@jVj;u&y(EXuK9?)2HicZIh4n{0O%}3fgYnWbx64bhQ22p z0)$m|p*wNpw4WDbfFENetY(LQjR)vvX$I9(2cOe6&%ZSV7?iZvSDks0wps_EPOtyw zOyjqHP2KR$*b1PJr6j9nSkXUkGkp%guk9tGLPth*Bi2g8u6dc7 ztcQn!qM`ypAX{GMDt+{%A1<*mQvM1zgv$~{<7om#^@{-*UaSPCJY#51`^5k{Y4rf~ z2E{W*^0Z$Jz-`O>1VXj3={;p(11OjQhOMYJHUNkR#lhys6@6D5p{#jMw{u}OcRL=- z_}I!2?~rBqq<)Ey{{4v?o**Olj|!NXKrsJxq<{;GTxm_}dR~sj@WU8C%tnt$sPQ)Y zJ)=^;J4R;@BWFSqOIj=Lo&axBR+mEX_MrXhnQkYR-Y)U2?qxn!btc;vYU(k#YWqFNHC0*+3 z2gfW;ui4oP{SveV3b{Sg6i=q(B=d}Jl#v_cF^w{?m)O*sIi4SN&CEmi&t_#I+Y z*gO`$`fU~e;DSF-?RtuB8+@-_~azfM3evyBhQ{dY#Ne=I#VerA5qK8^-Fzd6)&Abr{(r-beUGEGMsPJr+ z6~DSkUzTwG=iWbH(^M|*wQVgrUpGsdALOeZ8A7CtHV|?PeV_-E025e=yqwuQItzq& z3aqVmOUY|X&Yu`NWO9(r@IJr#6>81g>6ZE}*y``L+3WaLZ|Vgk8(Jhafer*Pt@|8} zQBpeD!}6+!uS5QfwNtjM>Vul%L9-o%Kofk?#rtY(%*#~I2l~bX@AJ#(qa+{p3_wk` zRZq|WXFUoT;F<;ig|deyS&h0oX8}V#2nR3(DDLGFL3=0wiQwA8nqz;U&Zt5IuY3T= zbwMZq0x|G2-}BJ?bx$JeK-knZ3Qq`i4-HJn)-7_(Lb}2Eka)lym^Tp_1V#mPz#)(q z7!`uk&*Zunv9ihBDR*Iw+#s}L?bEqBUc=K7P`R_9F5m0Esm){cl%m(J<~;cA$jTwL zU%r$LTRpU4NGGRZ4k=uL%e1Gc`Il`9&}n?S^>+QN<8BP>E?7X!<)xz@^GOyv$Uj*R zIyY7m4P`0&Gw%BXZ5fSi>adiFRXzdsS9*n>OF@#Echxd8^xYuu7|{n5uw;LWv-nrr zr>F%Vn;esZ*kLHuvLHg36}U=wXt%`m9WxI%hPs+2+iW0gCp#)$(@a;1%)<4s>Fh7N z2T7<|n$l?kog9DVLk#qSmK?PyXV7?rMbo0;u+{46?tm5B-!VR4>-CKY%pZ zU4Q@+)NTo&qx?i=fviyl1P*6VB|i(ag>_f$We}f0UZO|FfFKB+?28j8txuq3OO@9T zD*MfN@ZuqFi_1n|$Jt6B*$k6W+R}unoMwk2=qLO(r4@Zc!71<)&5erBVBIfeMo}yq zl|IW0SP6ZpM)0LoqvV$#{7PHk^f#X((tRy-@PFyltlH3)UBH53glivg!GsT0HFgjO zaqr)d#FcT=k-$k}L=W8n9Ej4?Rwf1dF~h>D@$SPMK&3DU4~m!P(XQG$qfH*IoTXw>JLZi@G9`Zqq|>>QqQI{38{S zSB7bNt9|%p8SF7<3zvYKsQeZW$uYfvXy_8uM1!;hGRZ*7NY=d2$sPf=0b8XzwUa~$ zH@~K!3vp7wrb8#C8(4xDu-QUx-}8`iu`P^q5xiOy!WWbnVt=u1Ox|{9No2f)S*`Vc z!hF9gEOUJlS?;6-NA~77Jsm#Fm+bTbYtj-YFatw>m`BJ)l2iY(?~Ga!5q~{C_Mz|G zRBeRLoeL=)Kj{~dP5WsjSW%z_mJ8KyzGt(A%Z84CEj8QP`awF6b^Pfrc1aHUaL+K8 zY_gswlz9G=v(2I*oGG#JCXiM6C7*|z#c^R}{}7p$Shu-1!7X8=qJ=BqMIrwbyE|2! zoY8w{0xG3_zsX`pGI&lk$gEX`#VT%;Qk5q2z*N)Xg2|y*Jeovx)e&>h-GrA?5Iz3| z%3Y}|80g(tR8A?Po<%q3G_NOK3x71HVB98&k^M}nfb@*YNT$;3F*QGZziBt;I~xAk z@UW(M$~QT%IVpxftOeDH!lfxwXz0DdK?n!lbbxG)LF`zY?gCm}7EL`aYsi*}Cp6jQ zdV4xJEVga?4Kf#Kktkg40*=H`zhuP+ zyOnNkw8TS%-&4AmV(g1ZO?}(T9A`MktmVyO=ax-eVE5a)CXC`{h_6P`;)*=18es_# z9&u&umh+f3^`=m+>`#nQiL2Wndjpo}Sogiz|C4+Dy2G@e1#R#HrMhT0WM6RMIfh~| zcWY9yG33z)+#40r#N3dCbv+UNkegkcAgm-4cxO%^M3M;@ zA(kM@XjxXR!a@HAtLz@FF-~85)T8QEZg!LTHq6K~ne z#Vu_)t+cvPd>2yO#cJtjNC~^+nVNt$I#e?yexi9^lMDb5hu!=*xQB@7GrN^0mGkn7OV=eYSGh zMEVy271~ofiVelDbpU=T0P647dGT8o5X|y%iu60zEZ;hLfJK^9u5(PgtiZTb?uLw%i`c;pxF2= zr6+K&e2B33uj(D&RAK_Sqw|4!|9yw@r{sAxH*4s5Zcsdpaf%mMlq#2j^t({nA%?eL zY|dS#h--~!u4Na9)BW6l#*&o9Ww70XVbh#Tq_GC@5EzlQ5jBUrLnTaBDtSp7CW+}2 z@D1xU`BHLU6RcYjZaxv~59cP&V{g-)u{T)Pvy{iMYb8>dx;1z$vDgOtH3Hc(sb!5@ z+|9|A@dyhrw(*;-kY*9~t?EjNRF(;2u!wir=fBC#n)R|MZm&%^4FSs^)dh!z8Wmeo zh=gf5>de?4F=58i5!(lAF|m3XM3H@1duQ%~fhVF6j zXSOA(ej5$yhs77h4v##-13!qCLElS!m-rjLhG++J;S;F!7e6nQ??xR@bhH6Nz#qMG z)E>qft%+^+#4Z(EXQpJOBS-1Ydr$&IA;vcN^oq zJDLYr0VjezW74yJbS%Ei%ZD`w(18lPalT9A^_Lb9v64)+6l$4y)W@8n{_U*(|bcJHpC$QY2Xn$^uM5|wpd5`<4~PP1Z{~{BQccERl63+zg)_aHdnzVDv)_K{ z0B2FoGrRGjopH5U@Ti$DR+oljoFaXtfzbk*Rd6ifq>r+deg0+6pe#&AMK;KZ>)Q5u z*P(CSR%3E;@xDv&toz~wE(H5I6C8~tN>Ge{F2LHV(|oXTLTd>os}$qw@EID>^2=jC zmvajc$mb~&xn@!>l48ryyHFZE)F_m!bU8m!s>Bi$o5XkjDMEf0N@7a<33Qp8ibS@Q za3#@rW&kT3wkVXjo)L16RP948%@YNzWJN6?5#GRtE>~4v61>SE!#nC^V_`&}r^#nU z@0)x^@X(=AKJ#Gib{_|AK{$AWeS@vBvy#|;Q?Tp#^kr;(=Sw?_ZUQWtm;V&nGf7bic^T)3ylx-ju)|bZYGo0h~l)cm$SG<%C$iscl#>g#anWm1Y^Sj8f z8dG_l7r*$1uHRiHJuyVej9>b`Lue@=tJ7^2Q(xHgDR=*dUcL#-tR5 zVU@Z|o$$s=UPdsg`?*~iVnOq@Zi8&PbatApRiRuy^G<__$6E9*;1^$)9sEQzb&Xu2 zV3vkZZR&hhIJqk<+q@);?jnrvIxk|{&3c@2iKyRER|;}tme|u`&oq6ucq<}2aSeAn zURXrJ5M+)XAk5mooIt>mU-Zfmeb$$hQmEW3Q^Ab?Ndu=Oj2!>4-Q;TDyn|*B1$Q;jVp#qjqyOEXi5WF-$j)G05X|F`3SBg;OItJX3#Yv&T zC{|T-o5ktL%|l&($V0F}KNVs_U-u&zquv;6_@a}6tE|Ir_gXb61gexDvZhq3%{AI* z)E`XJ9(M=Q(ls*SX7zpv>x>&ot;V%zg6G+08**zyO2T7tFrnv_&kv6~BzthCe#2My zM{xhU&hQ<+tPd)$bqn5&7{6E_iEx96S{@`_Tzl4m+O_nx$5AT49E9dG0I)XWb&HO zSg*Xzprj@!S@0of$i2`xgSqXvwUD?RY}Bpf{IsWyMqkLZz#Ogn{<&roZN@s1AtY~) zovA#|N;z?iLCHC81!?~q5rJsq>9rs?P^(br{jmc@AVTkm{2>dJ;#fqRz3)>g7eu7JCJ9Uv1jj5uGO(vQ2IJ2}H2cr@kU} zwFK(Q_FM%Drd9|M`WRq<9$A;O?jCn*KhwG9`7YV9p-cLdqj`TrxRMx-T1sbMraF<9 zz$-m5+$rAab9>n_^5<9MDDrw!q6*tx?fbRLqnk$B-<~gwx@+9y{{CVzqGirP8np6e zdnhH%(RcsuHg6cjxLD&}baI4!#96iZJ9fISh_Hm>2>7XYwMA%6_KNK_hG5AfVu_Pd zYo9uyFa?C#Pwja1hnwU_qyL+L`qAkBreXeYsC~!z zzHaou%oPpKE|_8Z%JAM$zh*5rZV4}ptGuPRSYq@N2I-4jjlffwq+ejB-@+sre@3)^ z6O;7g6#s&F{Z-lmb?%;ya{n^R<6h3ns!CV(=kQc9>s7c<2Q{bMC1uS}dS;H@Mers8 zKl)dyz>nA8Pp|mVWgUC5d%MB;71Jnh=Ct5@LwMT1fNF# E7g1t4R{#J2 literal 0 HcmV?d00001 diff --git a/docs/Load Block.jpg b/docs/Load Block.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c39ed669a9df9b3d88da1848f93e70c87a916bf3 GIT binary patch literal 65717 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û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