Explorar el Código

Improved ALU

Made ALU independant of general_pkg. Added quite a few instructions,
including multiplication, divition, modulus, signed/unsigned operations,
carry in/out, condition flags at output.
Min hace 6 años
padre
commit
04e6bdfb83
Se han modificado 1 ficheros con 138 adiciones y 80 borrados
  1. 138 80
      src/blocks/alu.sv

+ 138 - 80
src/blocks/alu.sv

@@ -1,104 +1,162 @@
-import project_pkg::*;
+package alu_pkg;
 
-module alu(op, exop, srcA, srcB, result, zero);
+	typedef enum logic [3:0] {
+		 ALU_ADD = 4'd0, 
+		 ALU_SUB = 4'd1,
+		 ALU_AND = 4'd2,
+		 ALU_OR  = 4'd3,
+		 ALU_XOR = 4'd4,
+		 ALU_NAND= 4'd5,
+		 ALU_NOR = 4'd6,
+		 ALU_XNOR= 4'd7,
+		 ALU_SL  = 4'd8,
+		 ALU_SR  = 4'd9,
+		 ALU_ROR = 4'd10,
+		 ALU_ROL = 4'd11,
+		 ALU_MUL = 4'd12,
+		 ALU_DIV = 4'd13,
+		 ALU_MOD = 4'd14
+	} e_alu_op;
 	
-	input  e_alu_op 	op;
-	input  word			srcA;
-	input  word			srcB;
-	input  e_alu_ext_op exop; 
-	output word			result;
-	output logic		zero;
+
+endpackage
+
+import alu_pkg::*;
+
+module alu(
+	srcA, srcB, result, op, cin, sign, zero, cout, gt, equal, overflow
+);
+	parameter WORD=8;
+	localparam WSIZE=$clog2(WORD);
+
+	input e_alu_op 			op;
+	input logic 			cin, sign;
+	input logic [WORD-1:0] 	srcA, srcB;
+	
+	output logic 			zero, cout, gt, equal, overflow;
+	output logic [WORD-1:0] result;
+	
+	logic [WSIZE-1:0] shmt;
+	assign shmt = srcB[WSIZE-1:0];
 	
+	// FIXME: Seems like there's a bug with ModelSim or Verilog
+	// Object must be signed to do arithmetic shift right
+	// casting $signed does not work. Tho folloing passes:
+ 	// assert(8'sb1000_0100 >>> 2 == 8'sb1110_0001);
+	reg signed [WORD-1:0] signedA, sr;
+	assign signedA = srcA;
+	assign sr = signedA >>> shmt;
+
 	always_comb begin
 	case(op)
-		ALU_CPY: result = srcB;
-		ALU_ADD: result = srcA + srcB;
-		ALU_SUB: result = srcA - srcB;
+		ALU_ADD: {cout, result} = (srcA + cin) + srcB;
+		ALU_SUB: {cout, result} = (srcA + cin) - srcB;
 		ALU_AND: result = srcA & srcB;
 		ALU_OR : result = srcA | srcB;
 		ALU_XOR: result = srcA ^ srcB;
-		ALU_GT : result = srcA > srcB;
-		ALU_EXT: begin
-				case(exop)
-						AEX_SHFL: result = srcA << 1;
-						AEX_SHFR: result = srcA >> 1;
-						AEX_ROTR: result = {srcA[0], srcA[7:1]};
-						default: result = srcA;
-				endcase
-		end
+		ALU_NAND: result = ~(srcA & srcB);
+		ALU_NOR : result = ~(srcA | srcB);
+		ALU_XNOR: result = ~(srcA ^ srcB);
+		ALU_SL: result = srcA << shmt;
+		ALU_SR: result = (sign) ? sr : srcA >> shmt;
+		ALU_ROL: result = {srcA[0], srcA[WORD-1:1]};
+		ALU_ROR: result = {srcA[WORD-2:0], srcA[WORD-1]};
+		ALU_MUL: result = srcA * srcB;
+		ALU_DIV: result = srcA / srcB;
+		ALU_MOD: result = srcA % srcB;
 		default: result = 0;
 	endcase
 	end
+
 	assign zero = result == 0;
-	
+	assign equal = srcA == srcB;
+	assign gt = srcA > srcB;
+
 endmodule
 
 module alu_tb;
 	e_alu_op op;
-	word srcA, srcB, result;
-	logic zero;
+	logic [7:0]srcA, srcB, result;
+	logic overflow, zero, cin, cout, gt, equal, sign;
 	
