In what way could my design be cleaner? As I said, this is my first attempt at Verilog.
This is a characteristic of CPLDs & FPGA. It is not a characteristic of verilog programming.
Clocking the FPGA, meaning is you feed for example a 50MHz clock in your design, at the absolute most basic, this means once you modify your inputs, all the output bits will change to their new results at the next clock cycle, usually all in a crisp parallel manner.
A non-clocked design just means the combination of logic gates which generate your function will ripple through the CPLD internal fuse wiring until a stable result is reached. Just like a wiring of 74LS/HC gates to make your ALU. However, since you only want to replicate a 74LS IC, the CPLD should still run circles around it.
Ok, for cleaning your design, let's take a look at this:
Beginning:
module ALU
// 16 bit adder/subtracter
// Opcode 0 produces A + B
// Opcode 1 produces A - B
// Opcode 2 produces A + 1
// Opcode 3 produces -B
#(parameter WIDTH = 16)
(output reg [WIDTH - 1:0] result, output reg c, output reg v, output reg n, // I had to add the 'reg' so that the always @(*) begin will function and also allow clocking in the future if you so desire.
input [3 : 0] opcode, input [WIDTH - 1:0] A, input [WIDTH - 1:0] B);
Good enough.
Next, lets wires containing your 4 calculated opcodes:
wire [WIDTH:0] i_add = A + B ; // We are adding the extra 1 bit at the top to keep track of the carry/borrow flag.
wire [WIDTH:0] i_sub = A - B ;
wire [WIDTH:0] i_inc = A + 1 ;
wire [WIDTH:0] i_negb = 0 - B ; // I wired it like this to hopefully help direct the compiler to a simplification of the inputs.
Now, lets set the outputs:
always @(*) begin // If we ever want to clock this design, the ' @(*) ' here would change to ' @(posedge clk_in) '
case (opcode[1:0]) // You only wanted to use the 2 bottom bits of the opcode.
2'd0 : begin // A+B
result <= i_add [WIDTH - 1:0] ; // Trim the i_add integer bits down to the 'WIDTH' to match 'result's width
c <= i_add [WIDTH] ; // I'm assuming ' c ' is the carry / borrow flag.
v <= 1'b0 ; // What does 'v' equal?
n <= 1'b0 ; // is n a negative flag? Are you using signed numbers? This would change things.
end
2'd1 : begin // A-B
result <= i_sub [WIDTH - 1:0] ; // Trim the i_add integer bits down to the 'WIDTH' to match 'result's width
c <= i_sub [WIDTH] ; // I'm assuming ' c ' is the carry / borrow flag.
v <= 1'b0 ; // What does 'v' equal?
n <= (B > A) ; // is n a negative flag? Are you using signed numbers?
end
2'd2 : begin // A+1
result <= i_inc [WIDTH - 1:0] ; // Trim the i_add integer bits down to the 'WIDTH' to match 'result's width
c <= i_inc [WIDTH] ; // I'm assuming ' c ' is the carry / borrow flag.
v <= 1'b0 ; // What does 'v' equal?
n <= 1'b0 ; // is n a negative flag? Are you using signed numbers?
end
2'd3 : begin // 0-B
result <= i_negb[WIDTH - 1:0] ; // Trim the i_add integer bits down to the 'WIDTH' to match 'result's width
c <= i_negb[WIDTH] ; // I'm assuming ' c ' is the carry / borrow flag.
v <= 1'b0 ; // What does 'v' equal?
n <= 1'b1 ; // is n a negative flag? Are you using signed numbers?
end
endcase
end // always @(*)
endmodule
This should make a little more sense and allow you to add opcodes if you wish.
Though, what does the 'v' stand for? I have not computed the 'v' in my code. It is just always set to 0.
This code took too many marcocells with a 'speed' optimized compile.
Setting the compiler optimization to 'Area' allowed this code to fit with 104 of 128 macrocells.
I've attached a Quartus 13.0sp1 full project using an EPM7128 which seems to compile and fit this code.