diff --git a/flake.nix b/flake.nix index f3e1324..dfa8251 100644 --- a/flake.nix +++ b/flake.nix @@ -11,38 +11,23 @@ verilator = import ./verilator.nix pkgs ; - rot-sim = pkgs.runCommandCC "rot-sim" {} '' - cp "${./rot.v}" rot.v - ${verilator}/bin/verilator --cc -O3 --exe --build --trace ${./sim_main.cpp} rot.v + vflags = "-Wpedantic -Wwarn-lint -Wwarn-style"; + verilate-src = cmd: '' + cp -r ${./verilog-src} ./verilog-src + cp -r ${./simulation} ./simulation + find ./verilog-src/ -name '*.v' -exec ${verilator}/bin/verilator ${vflags} ${cmd} {} + + ''; + + lint = pkgs.runCommand "lint" {} '' + ${verilate-src "--lint-only"} + echo "compiler didn't get angry :3" + : 3 > $out + ''; + + alu-sim = pkgs.runCommandCC "alu-sim" {} '' + ${verilate-src "--cc --build --exe ./simulation/test_alu.cpp"} mv obj_dir "$out" - ''; - - rot-trace = pkgs.runCommand "rot-trace" {} '' - mkdir "$out" - ${rot-sim}/Vrot $out/trace.vcd - ''; - - rot-trace-view = pkgs.writeScriptBin "rot-view" '' - ${pkgs.gtkwave}/bin/gtkwave ${rot-trace}/trace.vcd - ''; - - rot-synth = pkgs.runCommand "rot-synth" {} '' - mkdir "$out" - ${pkgs.yosys}/bin/yosys -p "read -vlog95 ${./rot.v} ; synth_ice40 -json $out/synth.json" - ''; - - rot-route = pkgs.runCommand "rot-route" {} '' - mkdir "$out" - ${pkgs.nextpnr}/bin/nextpnr-ice40 --pcf ${./rot.pcf} --json ${rot-synth}/synth.json --asc $out/routed.asc --up5k --top rot --freq 12 - ''; - - rot-pack = pkgs.runCommand "rot-pack" {} '' - mkdir "$out" - ${pkgs.icestorm}/bin/icepack ${rot-route}/routed.asc $out/packed.bin - ''; - - rot-upload = pkgs.writeScriptBin "rot-upload" '' - ${pkgs.icestorm}/bin/iceprog ${rot-pack}/packed.bin + mkdir "$out/bin" && cp "$out/Valu" "$out/bin/alu-sim" ''; deps = with pkgs; [ @@ -51,15 +36,9 @@ in rec { packages.verilator = verilator; - packages.rot-sim = rot-sim; - packages.rot-trace = rot-trace; - packages.rot-trace-view = rot-trace-view; - - packages.rot-synth = rot-synth; - packages.rot-route = rot-route; - packages.rot-pack = rot-pack; - packages.rot-upload = rot-upload; + packages.lint = lint; + packages.alu-sim = alu-sim; devShells.default = pkgs.mkShell { packages = deps; }; diff --git a/rot.pcf b/fpga-files/rot.pcf similarity index 100% rename from rot.pcf rename to fpga-files/rot.pcf diff --git a/rot.v b/rot.v deleted file mode 100644 index efe71bc..0000000 --- a/rot.v +++ /dev/null @@ -1,30 +0,0 @@ -module rot (input clk, output D0, output D1, output D2, output D3); - -reg ready = 0; -reg [23:0] divider; -reg [3:0] rot; - -always @(posedge clk) begin - if (ready) - begin - if (divider == 12_000_000) - begin - divider <= 0; - rot <= {rot[2], rot[1], rot[0], rot[3]}; - end - else - divider <= divider + 1; - end - else begin - ready <= 1; - rot <= 4'b1; - divider <= 0; - end -end - -assign D0 = rot[0]; -assign D1 = rot[1]; -assign D2 = rot[2]; -assign D3 = rot[3]; - -endmodule diff --git a/sim_main.cpp b/simulation/sim_main.cpp similarity index 100% rename from sim_main.cpp rename to simulation/sim_main.cpp diff --git a/simulation/test_alu.cpp b/simulation/test_alu.cpp new file mode 100644 index 0000000..ed77946 --- /dev/null +++ b/simulation/test_alu.cpp @@ -0,0 +1,18 @@ +#include "Valu.h" +#include "verilated.h" +#include + +int main(int argc, char **argv) { + VerilatedContext *vctx = new VerilatedContext; + + Valu *valu = new Valu(vctx); + valu->A = 0x2137; + valu->B = 0x1234; + + valu->op = 0b000; + valu->eval(); + printf("A = %04x + B = %04x = O = %04x\n", valu->A, valu->B, valu->O); + valu->op = 0b001; + valu->eval(); + printf("A = %04x - B = %04x = O = %04x\n", valu->A, valu->B, valu->O); +} diff --git a/verilog-src/alu.v b/verilog-src/alu.v new file mode 100644 index 0000000..3fde343 --- /dev/null +++ b/verilog-src/alu.v @@ -0,0 +1,28 @@ +/* + A and B are inputs, O is out + OP is the operation to perform: + 000 = add + 001 = sub + 010 = mul + (011) + 100 = and + 101 = or + 110 = xor + 111 = not A +*/ +module alu( + input [31:0] A, + input [31:0] B, + input [2:0] op, + output [31:0] O, + output Cout, + output Fzero +); + +wire subtraction = op == 3'b001; +wire [31:0] adder_B = subtraction ? ~B : B; + +carry_select_adder a(A, adder_B, subtraction, O, Cout); +assign Fzero = & O; + +endmodule diff --git a/verilog-src/alu/carry_select_adder.v b/verilog-src/alu/carry_select_adder.v new file mode 100644 index 0000000..4215209 --- /dev/null +++ b/verilog-src/alu/carry_select_adder.v @@ -0,0 +1,29 @@ +// 5 blocks of size 6, final block of size 2 +module carry_select_adder( + input [31:0] A, + input [31:0] B, + input Cin, + output [31:0] O, + output Cout +); + +// TODO: First block should not be carry_select, a normal RCA is better +// i think? +wire Cout_5; +carry_select_block#(6) B0 (A[5:0], B[5:0], Cin, O[5:0], Cout_5); + +wire Cout_11; +carry_select_block#(6) B1 (A[11:6], B[11:6], Cout_5, O[11:6], Cout_11); + +wire Cout_17; +carry_select_block#(6) B2 (A[17:12], B[17:12], Cout_11, O[17:12], Cout_17); + +wire Cout_23; +carry_select_block#(6) B3 (A[23:18], B[23:18], Cout_17, O[23:18], Cout_23); + +wire Cout_29; +carry_select_block#(6) B4 (A[29:24], B[29:24], Cout_23, O[29:24], Cout_29); + +carry_select_block#(2) B6 (A[31:30], B[31:30], Cout_29, O[31:30], Cout); + +endmodule diff --git a/verilog-src/alu/carry_select_block.v b/verilog-src/alu/carry_select_block.v new file mode 100644 index 0000000..ffd7d8b --- /dev/null +++ b/verilog-src/alu/carry_select_block.v @@ -0,0 +1,39 @@ +module carry_select_block#( + parameter N = 4 +) ( + input [N-1:0] A, + input [N-1:0] B, + input Cin, + output [N-1:0] O, + output Cout +); + +// Case for Cin = 0 +wire [N-1:0] O_C0; +wire Cout_C0; + +begin + wire [N-1:1] carry; + fa fa0(A[0], B[0], 0, O_C0[0], carry[1]); + genvar i; for (i = 1; i <= N - 1; i = i + 1) begin + fa fai(A[i], B[i], carry[i], O_C0[i], carry[i+1]); + end + assign Cout_C0 = carry[N-1]; +end + +// Case for Cin = 1 +wire [N-1:0] O_C1; +wire Cout_C1; +begin + wire [N-1:1] carry; + fa fa0(A[0], B[0], 1, O_C1[0], carry[1]); + genvar i; for (i = 1; i <= N - 1; i = i + 1) begin + fa fai(A[i], B[i], carry[i], O_C1[i], carry[i+1]); + end + assign Cout_C1 = carry[N-1]; +end + +assign O = Cin == 0 ? O_C0 : O_C1; +assign Cout = Cin == 0 ? Cout_C0 : Cout_C1; + +endmodule diff --git a/verilog-src/alu/fa.v b/verilog-src/alu/fa.v new file mode 100644 index 0000000..8581d5b --- /dev/null +++ b/verilog-src/alu/fa.v @@ -0,0 +1,7 @@ +// One bit full-adder +module fa(input A, input B, input Cin, output O, output Cout); + +assign O = A ^ B ^ Cin; +assign Cout = (A & B) | (B & Cin) | (Cin & A); + +endmodule