From 7590cd0cf3837ebc7c041695a36934f17567fb5d Mon Sep 17 00:00:00 2001 From: Austin Morlan Date: Tue, 3 Jan 2023 18:26:45 -0800 Subject: [PATCH] Add SAP-1 code --- build.sh | 58 ++++++++++++++++++++++ src/adder.v | 14 ++++++ src/clock.v | 9 ++++ src/controller.v | 123 +++++++++++++++++++++++++++++++++++++++++++++++ src/ir.v | 23 +++++++++ src/memory.v | 24 +++++++++ src/pc.v | 22 +++++++++ src/pins.pcf | 2 + src/program.bin | 16 ++++++ src/reg_a.v | 20 ++++++++ src/reg_b.v | 18 +++++++ src/top.v | 97 +++++++++++++++++++++++++++++++++++++ src/top_tb.v | 109 +++++++++++++++++++++++++++++++++++++++++ 13 files changed, 535 insertions(+) create mode 100755 build.sh create mode 100644 src/adder.v create mode 100644 src/clock.v create mode 100644 src/controller.v create mode 100644 src/ir.v create mode 100644 src/memory.v create mode 100644 src/pc.v create mode 100644 src/pins.pcf create mode 100644 src/program.bin create mode 100644 src/reg_a.v create mode 100644 src/reg_b.v create mode 100644 src/top.v create mode 100644 src/top_tb.v diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..0592427 --- /dev/null +++ b/build.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +set -e + +SRC_DIR=$(pwd)/src +BUILD_DIR=$(pwd)/.build +APIO_HOME_DIR=$(pwd)/.apio +BIN_DIR=$APIO_HOME_DIR/packages/tools-oss-cad-suite/bin +COMMAND=$1 +VERSION=$2 + +MODULES=" + $SRC_DIR/adder.v + $SRC_DIR/clock.v + $SRC_DIR/controller.v + $SRC_DIR/ir.v + $SRC_DIR/memory.v + $SRC_DIR/pc.v + $SRC_DIR/reg_a.v + $SRC_DIR/reg_b.v" + +TOP=$SRC_DIR/top.v +TB=$SRC_DIR/top_tb.v + +if [ -z "$COMMAND" ]; then + mkdir -p $BUILD_DIR + pushd $BUILD_DIR > /dev/null + + $BIN_DIR/yosys -q -p "synth_ice40 -json hardware.json" $MODULES $TOP + $BIN_DIR/nextpnr-ice40 --lp8k --package cm81 --json hardware.json --asc hardware.asc --pcf $SRC_DIR/pins.pcf -q + $BIN_DIR/icepack hardware.asc hardware.bin + + popd > /dev/null +elif [ "$COMMAND" == "init" ]; then + virtualenv .env + source .env/bin/activate + pip install apio tinyprog + export APIO_HOME_DIR=$APIO_HOME_DIR + apio install oss-cad-suite +elif [ "$COMMAND" == "clean" ]; then + rm -r $BUILD_DIR +elif [ "$COMMAND" == "program" ]; then + source .env/bin/activate + sudo tinyprog -p $BUILD_DIR/hardware.bin +elif [ "$COMMAND" == "sim" ]; then + mkdir -p $BUILD_DIR + + pushd $SRC_DIR > /dev/null + $BIN_DIR/iverilog -o $BUILD_DIR/top_tb $MODULES $TB + $BIN_DIR/vvp $BUILD_DIR/top_tb + mv top_tb.vcd $BUILD_DIR/ + popd > /dev/null + + gtkwave $BUILD_DIR/top_tb.vcd $BUILD_DIR/top_tb.gtkw +else + echo "Invalid arguments" +fi + diff --git a/src/adder.v b/src/adder.v new file mode 100644 index 0000000..1a0a495 --- /dev/null +++ b/src/adder.v @@ -0,0 +1,14 @@ +module adder( + input[7:0] a, + input[7:0] b, + input sub, + input en, + output[7:0] bus); + +assign bus = + (en) ? + ((sub) ? a-b : a+b) : + 8'bz; + +endmodule + diff --git a/src/clock.v b/src/clock.v new file mode 100644 index 0000000..451d6fb --- /dev/null +++ b/src/clock.v @@ -0,0 +1,9 @@ +module clock( + input hlt, + input clk_in, + output clk_out); + +assign clk_out = (hlt) ? 1'b0 : clk_in; + +endmodule + diff --git a/src/controller.v b/src/controller.v new file mode 100644 index 0000000..02c94f5 --- /dev/null +++ b/src/controller.v @@ -0,0 +1,123 @@ +module controller( + input clk, + input[3:0] instr, + output reg[11:0] ctrl_word); + +localparam SIG_HLT = 11; +localparam SIG_PC_INC = 10; +localparam SIG_PC_EN = 9; +localparam SIG_MEM_LOAD = 8; +localparam SIG_MEM_EN = 7; +localparam SIG_IR_LOAD = 6; +localparam SIG_IR_EN = 5; +localparam SIG_A_LOAD = 4; +localparam SIG_A_EN = 3; +localparam SIG_B_LOAD = 2; +localparam SIG_ADDER_SUB = 1; +localparam SIG_ADDER_EN = 0; + +localparam OP_LDA = 4'b0000; +localparam OP_ADD = 4'b0001; +localparam OP_SUB = 4'b0010; +localparam OP_HLT = 4'b1111; + +reg[2:0] stage = 0; + +always @(negedge clk) begin + if (stage == 6) begin + stage <= 1; + end else begin + stage <= stage + 1; + end +end + +always @(*) begin + case (stage) + 1: begin + ctrl_word = 12'b0; + ctrl_word[SIG_PC_EN] = 1; + ctrl_word[SIG_MEM_LOAD] = 1; + end + 2: begin + ctrl_word = 12'b0; + ctrl_word[SIG_PC_INC] = 1; + end + 3: begin + ctrl_word = 12'b0; + ctrl_word[SIG_MEM_EN] = 1; + ctrl_word[SIG_IR_LOAD] = 1; + end + 4: begin + case (instr) + OP_LDA: begin + ctrl_word = 12'b0; + ctrl_word[SIG_IR_EN] = 1; + ctrl_word[SIG_MEM_LOAD] = 1; + end + OP_ADD: begin + ctrl_word = 12'b0; + ctrl_word[SIG_IR_EN] = 1; + ctrl_word[SIG_MEM_LOAD] = 1; + end + OP_SUB: begin + ctrl_word = 12'b0; + ctrl_word[SIG_IR_EN] = 1; + ctrl_word[SIG_MEM_LOAD] = 1; + end + OP_HLT: begin + ctrl_word = 12'b0; + ctrl_word[SIG_HLT] = 1; + end + default: begin + ctrl_word = 12'b0; + end + endcase + end + 5: begin + case (instr) + OP_LDA: begin + ctrl_word = 12'b0; + ctrl_word[SIG_MEM_EN] = 1; + ctrl_word[SIG_A_LOAD] = 1; + end + OP_ADD: begin + ctrl_word = 12'b0; + ctrl_word[SIG_MEM_EN] = 1; + ctrl_word[SIG_B_LOAD] = 1; + end + OP_SUB: begin + ctrl_word = 12'b0; + ctrl_word[SIG_MEM_EN] = 1; + ctrl_word[SIG_B_LOAD] = 1; + end + default: begin + ctrl_word = 12'b0; + end + endcase + end + 6: begin + case (instr) + OP_ADD: begin + ctrl_word = 12'b0; + ctrl_word[SIG_ADDER_EN] = 1; + ctrl_word[SIG_A_LOAD] = 1; + end + OP_SUB: begin + ctrl_word = 12'b0; + ctrl_word[SIG_ADDER_SUB] = 1; + ctrl_word[SIG_ADDER_EN] = 1; + ctrl_word[SIG_A_LOAD] = 1; + end + default: begin + ctrl_word = 12'b0; + end + endcase + end + default: begin + ctrl_word = 12'b0; + end + endcase +end + +endmodule + diff --git a/src/ir.v b/src/ir.v new file mode 100644 index 0000000..9694b06 --- /dev/null +++ b/src/ir.v @@ -0,0 +1,23 @@ +module ir( + input clk, + input clr, + input load, + input en, + inout[7:0] bus, + output[3:0] instr); + +reg[7:0] ir = 0; + +always @(posedge clk or posedge clr) begin + if (clr) begin + ir <= 8'b0; + end else if (load) begin + ir <= bus; + end +end + +assign instr = ir[7:4]; +assign bus = (en) ? ir[3:0] : 8'bz; + +endmodule + diff --git a/src/memory.v b/src/memory.v new file mode 100644 index 0000000..1b9f3ed --- /dev/null +++ b/src/memory.v @@ -0,0 +1,24 @@ +module memory( + input clk, + input load, + input en, + inout[7:0] bus +); + +initial begin + $readmemh("program.bin", ram); +end + +reg[3:0] mar = 0; +reg[7:0] ram[0:15]; + +always @(posedge clk) begin + if (load) begin + mar <= bus[3:0]; + end +end + +assign bus = (en) ? ram[mar] : 8'bz; + +endmodule + diff --git a/src/pc.v b/src/pc.v new file mode 100644 index 0000000..5c216e6 --- /dev/null +++ b/src/pc.v @@ -0,0 +1,22 @@ +module pc( + input clk, + input clr, + input inc, + input en, + output[7:0] bus +); + +reg[3:0] pc = 0; + +always @(posedge clk or posedge clr) begin + if (clr) begin + pc <= 4'b0; + end else if (inc) begin + pc <= pc + 1; + end +end + +assign bus = (en) ? pc : 8'bz; + +endmodule + diff --git a/src/pins.pcf b/src/pins.pcf new file mode 100644 index 0000000..ff7bc53 --- /dev/null +++ b/src/pins.pcf @@ -0,0 +1,2 @@ +set_io --warn-no-port CLK B2 # input + diff --git a/src/program.bin b/src/program.bin new file mode 100644 index 0000000..cf6c4cd --- /dev/null +++ b/src/program.bin @@ -0,0 +1,16 @@ +0D +1E +2F +F0 +00 +00 +00 +00 +00 +00 +00 +00 +00 +03 +04 +02 diff --git a/src/reg_a.v b/src/reg_a.v new file mode 100644 index 0000000..89f2f0b --- /dev/null +++ b/src/reg_a.v @@ -0,0 +1,20 @@ +module reg_a( + input clk, + input load, + input en, + inout[7:0] bus, + output[7:0] val); + +reg[7:0] reg_a = 0; + +always @(posedge clk) begin + if (load) begin + reg_a <= bus; + end +end + +assign bus = (en) ? reg_a : 8'bz; +assign val = reg_a; + +endmodule + diff --git a/src/reg_b.v b/src/reg_b.v new file mode 100644 index 0000000..30c57a6 --- /dev/null +++ b/src/reg_b.v @@ -0,0 +1,18 @@ +module reg_b( + input clk, + input load, + input[7:0] bus, + output[7:0] val); + +reg[7:0] reg_b = 0; + +always @(posedge clk) begin + if (load) begin + reg_b <= bus; + end +end + +assign val = reg_b; + +endmodule + diff --git a/src/top.v b/src/top.v new file mode 100644 index 0000000..46eab98 --- /dev/null +++ b/src/top.v @@ -0,0 +1,97 @@ +module top( + input CLK); + +wire[7:0] bus; + +wire clk; +wire hlt; +clock clock( + .hlt(hlt), + .clk_in(CLK), + .clk_out(clk) +); + +wire clr; +wire pc_en; +wire pc_inc; +pc pc( + .clk(clk), + .clr(clr), + .inc(pc_inc), + .en(pc_en), + .bus(bus) +); + +wire a_load; +wire a_en; +wire[7:0] a_val; +reg_a reg_a( + .clk(clk), + .load(a_load), + .en(a_en), + .bus(bus), + .val(a_val) +); + +wire b_load; +wire[7:0] b_val; +reg_b reg_b( + .clk(clk), + .load(b_load), + .bus(bus), + .val(b_val) +); + +wire adder_sub; +wire adder_en; +adder adder( + .a(a_val), + .b(b_val), + .sub(adder_sub), + .en(adder_en), + .bus(bus) +); + +wire mar_load; +wire mem_en; +memory mem( + .clk(clk), + .load(mar_load), + .en(mem_en), + .bus(bus) +); + +wire ir_load; +wire ir_en; +wire[3:0] ir_instr; +ir ir( + .clk(clk), + .clr(clr), + .load(ir_load), + .en(ir_en), + .bus(bus), + .instr(ir_instr) +); + +controller controller( + .clk(clk), + .instr(ir_instr), + .ctrl_word( + { + hlt, + pc_inc, + pc_en, + mar_load, + mem_en, + ir_load, + ir_en, + a_load, + a_en, + b_load, + adder_sub, + adder_en + }) +); + +endmodule + diff --git a/src/top_tb.v b/src/top_tb.v new file mode 100644 index 0000000..ce87d1b --- /dev/null +++ b/src/top_tb.v @@ -0,0 +1,109 @@ +module top_tb(); + +initial begin + $dumpfile("top_tb.vcd"); + $dumpvars(0, top_tb); +end + +reg clk_in = 0; +integer i; +initial begin + for (i = 0; i < 128; i++) begin + #1 clk_in = ~clk_in; + end +end + +wire clk; +wire hlt; +wire clr; +wire[7:0] bus; + +clock clock( + .hlt(hlt), + .clk_in(clk_in), + .clk_out(clk) +); + +wire pc_en; +wire pc_inc; +pc pc( + .clk(clk), + .clr(clr), + .inc(pc_inc), + .en(pc_en), + .bus(bus) +); + +wire a_load; +wire a_en; +wire[7:0] a_val; +reg_a reg_a( + .clk(clk), + .load(a_load), + .en(a_en), + .bus(bus), + .val(a_val) +); + +wire b_load; +wire[7:0] b_val; +reg_b reg_b( + .clk(clk), + .load(b_load), + .bus(bus), + .val(b_val) +); + +wire adder_sub; +wire adder_en; +adder adder( + .a(a_val), + .b(b_val), + .sub(adder_sub), + .en(adder_en), + .bus(bus) +); + +wire mar_load; +wire mem_en; +memory mem( + .clk(clk), + .load(mar_load), + .en(mem_en), + .bus(bus) +); + +wire ir_load; +wire ir_en; +wire[3:0] ir_instr; +ir ir( + .clk(clk), + .clr(clr), + .load(ir_load), + .en(ir_en), + .bus(bus), + .instr(ir_instr) +); + +controller controller( + .clk(clk), + .instr(ir_instr), + .ctrl_word( + { + hlt, + pc_inc, + pc_en, + mar_load, + mem_en, + ir_load, + ir_en, + a_load, + a_en, + b_load, + adder_sub, + adder_en + }) +); + +endmodule +