commit 8ccea9566e7bca674e7f910deea2fecc7925fc4e Author: Denis Tereshkin Date: Thu Nov 23 22:26:50 2023 +0700 Add ALU diff --git a/doc/w65c02s.pdf b/doc/w65c02s.pdf new file mode 100644 index 0000000..cef921f Binary files /dev/null and b/doc/w65c02s.pdf differ diff --git a/src/alu.verilog b/src/alu.verilog new file mode 100644 index 0000000..9d69433 --- /dev/null +++ b/src/alu.verilog @@ -0,0 +1,94 @@ +module alu + ( + input nrst, + input clk, + input [7:0] A, + input [7:0] B, + input C, + input [2:0] sel, + output [7:0] result, + output r_n, + output r_z, + output reg r_v, + output reg r_c + ); + + localparam OP_OR = 0; + localparam OP_AND = 1; + localparam OP_EOR = 2; + localparam OP_ADC = 3; + localparam OP_SUB = 4; + localparam OP_ROT = 5; + localparam OP_SHF = 6; + + localparam SHIFT_LEFT = 0; + localparam SHIFT_RIGHT = 1; + + wire rst = !nrst; + reg [8:0] buffer; + wire [8:0] sum; + wire [8:0] diff; + + assign result[7:0] = buffer[7:0]; + assign r_z = buffer[7:0] == 0; + assign r_n = buffer[7]; + assign sum = A + B + C; + assign diff = A - B - (1 - C); + + always @(posedge clk) + begin + case (sel) + OP_OR: + begin + buffer <= A | B; + end + OP_AND: + begin + buffer <= A & B; + end + OP_EOR: + begin + buffer <= A ^ B; + end + OP_ADC: + begin + buffer <= sum; + r_c <= sum[8]; + r_v <= !(A[7] ^ B[7]) & (A[7] & sum[7]); + end + OP_SUB: + begin + buffer <= diff; + r_c <= diff[8]; + r_v <= !(A[7] ^ B[7]) & (A[7] & diff[7]); + end + OP_ROT: + begin + if (B == SHIFT_LEFT) begin + buffer[8:1] <= A[7:0]; + buffer[0] <= C; + r_c <= A[7]; + end + else begin + buffer[6:0] <= A[7:1]; + buffer[7] <= C; + r_c <= A[0]; + end + end + OP_SHF: + begin + if (B == SHIFT_LEFT) begin + buffer[8:1] <= A[7:0]; + buffer[0] <= 0; + r_c <= A[7]; + end + else begin + buffer[6:0] <= A[7:1]; + buffer[7] <= 0; + r_c <= A[0]; + end + end + endcase // case sel + end + +endmodule diff --git a/tests/test_alu.verilog b/tests/test_alu.verilog new file mode 100644 index 0000000..fe2f5d3 --- /dev/null +++ b/tests/test_alu.verilog @@ -0,0 +1,120 @@ +module test_alu; + initial begin + $dumpfile("test.vcd"); + $dumpvars(0, test_alu); + end + +`define assert(signal, value) \ +if (signal !== value) begin \ + $display("ASSERTION FAILED in %m: signal != value"); \ + $finish; \ + end + + + reg nrst = 1; + reg clk = 0; + + reg [7:0] A; + reg [7:0] B; + reg C; + reg [2:0] op_sel; + + wire [7:0] result; + wire r_z; + wire r_n; + wire r_c; + wire r_v; + + always #1 clk = !clk; + + alu my_alu( + .nrst(nrst), + .clk(clk), + .A(A), + .B(B), + .C(C), + .sel(op_sel), + .result(result), + .r_z(r_z), + .r_n(r_n), + .r_c(r_c), + .r_v(r_v)); + + initial begin + #10 A = 8'h11; + B = 8'h22; + C = 0; + op_sel = 0; // OR + + #2 `assert (result, 8'h33); + + #2 op_sel = 1; // AND + + #2 `assert (result, 8'h00); + + #2 op_sel = 2; // EOR + + #2 `assert (result, 8'h33); + + #2 A = 8'h22; + B = 8'h22; + + #2 `assert (result, 8'h00); + + #2 op_sel = 3; // ADC + + #2 A = 8'h22; + B = 8'h22; + + #2 `assert (result, 8'h44); + + #2 C = 1; // ADD with CARRY + + #2 `assert (result, 8'h45); + + #2 A = 8'hf0; + B = 8'h10; + C = 0; + + #2 `assert (r_c, 1); + + #2 op_sel = 4; + A = 8'hf0; + B = 8'h10; + C = 0; + #2 `assert (result, 8'hdf); + + #2 C = 1; + + #2 `assert (result, 8'he0); + + #2 op_sel = 5; + + A = 8'hf0; + B = 8'h00; + C = 1; + + #2 `assert (result, 8'he1); + `assert (r_c, 1); + + #2 C = 0; + + #2 `assert (result, 8'he0); + + #2 B = 1; + C = 0; + + #2 `assert (result, 8'h78); + + #2 A = 8'hf1; + C = 1; + + #2 `assert (result, 8'hf8); + `assert (r_c, 1); + + #2 op_sel = 6; + + #500 $finish; + end + +endmodule