diff options
-rw-r--r-- | .gitignore | 13 | ||||
-rw-r--r-- | alu.v | 68 | ||||
-rw-r--r-- | alu_tb.v | 74 | ||||
-rw-r--r-- | decoder.v | 77 | ||||
-rw-r--r-- | nqcpu.qpf | 30 | ||||
-rw-r--r-- | nqcpu.qsf | 61 | ||||
-rw-r--r-- | regFile.v | 27 | ||||
-rw-r--r-- | regFile_tb.v | 83 | ||||
-rw-r--r-- | shifter.v | 68 | ||||
-rw-r--r-- | shifter_tb.v | 100 |
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 @@ -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 |