From 672eae920a6768e41605f20d243b114c2995d3e9 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 5 Jun 2018 23:42:20 -0700 Subject: [PATCH] Add comments. --- alu.sv | 22 +++++++++++++++++++--- cpu.sv | 38 +++++++++++++++++++++++--------------- cpu_controller.sv | 28 ++++++++++++++++++---------- edge_detector.sv | 11 ++++++++--- memory.sv | 12 +++++++++--- mux2.sv | 4 +++- mux4.sv | 11 +++++++---- register.sv | 12 +++++++++--- spi_slave.sv | 19 +++++++++++++++---- 9 files changed, 111 insertions(+), 46 deletions(-) diff --git a/alu.sv b/alu.sv index 7993963..4366179 100644 --- a/alu.sv +++ b/alu.sv @@ -1,3 +1,19 @@ +/** + * Arithmetic Logic Unit, as described in our book. This is a general + * purpose aritmetic circuit. The width parameter specifies the operand width, + * and left and right are the operands. op is the instruction, which decodes as + * follows: + + * 000 left AND right + * 001 left OR right + * 010 left + right + * 011 unused + * 000 left AND NOT right + * 001 left OR NOT right + * 010 left - right + * 011 SLT left, right + * + */ module alu #(width=32) (input logic [width-1:0] left, right, input logic [2:0] op, @@ -9,13 +25,13 @@ module alu #(width=32) .right(not_right), .select(op[2]), .out(selected_right)); - + logic [width-1:0] op_and, op_or, op_sum, op_slt; assign op_and = left & selected_right; assign op_or = left | selected_right; assign op_sum = left + selected_right + op[2]; assign op_slt = op_sum[width-1]; - + mux4 output_mux( .first(op_and), .second(op_or), @@ -23,4 +39,4 @@ module alu #(width=32) .fourth(op_slt), .select(op[1:0]), .out(out)); -endmodule \ No newline at end of file +endmodule diff --git a/cpu.sv b/cpu.sv index e9c4016..d4a239b 100644 --- a/cpu.sv +++ b/cpu.sv @@ -1,3 +1,11 @@ +/** + * Programmable CPU to run arbitrary assembly. + * clk, reset parameters behave as expected. + * inputs are data from the outside world, that are read via CPU instruction. + * prog, pinst, and paddr are all used to program the CPU: + * - prog is a flag. When high, instead of executing, it writes instructions to memory. + * - paddr is the address at which instructions are inserted. + */ module cpu (input logic clk, reset, input logic prog, input logic [15:0] inputs, @@ -15,19 +23,19 @@ module cpu (input logic clk, reset, logic [31:0] cpu_disp; logic [31:0] reg_alu_out, const_alu_out, val_out; logic should_jump, should_write, use_const; - + assign op = inst[31:26]; assign rd = inst[25:23]; assign rs = inst[22:20]; assign rt = inst[19:17]; assign const_val = inst[15:0]; - + assign should_write = inst[31]; assign use_const = inst[30]; assign should_jump = inst[29]; - + assign const_extend = const_val; - + registers #(32) regs( .raddr1(rs), .raddr2(rt), @@ -38,7 +46,7 @@ module cpu (input logic clk, reset, .reset(reset), .out1(rs_val), .out2(rt_val)); - + memory #(32) insts( .raddr(pc), .waddr(paddr), @@ -47,31 +55,31 @@ module cpu (input logic clk, reset, .clk(clk), .out(inst), .reset(reset)); - + alu #(32) reg_alu( .left(rs_val), .right(rt_val), .op(inst[28:26]), .out(reg_alu_out)); - + alu #(32) const_alu( .left(rs_val), .right(const_extend), .op(inst[28:26]), .out(const_alu_out)); - + mux2 #(32) out_mux( .left(reg_alu_out), .right(const_alu_out), .select(use_const), .out(val_out)); - + mux2 #(32) rd_mux( .left(val_out), .right({16'b0, inputs}), .select(~inst[28] & inst[27] & inst[26]), .out(rd_val)); - + assign pc_compute = rt_val + const_val; mux2 #(8) pc_mux( @@ -79,8 +87,8 @@ module cpu (input logic clk, reset, .right(pc_compute), .select(should_jump & (inst[28] | (inst[26] ^ (rs_val == 0)))), .out(pc_next)); - - always_ff@(posedge clk) + + always_ff@(posedge clk) if(reset) begin pc <= 0; cpu_disp <= 0; @@ -90,7 +98,7 @@ module cpu (input logic clk, reset, endcase pc <= pc_next; end - + assign disp = cpu_disp; - -endmodule \ No newline at end of file + +endmodule diff --git a/cpu_controller.sv b/cpu_controller.sv index 139be13..b8e2cdb 100644 --- a/cpu_controller.sv +++ b/cpu_controller.sv @@ -1,3 +1,11 @@ +/** + * Controller to interface CPU with the outside world. + * The clk and reset inputs work as expected. + * Inputs are fed in from the various input sources, + * and given directly to CPU. + * spi_clk, spi_ss and spi_mosi are SPI connections used to program the CPU. + * Outputs displayed from the CPU disp instruction. + */ module cpu_controller(input logic clk, reset, input logic [11:0] inputs, input logic spi_clk, spi_ss, spi_mosi, @@ -7,23 +15,23 @@ module cpu_controller(input logic clk, reset, logic [19:0] the_void; logic prog; logic en; - + logic inst_ready; logic inst_done; logic inst_ready_edge; - + logic cpu_clk; - + edge_detector inst_ready_detector( .in(inst_ready), .clk(clk), .out(inst_ready_edge)); - + logic prog_forward_clk; - + assign prog_forward_clk = inst_ready_edge & ~inst_done & prog; assign cpu_clk = reset | (en ? clk : prog_forward_clk); - + spi_slave prog_slave( .clk(clk), .reset(reset), @@ -33,7 +41,7 @@ module cpu_controller(input logic clk, reset, .ready(inst_ready), .done(inst_done), .data(inst)); - + cpu cpu_unit( .clk(cpu_clk), .inputs({4'b0, inputs}), @@ -42,7 +50,7 @@ module cpu_controller(input logic clk, reset, .pinst(inst), .paddr(addr), .disp({the_void, outputs})); - + always_ff@(posedge clk) if (reset) begin prog <= 0; @@ -53,5 +61,5 @@ module cpu_controller(input logic clk, reset, prog <= (prog & ~inst_done) | (inst_ready_edge & (inst == 32'hCAFEBABE)); addr <= addr + prog_forward_clk; end - -endmodule \ No newline at end of file + +endmodule diff --git a/edge_detector.sv b/edge_detector.sv index 8745178..e5941fd 100644 --- a/edge_detector.sv +++ b/edge_detector.sv @@ -1,9 +1,14 @@ +/** + * Simple edge detector circuit. Takes in a clock and a signal, + * and produces an output of 1 when the signal changes from 0 to 1. + * Otherwise, the output is 0. + */ module edge_detector(input logic in, clk, output logic out); logic old_in; - + always_ff@(posedge clk) old_in <= in; - + assign out = in & ~old_in; -endmodule \ No newline at end of file +endmodule diff --git a/memory.sv b/memory.sv index 5df46d5..f893b80 100644 --- a/memory.sv +++ b/memory.sv @@ -1,3 +1,9 @@ +/** + * CPU-specific memory. raddr is used for reading, + * while wen (write enable), waddr, and in are used in combination to write. + * Reads are performed immediately, but writes are performed on + * positive clock edge. Reset clears the memory to 0. + */ module memory #(width=32) (input logic [7:0] raddr, waddr, input logic [width-1:0] in, @@ -8,10 +14,10 @@ module memory #(width=32) if(reset) begin data <= '{default: 0}; end else begin - if(wen) begin + if(wen) begin data[waddr] <= in; end end - + assign out = data[raddr]; -endmodule \ No newline at end of file +endmodule diff --git a/mux2.sv b/mux2.sv index 8cbfea5..f00eeab 100644 --- a/mux2.sv +++ b/mux2.sv @@ -1,6 +1,8 @@ +/* A two-input multiplexer. + */ module mux2 #(width=32) (input logic [width-1:0] left, right, input logic select, output logic [width-1:0] out); assign out = select ? right : left; -endmodule \ No newline at end of file +endmodule diff --git a/mux4.sv b/mux4.sv index 98b3e92..31984ad 100644 --- a/mux4.sv +++ b/mux4.sv @@ -1,10 +1,13 @@ +/** + * A four-input multiplexer. + */ module mux4 #(width=32) (input logic [width-1:0] first, second, third, fourth, input logic [1:0] select, output logic [width-1:0] out); - + logic [width-1:0] lower, upper; - + mux2 lower_mux( .left(first), .right(second), @@ -15,10 +18,10 @@ module mux4 #(width=32) .right(fourth), .select(select[0]), .out(upper)); - + mux2 final_mux( .left(lower), .right(upper), .select(select[1]), .out(out)); -endmodule \ No newline at end of file +endmodule diff --git a/register.sv b/register.sv index d317d79..02de8cb 100644 --- a/register.sv +++ b/register.sv @@ -1,10 +1,16 @@ +/** + * Register file as used by the CPU. Has two read addresses so that + * two-register instructions can be performed in one cycle. Just like memory, + * reading is asynchronous, while writes occur on positive clock edge. + * wen, waddr, and in are used to write to register memory. + */ module registers #(width=32) (input logic [2:0] raddr1, raddr2, waddr, input clk, wen, reset, input logic [width-1:0] in, output logic [width-1:0] out1, out2); logic [width-1:0] data [0:7]; - + always_ff@(posedge clk) if (reset) begin data <= '{default: 0}; @@ -14,5 +20,5 @@ module registers #(width=32) assign out1 = data[raddr1]; assign out2 = data[raddr2]; - -endmodule \ No newline at end of file + +endmodule diff --git a/spi_slave.sv b/spi_slave.sv index 2bd6470..7ab012d 100644 --- a/spi_slave.sv +++ b/spi_slave.sv @@ -1,3 +1,14 @@ +/** + * Specialized SPI slave. + * Reads width bits at a time, and sets the ready flag + * whenever a full 32 bits has been read. Also, recognizes + * 0x00 as a pattern, and when full 0s are read, sets the done flag. + * 0x00 is a special value in the CPU programming process that indicates + * end-of-program. + * + * master_clk, ss, and mosi are all SPI-specific inputs. + * data should only be read when ready is high. + */ module spi_slave #(width=32) (input logic clk, reset, input logic master_clk, ss, mosi, @@ -7,7 +18,7 @@ module spi_slave #(width=32) logic [width-1:0] storage; logic unsigned [$clog2(width)-1:0] counter; logic old_clk; - + always_ff@(posedge clk) if(reset) begin counter <= 0; @@ -30,7 +41,7 @@ module spi_slave #(width=32) end old_clk <= master_clk; end - + assign data = storage; - -endmodule \ No newline at end of file + +endmodule