-	alu ALU(op, srcA, srcB, result, zero);
+	alu test_alu(
+		.op(op),
+		.srcA(srcA), 
+		.srcB(srcB),
+		.result(result),
+		.zero(zero),
+		.cin(cin),
+		.cout(cout),
+		.gt(gt),
+		.equal(equal),
+		.sign(sign),
+		.overflow(overflow)
+	);
+
+	task test;
+		input e_alu_op t_op;
+		input [7:0] t_a, t_b, t_e;
+		begin
+			op = t_op;
+			srcA = t_a;
+			srcB = t_b;
+			#1
+			$write("ALU Test: %d %8s %d = %d ", 
+				(sign) ? $signed(t_a) : t_a,
+				op.name, 
+				(sign) ? $signed(t_b) : t_b,
+				(sign) ? $signed(result) : result
+			);
+			if (result == t_e) $display("(correct)");
+			else $display("(expected %d)", t_e); 
+			assert(result == t_e);	
+		end		
+	endtask
 	
-	initial begin
-		op = ALU_CPY;
-		srcA = 120;
-		srcB = 100;
-		#5ns;
-		assert(result == srcA);
-		
-		op = ALU_ADD;
-		#5ns;
-		assert(result == 220);
-		
-		op = ALU_SUB;
-		#5ns;
-		assert(result == 20);
-		
-		op = ALU_AND;
-		// 01100100 & 01111000 = 01100000
-		#5ns;
-		assert(result == 96);
+	task testb;
+		input e_alu_op t_op;
+		input [7:0] t_a, t_b, t_e;
+		begin
+			op = t_op;
+			srcA = t_a;
+			srcB = t_b;
+			#1
+			$write("ALU Test: %b %8s %b = %b ", t_a, op.name, t_b, result);
+			if (result == t_e) $display("(correct)");
+			else $display("(expected %b)", t_e); 
+			assert(result == t_e);	
+		end		
+	endtask
 
-		op = ALU_OR;
-		// 01100100 | 01111000 = 01111100
-		#5ns;
-		assert(result == 124);
-		
-		op = ALU_XOR;
-		#5ns;
-		assert(result == 28);
-		
-		op = ALU_GT;
-		#5ns;
-		assert(result == 1);
-		
-		srcB = 140;
-		#5ns;
-		assert(result == 0);
-		assert(zero == 1);
-		
-		op = ALU_EXT;
-		srcB = 8'b000xx000;
-		#5ns;
-		assert(result == srcA);
-		
-		srcB = 8'b000xx001;
-		#5ns;
-		assert(result == 240);
-		
-		srcB = 8'b001xx001;
-		#5ns;
-		assert(result == 60);
+	initial begin
+		sign = 0;
+		cin = 0;
+		test(ALU_ADD, 120, 100, 220);
+		test(ALU_SUB, 120, 100, 20);
+		testb(ALU_AND, 120, 100, 96);
+		testb(ALU_NAND, 100, 120, -97);
+		testb(ALU_OR, 100, 120, 124);
+		testb(ALU_NOR, 100, 120, -125);
+		testb(ALU_XOR, 100, 120, 28);
+		testb(ALU_XNOR, 100, 120, -29);
+		testb(ALU_SL, 8'b1111_0111, 2, 8'b1101_1100);
+		testb(ALU_SR, 8'b1110_1111, 2, 8'b0011_1011);
+		sign = 1;
+		$display("ALU Settings: sign = 1");
 		
-		srcB = 8'b001xx010;
-		#5ns;
-		assert(result == 30);
+		testb(ALU_SR, 8'b1000_0100, 2, 8'b1110_0001);
+		testb(ALU_SR, 8'b0000_0100, 2, 8'b0000_0001);
+		test(ALU_ADD, -10, 20, 10);
+		test(ALU_SUB, -10, -20, 10);
 		
-		srcB = 8'b010xx100;
-		#5ns;
-		// 01111000 >>> 4 = 10000111
-		assert(result == 71);
+		testb(ALU_ROR, 8'b1100_0000, 0, 8'b1000_0001);
+		testb(ALU_ROL, 8'b0000_0011, 0, 8'b1000_0001);
+		test(ALU_MUL, 5, 8, 40);
+		test(ALU_DIV, 64, 4, 16);
+		test(ALU_DIV, 65, 4, 16);
+		test(ALU_MOD, 66, 4, 2);
+		test(ALU_MOD, 65, 4, 1);
+		test(ALU_MOD, 64, 4, 0);
 		$stop;
 	end