summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick McKinney <nick@kmonkey.net>2016-12-01 21:36:51 -0600
committerNick McKinney <nick@kmonkey.net>2016-12-01 21:36:51 -0600
commit37db52dbd66db1fd43337082249c469eda39f776 (patch)
treeeff432c8922c877f60aba36e216710e41d8304dd
initial commit
-rw-r--r--.gitignore13
-rw-r--r--alu.v68
-rw-r--r--alu_tb.v74
-rw-r--r--decoder.v77
-rw-r--r--nqcpu.qpf30
-rw-r--r--nqcpu.qsf61
-rw-r--r--regFile.v27
-rw-r--r--regFile_tb.v83
-rw-r--r--shifter.v68
-rw-r--r--shifter_tb.v100
10 files changed, 601 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..310a92b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+db/
+incremental_db/
+output_files/
+simulation/
+greybox_tmp/
+*.rpt
+*.smsg
+*.summary
+*.pof
+*.sof
+*.done
+*.bak
+*.qws
diff --git a/alu.v b/alu.v
new file mode 100644
index 0000000..1ecc0a0
--- /dev/null
+++ b/alu.v
@@ -0,0 +1,68 @@
+module alu (
+ input [3:0] op,
+ input [15:0] x,
+ input [15:0] y,
+ output [15:0] result,
+ output zero,
+ output carry
+);
+
+// op:
+// 0000: result = x + y
+// 0001: result = x - y
+// 0010: result = x * y
+// 0011: result = x / y
+// 0100: result = x & y
+// 0101: result = x | y
+// 0110: result = x ^ y
+// 0111: result = don't care
+// 1000: result = x << y (zero extend)
+// 1001: result = x << y (one extend)
+// 1010: result = x << y (extend with last bit)
+// 1011: result = x << y (barrel shift)
+// 1100: result = x >> y (zero extend)
+// 1101: result = x >> y (one extend)
+// 1110: result = x >> y (extend with sign bit)
+// 1111: result = x >> y (barrel shift)
+
+ wire [16:0] sum;
+ wire [16:0] diff;
+ wire [16:0] prod;
+ wire [16:0] quot;
+ wire [15:0] anded;
+ wire [15:0] ored;
+ wire [15:0] xored;
+ wire [15:0] shifted;
+
+ assign sum = x + y;
+ assign diff = x - y;
+ assign prod = x * y;
+ assign quot = x / y;
+ assign anded = x & y;
+ assign ored = x | y;
+ assign xored = x ^ y;
+
+ shifter shifter_inst (
+ .v(x),
+ .by(y),
+ .dir(op[2]),
+ .extend(op[1:0]),
+ .result(shifted)
+ );
+
+ assign result =
+ op == 4'b0000 ? sum[15:0] :
+ op == 4'b0001 ? diff[15:0] :
+ op == 4'b0010 ? prod[15:0] :
+ op == 4'b0011 ? quot[15:0] :
+ op == 4'b0100 ? anded :
+ op == 4'b0101 ? ored :
+ op == 4'b0110 ? xored :
+ shifted;
+
+ assign zero = ~(|result);
+ assign carry =
+ op == 4'b0000 ? sum[16] :
+ op == 4'b0001 ? diff[16] : 1'b0;
+
+endmodule
diff --git a/alu_tb.v b/alu_tb.v
new file mode 100644
index 0000000..dffe337
--- /dev/null
+++ b/alu_tb.v
@@ -0,0 +1,74 @@
+`timescale 1 ns / 100 ps
+
+module alu_tb ();
+ reg [3:0] op;
+ reg [15:0] x;
+ reg [15:0] y;
+ wire [15:0] result;
+ reg [15:0] expected_result;
+ wire zero;
+ reg expected_zero;
+ wire carry;
+ reg expected_carry;
+
+ initial begin
+ x = 16'h0123;
+ y = 16'h1234;
+
+ op = 4'h0; // add
+ expected_result = 16'h1357;
+ expected_zero = 1'b0;
+ expected_carry = 1'b0;
+
+ #2
+ op = 4'h1; // subtract
+ expected_result = 16'hEEEF;
+ expected_carry = 1'b1;
+ expected_zero = 1'b0;
+
+ #2
+ y = 16'h0123;
+ expected_result = 16'h0;
+ expected_zero = 1'b1;
+ expected_carry = 1'b0;
+
+ #2
+ y = 16'h1234;
+ op = 4'h2; // multiply
+ expected_result = 16'hB11C;
+ expected_zero = 1'b0;
+ expected_carry = 1'b0;
+
+ #2
+ x = 16'h3E58;
+ y = 16'h0078;
+ op = 4'h3; // divide
+ expected_result = 16'h0085;
+
+ #2
+ x = 16'hAF74;
+ y = 16'h7CC7;
+ op = 4'h4; // and
+ expected_result = 16'h2C44;
+
+ #2
+ op = 4'h5; // or
+ expected_result = 16'hFFF7;
+
+ #2
+ op = 4'h6; // xor
+ expected_result = 16'hD3B3;
+
+ #5
+ $stop;
+ end
+
+ alu alu_inst (
+ .op(op),
+ .x(x),
+ .y(y),
+ .result(result),
+ .zero(zero),
+ .carry(carry)
+ );
+endmodule
diff --git a/decoder.v b/decoder.v
new file mode 100644
index 0000000..70b70f2
--- /dev/null
+++ b/decoder.v
@@ -0,0 +1,77 @@
+module decoder (
+);
+
+// instructions
+// add (reg0 <- reg1 + reg2)
+// sub (reg0 <- reg1 - reg2)
+// mul (reg0 <- reg1 * reg2)
+// div (reg0 <- reg1 / reg2)
+// shl (reg0 <- reg1 >> reg2, sign extend)
+// shr (reg0 <- reg1 << reg2, zero extend) <-- could maybe be one instruction with a direction and extend flags
+// and (reg0 <- reg1 & reg2)
+// or (reg0 <- reg1 | reg2)
+// xor (reg0 <- reg1 ^ reg2)
+// not (reg0 <- !reg1)
+// neg (reg0 <- -reg1) <-- could maybe be another mode of not instruction where it also adds 1.
+// bts (reg1th bit of reg0 moved to "zero" status bit, reg1th bit of reg0 is set or reset)
+// mov (reg0 <- reg1, *reg0 <- reg1, reg0 <- *reg1, imm8 -> reg0H, imm8 -> reg0L)
+// b** (relative branch: ne, eq, gt, lt, ge, le, always)
+// jmp (absolute branch)
+
+// 8 registers, 3 bits per register argument
+// 4 bits for instruction
+// instr with 3 reg params is 13 bits
+
+// add/sub/mul/div/and/or/xor
+// 0000 + [reg0] + [op-msb] + [reg1] + [reg2] + [op-2lsb]
+// op: 0 00 add
+// 0 01 sub
+// 0 10 mul
+// 0 11 div
+// 1 00 and
+// 1 01 or
+// 1 10 xor
+// 1 11 ???
+
+// shl/slr
+// 0001 + [reg0] + [dir] + [reg1] + [reg2] + [extend]
+// dir: 0 = left, 1 = right
+// extend: 00 zero
+// 01 one
+// 10 sign/last bit (copy bit on the end)
+// 11 barrel shift
+
+// not/neg
+// 0010 + [reg0] + [which] + [reg1] + 000 + 00
+// which: 0 = not, 1 = neg
+
+// bts
+// 0011 + [reg0] + [set or reset] + [reg1] + 00000
+// set or reset: 0 = reset, 1 = set
+
+// mov
+// reg0 <- reg1: 0100 + [reg0] + 0 + [reg1] + [dest byte] + [src byte] + [byte or word] + 00
+// *reg0 <- reg1: 0100 + [reg0] + 1 + [reg1] + 0 + [src byte] + [byte or word] + 0 + 0
+// reg0 <- *reg1: 0100 + [reg0] + 1 + [reg1] + [dest byte] + 0 + [byte or word] + 0 + 1
+// reg0L <- imm8: 0101 + [reg0] + 0 + [immediate value]
+// reg0H <- imm8: 0101 + [reg0] + 1 + [immediate value]
+// byte or word: 0 = word, 1 = byte
+// for mem operations, word ops must be word-aligned (lsb must be 0)
+// src/dest byte: 0 = low byte, 1 = high byte (ignored for word operations)
+
+// b**
+// 0110 + [which] + 0 + [immediate offset]
+// which: 000 eq
+// 001 ne
+// 010 gt
+// 011 ge
+// 100 lt
+// 101 le
+// 110 ??
+// 111 always
+
+// jmp
+// 0111 + [reg0] + 0 + 00000000
+// basically moves reg0 to pc
+
+endmodule
diff --git a/nqcpu.qpf b/nqcpu.qpf
new file mode 100644
index 0000000..443d46b
--- /dev/null
+++ b/nqcpu.qpf
@@ -0,0 +1,30 @@
+# -------------------------------------------------------------------------- #
+#
+# Copyright (C) 1991-2013 Altera Corporation
+# Your use of Altera Corporation's design tools, logic functions
+# and other software and tools, and its AMPP partner logic
+# functions, and any output files from any of the foregoing
+# (including device programming or simulation files), and any
+# associated documentation or information are expressly subject
+# to the terms and conditions of the Altera Program License
+# Subscription Agreement, Altera MegaCore Function License
+# Agreement, or other applicable license agreement, including,
+# without limitation, that your use is for the sole purpose of
+# programming logic devices manufactured by Altera and sold by
+# Altera or its authorized distributors. Please refer to the
+# applicable agreement for further details.
+#
+# -------------------------------------------------------------------------- #
+#
+# Quartus II 64-Bit
+# Version 13.0.1 Build 232 06/12/2013 Service Pack 1 SJ Web Edition
+# Date created = 22:25:59 November 17, 2016
+#
+# -------------------------------------------------------------------------- #
+
+QUARTUS_VERSION = "13.0"
+DATE = "22:25:59 November 17, 2016"
+
+# Revisions
+
+PROJECT_REVISION = "nqcpu"
diff --git a/nqcpu.qsf b/nqcpu.qsf
new file mode 100644
index 0000000..33d9bd8
--- /dev/null
+++ b/nqcpu.qsf
@@ -0,0 +1,61 @@
+# -------------------------------------------------------------------------- #
+#
+# Copyright (C) 1991-2013 Altera Corporation
+# Your use of Altera Corporation's design tools, logic functions
+# and other software and tools, and its AMPP partner logic
+# functions, and any output files from any of the foregoing
+# (including device programming or simulation files), and any
+# associated documentation or information are expressly subject
+# to the terms and conditions of the Altera Program License
+# Subscription Agreement, Altera MegaCore Function License
+# Agreement, or other applicable license agreement, including,
+# without limitation, that your use is for the sole purpose of
+# programming logic devices manufactured by Altera and sold by
+# Altera or its authorized distributors. Please refer to the
+# applicable agreement for further details.
+#
+# -------------------------------------------------------------------------- #
+#
+# Quartus II 64-Bit
+# Version 13.0.1 Build 232 06/12/2013 Service Pack 1 SJ Web Edition
+# Date created = 22:25:59 November 17, 2016
+#
+# -------------------------------------------------------------------------- #
+#
+# Notes:
+#
+# 1) The default values for assignments are stored in the file:
+# nqcpu_assignment_defaults.qdf
+# If this file doesn't exist, see file:
+# assignment_defaults.qdf
+#
+# 2) Altera recommends that you do not modify this file. This
+# file is updated automatically by the Quartus II software
+# and any changes you make may be lost or overwritten.
+#
+# -------------------------------------------------------------------------- #
+
+
+set_global_assignment -name FAMILY "Cyclone II"
+set_global_assignment -name DEVICE EP2C20F484C7
+set_global_assignment -name TOP_LEVEL_ENTITY alu
+set_global_assignment -name ORIGINAL_QUARTUS_VERSION "13.0 SP1"
+set_global_assignment -name PROJECT_CREATION_TIME_DATE "22:25:59 NOVEMBER 17, 2016"
+set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1"
+set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
+set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
+set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
+set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
+set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (Verilog)"
+set_global_assignment -name EDA_OUTPUT_DATA_FORMAT "VERILOG HDL" -section_id eda_simulation
+set_global_assignment -name VERILOG_FILE decoder.v
+set_global_assignment -name VERILOG_FILE regFile.v
+set_global_assignment -name VERILOG_FILE regFile_tb.v
+set_global_assignment -name VERILOG_FILE alu.v
+set_global_assignment -name VERILOG_FILE shifter.v
+set_global_assignment -name VERILOG_FILE shifter_tb.v
+set_global_assignment -name VERILOG_FILE alu_tb.v
+set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
+set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
+set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
+set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file
diff --git a/regFile.v b/regFile.v
new file mode 100644
index 0000000..4331adc
--- /dev/null
+++ b/regFile.v
@@ -0,0 +1,27 @@
+module regFile (
+ input clk,
+ input [2:0] regA,
+ input [2:0] regB,
+ input [2:0] regDest,
+ input [15:0] dataIn,
+ input we,
+ input hb,
+ input lb,
+ output [15:0] dataA,
+ output [15:0] dataB
+);
+
+ reg [15:0] register[7];
+
+ assign dataA = register[regA];
+ assign dataB = register[regB];
+
+ always @(posedge clk) begin
+ if(we) begin
+ register[regDest] <= {
+ hb ? dataIn[15:8] : register[regDest][15:8],
+ lb ? dataIn[7:0] : register[regDest][7:0]
+ };
+ end
+ end
+endmodule
diff --git a/regFile_tb.v b/regFile_tb.v
new file mode 100644
index 0000000..10839d0
--- /dev/null
+++ b/regFile_tb.v
@@ -0,0 +1,83 @@
+`timescale 1 ns / 100 ps
+
+module regFile_tb ();
+
+ reg clk;
+ reg [2:0] regA;
+ reg [2:0] regB;
+ reg [2:0] regDest;
+ reg [15:0] dataIn;
+ reg we, hb, lb;
+ wire [15:0] dataA;
+ wire [15:0] dataB;
+
+ initial begin
+ clk = 1'b0;
+
+ regA = 3'h0;
+ regB = 3'h0;
+ regDest = 3'h0;
+ we = 1'b0;
+ hb = 1'b0;
+ lb = 1'b0;
+ dataIn = 16'h0;
+
+ #2
+ regA = 3'h1;
+ regDest = 3'h1;
+ dataIn = 16'hDEAD;
+ we = 1'b1;
+ hb = 1'b1;
+ lb = 1'b1;
+
+ #2
+ regB = 3'h1;
+ regA = 3'h2;
+ dataIn = 16'hBEEF;
+ lb = 1'b0;
+
+ #2
+ lb = 1'b1;
+
+ #2
+ regDest = 3'h2;
+ hb = 1'b0;
+ dataIn = 16'h9876;
+
+ #2
+ hb = 1'b1;
+ lb = 1'b0;
+ dataIn = 16'h2345;
+
+ #2
+ regB = 3'h7;
+ regDest = 3'h7;
+ lb = 1'b0;
+ hb = 1'b0;
+ we = 1'b1;
+ dataIn = 16'hFFCC;
+
+ #2
+ lb = 1'b1;
+ hb = 1'b1;
+ we = 1'b0;
+
+ #5
+ $stop;
+ end
+
+ always #1 clk = !clk;
+
+ regFile regFile_inst (
+ .clk(clk),
+ .regA(regA),
+ .regB(regB),
+ .regDest(regDest),
+ .dataIn(dataIn),
+ .we(we),
+ .hb(hb),
+ .lb(lb),
+ .dataA(dataA),
+ .dataB(dataB)
+ );
+endmodule
diff --git a/shifter.v b/shifter.v
new file mode 100644
index 0000000..46360fe
--- /dev/null
+++ b/shifter.v
@@ -0,0 +1,68 @@
+module shifter (
+ input [15:0] v, // number to shift
+ input [15:0] by, // bits to shift by
+ input dir, // 0 = left shift, 1 = right shift
+ input [1:0] extend, // 0 = zero extend, 1 = one extend, 2 = sign extend (or last bit), 3 = barrel shift
+ output [15:0] result
+);
+
+ wire [47:0] x;
+
+ assign x = {
+ extend == 2'b00 ? 16'h0 :
+ extend == 2'b01 ? 16'hFFFF :
+ extend == 2'b10 ? {16{v[15]}} : v,
+
+ v,
+
+ extend == 2'b00 ? 16'h0 :
+ extend == 2'b01 ? 16'hFFFF :
+ extend == 2'b10 ? {16{v[0]}} : v
+ };
+
+ wire [15:0] barrelResult;
+ wire [15:0] otherResult;
+
+ wire [4:0] dirAndAmount;
+ assign dirAndAmount = {dir, by[3:0]};
+
+ assign barrelResult =
+ |(by[15:4]) ? (dir == 1'b1 ? x[47:32] : x[15:0]) :
+ dirAndAmount == 5'h1F ? x[46:31] :
+ dirAndAmount == 5'h1E ? x[45:30] :
+ dirAndAmount == 5'h1D ? x[44:29] :
+ dirAndAmount == 5'h1C ? x[43:28] :
+ dirAndAmount == 5'h1B ? x[42:27] :
+ dirAndAmount == 5'h1A ? x[41:26] :
+ dirAndAmount == 5'h19 ? x[40:25] :
+ dirAndAmount == 5'h18 ? x[39:24] :
+ dirAndAmount == 5'h17 ? x[38:23] :
+ dirAndAmount == 5'h16 ? x[37:22] :
+ dirAndAmount == 5'h15 ? x[36:21] :
+ dirAndAmount == 5'h14 ? x[35:20] :
+ dirAndAmount == 5'h13 ? x[34:19] :
+ dirAndAmount == 5'h12 ? x[33:18] :
+ dirAndAmount == 5'h11 ? x[32:17] :
+ // zero shift is handled at the bottom
+ dirAndAmount == 5'h01 ? x[30:15] :
+ dirAndAmount == 5'h02 ? x[29:14] :
+ dirAndAmount == 5'h03 ? x[28:13] :
+ dirAndAmount == 5'h04 ? x[27:12] :
+ dirAndAmount == 5'h05 ? x[26:11] :
+ dirAndAmount == 5'h06 ? x[25:10] :
+ dirAndAmount == 5'h07 ? x[24:9] :
+ dirAndAmount == 5'h08 ? x[23:8] :
+ dirAndAmount == 5'h09 ? x[22:7] :
+ dirAndAmount == 5'h0A ? x[21:6] :
+ dirAndAmount == 5'h0B ? x[20:5] :
+ dirAndAmount == 5'h0C ? x[19:4] :
+ dirAndAmount == 5'h0D ? x[18:3] :
+ dirAndAmount == 5'h0E ? x[17:2] :
+ dirAndAmount == 5'h0F ? x[16:1] :
+ x[31:16];
+
+ assign otherResult =
+ |(by[15:4]) ? (dir == 1'b1 ? x[47:32] : x[15:0]) : barrelResult;
+
+ assign result = extend == 2'b11 ? barrelResult : otherResult;
+endmodule
diff --git a/shifter_tb.v b/shifter_tb.v
new file mode 100644
index 0000000..7d28915
--- /dev/null
+++ b/shifter_tb.v
@@ -0,0 +1,100 @@
+`timescale 1 ns / 100 ps
+
+module shifter_tb ();
+ reg [15:0] v;
+ reg [15:0] by;
+ reg dir;
+ reg [1:0] extend;
+ wire [15:0] result;
+ reg [15:0] expected_result;
+
+ // xxxxxxxxxxxxxxxx1111101000001010xxxxxxxxxxxxxxxx
+
+ initial begin
+ v = 16'hFA0A;
+ by = 16'h0;
+ dir = 1'b0;
+ extend = 2'h0;
+ expected_result = 16'hFA0A;
+
+ #2
+ by = 16'h1;
+ expected_result = 16'hF414; // 1111 0100 0001 0100
+
+ #2
+ by = 16'h2;
+ expected_result = 16'hE828; // 1110 1000 0010 1000
+
+ #2
+ dir = 1'b1;
+ expected_result = 16'h3E82; // 0011 1110 1000 0010
+
+ #2
+ by = 16'h4;
+ expected_result = 16'h0FA0; // 0000 1111 1010 0000
+
+ #2
+ dir = 1'b0;
+ expected_result = 16'hA0A0; // 1010 0000 1010 0000
+
+ #2
+ extend = 2'h1;
+ expected_result = 16'hA0AF; // 1010 0000 1010 1111
+
+ #2
+ dir = 1'b1;
+ expected_result = 16'hFFA0; // 1111 1111 1010 0000
+
+ #2
+ extend = 2'h2;
+ dir = 1'b0;
+ expected_result = 16'hA0A0; // 1010 0000 1010 0000
+
+ #2
+ dir = 1'b1;
+ expected_result = 16'hFFA0; // 1111 1111 1010 0000
+
+ #2
+ extend = 2'h3;
+ expected_result = 16'hAFA0; // 1010 1111 1010 0000
+
+ #2
+ dir = 1'b0;
+ expected_result = 16'hA0AF; // 1010 0000 1010 1111
+
+ #2
+ v = 16'h0001;
+ extend = 2'h2;
+ dir = 1'b0;
+ by = 16'hE;
+ expected_result = 16'h7FFF;
+
+ #2
+ by = 16'h10;
+ expected_result = 16'hFFFF;
+
+ #2
+ dir = 1'b1;
+ expected_result = 16'h0000;
+
+ #2
+ dir = 1'b0;
+ by = 16'h1000;
+ expected_result = 16'hFFFF;
+
+ #2
+ dir = 1'b1;
+ expected_result = 16'h0000;
+
+ #5
+ $stop;
+ end
+
+ shifter shifter_inst (
+ .v(v),
+ .by(by),
+ .dir(dir),
+ .extend(extend),
+ .result(result)
+ );
+endmodule