Beginning Logic Design – Part 7

Hello and welcome to Part 7 of my Beginning Logic Design series. In this post I will continue to add functionality to the ALU I’ve been working on in the last couple posts.

Using Vivado Via Command Line

This ALU project is making decent progress and I’d like to start managing the code with Git and make my work flow a bit faster. When I talk to engineers that work with FPGAs for a living, it seems like most of them do not use the project flow that I’ve been working with. They favor the command line or batch mode approach.

I’ll first copy my alu.sv and top.sv to a new directory so that those files are all I have. To build and test on the command line there are 3 commands I’ll use, xvlog to parse my SystemVerilog, xelab to elaborate the design, and xsim to run the simulation.

  1. xvlog --sv alu.sv top.sv
  2. xelab top
  3. xsim -R top
xvlog --sv alu.sv top.sv
xelab top
xsim -R top

Armed with these commands, I can more easily write my code in whichever editor I choose!

I’ll use this Makefile to give me an easy way to test and clean up the built files and logs.

  1. XVLOG_FILES=xvlog.log xvlog.pb xsim.dir
  2. XELAB_FILES=webtalk*.log webtalk*.jou xelab.log xelab.pb .Xil/
  3. XSIM_FILES=xsim*.log xsim*.jou
  4. all:
  5. @echo "Parsing HDL"
  6. @xvlog --sv *.sv > build.log
  7. @echo "Elaborating design"
  8. @xelab top >> build.log
  9. @echo "Starting simulation"
  10. @xsim -R top
  11. clean:
  12. rm -rf $(XVLOG_FILES) $(XELAB_FILES) $(XSIM_FILES) build.log
XVLOG_FILES=xvlog.log xvlog.pb xsim.dir
XELAB_FILES=webtalk*.log webtalk*.jou xelab.log xelab.pb .Xil/
XSIM_FILES=xsim*.log xsim*.jou

all:
  @echo "Parsing HDL"
  @xvlog --sv *.sv > build.log
  @echo "Elaborating design"
  @xelab top >> build.log
  @echo "Starting simulation"
  @xsim -R top

clean:
  rm -rf $(XVLOG_FILES) $(XELAB_FILES) $(XSIM_FILES) build.log



Implementing Subtraction

Subtraction in binary is nearly identical to addition. In the case of subtraction, carry is looked at as a borrow value. Building a subtraction operation in SystemVerilog is the same as addition, but with - instead of +.

  1. // Subtract operation internals
  2. logic [7:0] subtract;
  3. logic [6:0] subtract_lower_bits;
  4. logic subtract_borrow_6;
  5. logic subtract_borrow_7;
  6. ...
  7. assign {subtract_borrow_6, subtract_lower_bits} = a[6:0] - b[6:0] - carry_in,
  8. {subtract_borrow_7, subtract} = a - b - carry_in;
  9. ...
  10. SUBTRACT: begin
  11. y <= subtract;
  12. carry_out <= subtract_borrow_7;
  13. sign <= subtract[7];
  14. overflow <= subtract_borrow_7 ^ subtract_borrow_6;
  15. if (subtract == 0)
  16. zero <= 1;
  17. else
  18. zero <= 0;
  19. end
// Subtract operation internals
logic [7:0] subtract;
logic [6:0] subtract_lower_bits;
logic subtract_borrow_6;
logic subtract_borrow_7;

...

assign {subtract_borrow_6, subtract_lower_bits} = a[6:0] - b[6:0] - carry_in,
    {subtract_borrow_7, subtract} = a - b - carry_in;

...

        SUBTRACT: begin
            y <= subtract;
            carry_out <= subtract_borrow_7;
            sign <= subtract[7];
            overflow <= subtract_borrow_7 ^ subtract_borrow_6;
            if (subtract == 0)
                zero <= 1;
            else
                zero <= 0;
        end

As with the addition, I’ll make some tests that validate I’m getting the results I expect from the operation.

  1. // Test 100 - 80
  2. operation = SUBTRACT;
  3. a = 100;
  4. b = 80;
  5. #2 assert(y == 20) else $error("Subtract assertion failed.");
  6. assert(zero == 0) else $error("Zero assertion failed.");
  7. assert(sign == 0) else $error("Sign assertion failed.");
  8. assert(carry_out == 0) else $error("Carry assertion failed.");
  9. assert(overflow == 0) else $error("Overflow assertion failed.");
  10. // Test 80 - 100
  11. a = 80;
  12. b = 100;
  13. #2 assert(y == 236) else $error("Subtract assertion failed.");
  14. assert(zero == 0) else $error("Zero assertion failed.");
  15. assert(sign == 1) else $error("Sign assertion failed.");
  16. assert(carry_out == 1) else $error("Carry assertion failed.");
  17. assert(overflow == 0) else $error("Overflow assertion failed.");
  18. // Test 80 - 176
  19. a = 80;
  20. b = 176;
  21. #2 assert(y == 160) else $error("Subtract assertion failed.");
  22. assert(zero == 0) else $error("Zero assertion failed.");
  23. assert(sign == 1) else $error("Sign assertion failed.");
  24. assert(carry_out == 1) else $error("Carry assertion failed.");
  25. assert(overflow == 1) else $error("Overflow assertion failed.");
  26. // Test 208 - 112
  27. a = 208;
  28. b = 112;
  29. #2 assert(y == 96) else $error("Subtract assertion failed.");
  30. assert(zero == 0) else $error("Zero assertion failed.");
  31. assert(sign == 0) else $error("Sign assertion failed.");
  32. assert(carry_out == 0) else $error("Carry assertion failed.");
  33. assert(overflow == 1) else $error("Overflow assertion failed.");
  34. // Test 208 - 208
  35. a = 208;
  36. b = 208;
  37. #2 assert(y == 0) else $error("Subtract assertion failed.");
  38. assert(zero == 1) else $error("Zero assertion failed.");
  39. assert(sign == 0) else $error("Sign assertion failed.");
  40. assert(carry_out == 0) else $error("Carry assertion failed.");
  41. assert(overflow == 0) else $error("Overflow assertion failed.");
// Test 100 - 80
operation = SUBTRACT;
a = 100;
b = 80;
#2 assert(y == 20) else $error("Subtract assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");
assert(carry_out == 0) else $error("Carry assertion failed.");
assert(overflow == 0) else $error("Overflow assertion failed.");

// Test 80 - 100
a = 80;
b = 100;
#2 assert(y == 236) else $error("Subtract assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 1) else $error("Sign assertion failed.");
assert(carry_out == 1) else $error("Carry assertion failed.");
assert(overflow == 0) else $error("Overflow assertion failed.");

// Test 80 - 176
a = 80;
b = 176;
#2 assert(y == 160) else $error("Subtract assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 1) else $error("Sign assertion failed.");
assert(carry_out == 1) else $error("Carry assertion failed.");
assert(overflow == 1) else $error("Overflow assertion failed.");

// Test 208 - 112
a = 208;
b = 112;
#2 assert(y == 96) else $error("Subtract assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");
assert(carry_out == 0) else $error("Carry assertion failed.");
assert(overflow == 1) else $error("Overflow assertion failed.");

// Test 208 - 208
a = 208;
b = 208;
#2 assert(y == 0) else $error("Subtract assertion failed.");
assert(zero == 1) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");
assert(carry_out == 0) else $error("Carry assertion failed.");
assert(overflow == 0) else $error("Overflow assertion failed.");

Implementing Remaining Operations

Addition and Subtraction are the trickiest operations to implement of the operations planned for this ALU. With two instructions down there are 10 to go,

  • Arithmetic Operations
    • Add with Carry
    • Subtract with Carry
    • Increment
    • Decrement
  • Logic Operations
    • AND
    • OR
    • XOR
    • NOT/Negate (not in 6502, but I want my ALU to have it!)
  • Shifting Operations
    • Arithmetic Shift Left
    • Logical Shift Right
    • Rotate Left
    • Rotate Right

Increment & Decrement

Increment and decrement only affect the sign and zero flags, and adds or subtracts 1 from a single operand. To implement them I’ll use assign again to give me a reference to an incremented and decremented value.

  1. // Increment/Decrement
  2. logic [7:0] incremented;
  3. logic [7:0] decremented;
  4. assign incremented = a + 1,
  5. decremented = a - 1;
// Increment/Decrement
logic [7:0] incremented;
logic [7:0] decremented;


assign incremented = a + 1,
  decremented = a - 1;

Then in my case statement on operation, I’ll add the INCREMENT and DECREMENT cases.

  1. INCREMENT: begin
  2. y <= incremented;
  3. sign <= incremented[7];
  4. if (incremented == 0)
  5. zero <= 1;
  6. else
  7. zero <= 0;
  8. end
  9. DECREMENT: begin
  10. y <= decremented;
  11. sign <= decremented[7];
  12. if (decremented == 0)
  13. zero <= 1;
  14. else
  15. zero <= 0;
  16. end
INCREMENT: begin
  y <= incremented;
  sign <= incremented[7];
  if (incremented == 0) 
    zero <= 1;
  else
    zero <= 0;
end
DECREMENT: begin
  y <= decremented;
  sign <= decremented[7];
  if (decremented == 0) 
    zero <= 1;
  else
    zero <= 0;
end

Then I’ll add some more tests to top to verify it.

  1. // Test 0++
  2. operation = INCREMENT;
  3. a = 0;
  4. #2 assert(y == 1) else $error("Increment assertion failed.");
  5. assert(zero == 0) else $error("Zero assertion failed.");
  6. assert(sign == 0) else $error("Sign assertion failed.");
  7. // Test 200++
  8. a = 200;
  9. #2 assert(y == 201) else $error("Increment assertion failed.");
  10. assert(zero == 0) else $error("Zero assertion failed.");
  11. assert(sign == 1) else $error("Sign assertion failed.");
  12. // Test 255++
  13. a = 255;
  14. #2 assert(y == 0) else $error("Increment assertion failed.");
  15. assert(zero == 1) else $error("Zero assertion failed.");
  16. assert(sign == 0) else $error("Sign assertion failed.");
  17. // Test 0--
  18. operation = DECREMENT;
  19. a = 0;
  20. #2 assert(y == 255) else $error("Decrement assertion failed.");
  21. assert(zero == 0) else $error("Zero assertion failed.");
  22. assert(sign == 1) else $error("Sign assertion failed.");
  23. // Test 200--
  24. a = 200;
  25. #2 assert(y == 199) else $error("Decrement assertion failed.");
  26. assert(zero == 0) else $error("Zero assertion failed.");
  27. assert(sign == 1) else $error("Sign assertion failed.");
  28. // Test 1--
  29. a = 1;
  30. #2 assert(y == 0) else $error("Decrement assertion failed.");
  31. assert(zero == 1) else $error("Zero assertion failed.");
  32. assert(sign == 0) else $error("Sign a
// Test 0++
operation = INCREMENT;
a = 0;
#2 assert(y == 1) else $error("Increment assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test 200++
a = 200;
#2 assert(y == 201) else $error("Increment assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 1) else $error("Sign assertion failed.");

// Test 255++
a = 255;
#2 assert(y == 0) else $error("Increment assertion failed.");
assert(zero == 1) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test 0--
operation = DECREMENT;
a = 0;
#2 assert(y == 255) else $error("Decrement assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 1) else $error("Sign assertion failed.");

// Test 200--
a = 200;
#2 assert(y == 199) else $error("Decrement assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 1) else $error("Sign assertion failed.");

// Test 1--
a = 1;
#2 assert(y == 0) else $error("Decrement assertion failed.");
assert(zero == 1) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign a

Logic Operations

The logic operations AND, OR, XOR, and NOT are the easiest operations to implement. Very similar to what I did for increment and decrement, I’ll name some new variables and keep them assigned to the results for each operation. Then they are added to the case statement.

  1. // Logic operations
  2. logic [7:0] and_result;
  3. logic [7:0] or_result;
  4. logic [7:0] xor_result;
  5. logic [7:0] not_result;
  6. // Logic assignments
  7. assign and_result = a & b,
  8. or_result = a | b,
  9. xor_result = a ^ b,
  10. not_result = ~a;
  11. ...
  12. BIT_AND: begin
  13. y <= and_result;
  14. sign <= and_result[7];
  15. if (and_result == 0)
  16. zero <= 1;
  17. else
  18. zero <= 0;
  19. end
  20. BIT_OR: begin
  21. y <= or_result;
  22. sign <= or_result[7];
  23. if (or_result == 0)
  24. zero <= 1;
  25. else
  26. zero <= 0;
  27. end
  28. BIT_XOR: begin
  29. y <= xor_result;
  30. sign <= xor_result[7];
  31. if (xor_result == 0)
  32. zero <= 1;
  33. else
  34. zero <= 0;
  35. end
  36. BIT_NOT: begin
  37. y <= not_result;
  38. sign <= not_result[7];
  39. if (not_result == 0)
  40. zero <= 1;
  41. else
  42. zero <= 0;
  43. end
// Logic operations
logic [7:0] and_result;
logic [7:0] or_result;
logic [7:0] xor_result;
logic [7:0] not_result;

// Logic assignments
assign and_result = a & b,
  or_result = a | b,
  xor_result = a ^ b,
  not_result = ~a;

...

    BIT_AND: begin
      y <= and_result;
      sign <= and_result[7];
      if (and_result == 0)
        zero <= 1;
      else
        zero <= 0;
    end
    BIT_OR: begin
      y <= or_result;
      sign <= or_result[7];
      if (or_result == 0)
        zero <= 1;
      else
        zero <= 0;
    end
    BIT_XOR: begin
      y <= xor_result;
      sign <= xor_result[7];
      if (xor_result == 0)
        zero <= 1;
      else
        zero <= 0;
    end
    BIT_NOT: begin
      y <= not_result;
      sign <= not_result[7];
      if (not_result == 0)
        zero <= 1;
      else
        zero <= 0;
    end

Then some tests to verify.

  1. // Test 12 & 10
  2. operation = BIT_AND;
  3. a = 12;
  4. b = 10;
  5. #2 assert(y == 8) else $error("AND assertion failed.");
  6. assert(zero == 0) else $error("Zero assertion failed.");
  7. assert(sign == 0) else $error("Sign assertion failed.");
  8. // Test 13 | 15
  9. operation = BIT_OR;
  10. a = 13;
  11. b = 15;
  12. #2 assert(y == 15) else $error("OR assertion failed.");
  13. assert(zero == 0) else $error("Zero assertion failed.");
  14. assert(sign == 0) else $error("Sign assertion failed.");
  15. // Test 13 ^ 15
  16. operation = BIT_XOR;
  17. a = 13;
  18. b = 15;
  19. #2 assert(y == 2) else $error("XOR assertion failed.");
  20. assert(zero == 0) else $error("Zero assertion failed.");
  21. assert(sign == 0) else $error("Sign assertion failed.");
  22. // Test 13 & 15
  23. operation = BIT_NOT;
  24. a = 13;
  25. #2 assert(y == 242) else $error("NOT assertion failed.");
  26. assert(zero == 0) else $error("Zero assertion failed.");
  27. assert(sign == 1) else $error("Sign assertion failed.");
// Test 12 & 10
operation = BIT_AND;
a = 12;
b = 10;
#2 assert(y == 8) else $error("AND assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test 13 | 15
operation = BIT_OR;
a = 13;
b = 15;
#2 assert(y == 15) else $error("OR assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test 13 ^ 15
operation = BIT_XOR;
a = 13;
b = 15;
#2 assert(y == 2) else $error("XOR assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test 13 & 15
operation = BIT_NOT;
a = 13;
#2 assert(y == 242) else $error("NOT assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 1) else $error("Sign assertion failed.");

Shifting Operations

The last few operations to add are the shifters. Rotate left and rotate right shift all the bits left or right by one position. In the case of a right shift, the leftmost bit will change to the carry in bit, and the rightmost bit will become the new carry out. In the arithmetic and logical shift operations the bit being pushed in will be 0 regardless of the carry in value.

  1. // Shifting operations
  2. logic [7:0] rotated_left;
  3. logic [7:0] rotated_right;
  4. logic [7:0] shifted_left;
  5. logic [7:0] shifted_right;
  6. // Shifting assignments
  7. assign rotated_left = {a[6:0], carry_in},
  8. rotated_right = {carry_in, a[7:1]},
  9. shifted_left = {a[6:0], 1'b0},
  10. shifted_right = {1'b0, a[7:1]};
  11. ...
  12. ROTATE_LEFT: begin
  13. y <= rotated_left;
  14. carry_out <= a[7];
  15. sign <= rotated_left[7];
  16. if (rotated_left == 0)
  17. zero <= 1;
  18. else
  19. zero <= 0;
  20. end
  21. ROTATE_RIGHT: begin
  22. y <= rotated_right;
  23. carry_out <= a[0];
  24. sign <= rotated_right[7];
  25. if (rotated_right == 0)
  26. zero <= 1;
  27. else
  28. zero <= 0;
  29. end
  30. SHIFT_LEFT: begin
  31. y <= shifted_left;
  32. carry_out <= a[7];
  33. sign <= shifted_left[7];
  34. if (shifted_left == 0)
  35. zero <= 1;
  36. else
  37. zero <= 0;
  38. end
  39. SHIFT_RIGHT: begin
  40. y <= shifted_right;
  41. carry_out <= a[0];
  42. sign <= shifted_right[7];
  43. if (shifted_right == 0)
  44. zero <= 1;
  45. else
  46. zero <= 0;
// Shifting operations
logic [7:0] rotated_left;
logic [7:0] rotated_right;
logic [7:0] shifted_left;
logic [7:0] shifted_right;

// Shifting assignments
assign rotated_left = {a[6:0], carry_in},
  rotated_right = {carry_in, a[7:1]},
  shifted_left = {a[6:0], 1'b0},
  shifted_right = {1'b0, a[7:1]};

...

    ROTATE_LEFT: begin
      y <= rotated_left;
      carry_out <= a[7];
      sign <= rotated_left[7];
      if (rotated_left == 0)
        zero <= 1;
      else
        zero <= 0;
    end
    ROTATE_RIGHT: begin
      y <= rotated_right;
      carry_out <= a[0];
      sign <= rotated_right[7];
      if (rotated_right == 0)
        zero <= 1;
      else
        zero <= 0;
    end
    SHIFT_LEFT: begin
      y <= shifted_left;
      carry_out <= a[7];
      sign <= shifted_left[7];
      if (shifted_left == 0)
        zero <= 1;
      else
        zero <= 0;
    end
    SHIFT_RIGHT: begin
      y <= shifted_right;
      carry_out <= a[0];
      sign <= shifted_right[7];
      if (shifted_right == 0)
        zero <= 1;
      else
        zero <= 0;

For the shift assignments I use 1'b0 to specify a 1 bit binary with the value 0 in the concatenation. As always some tests to validate we’re getting the right behavior.

  1. // Test shift left
  2. operation = SHIFT_LEFT;
  3. carry_in = 1;
  4. a = 136;
  5. #2 assert(y == 16) else $error("Shift left assertion failed.");
  6. assert(carry_out == 1) else $error("carry assertion failed.");
  7. assert(zero == 0) else $error("Zero assertion failed.");
  8. assert(sign == 0) else $error("Sign assertion failed.");
  9. // Test shift right
  10. operation = SHIFT_RIGHT;
  11. a = 8;
  12. #2 assert(y == 4) else $error("Shift right assertion failed.");
  13. assert(carry_out == 0) else $error("carry assertion failed.");
  14. assert(zero == 0) else $error("Zero assertion failed.");
  15. assert(sign == 0) else $error("Sign assertion failed.");
  16. // Test rotate left
  17. operation = ROTATE_LEFT;
  18. a = 8;
  19. #2 assert(y == 17) else $error("Rotate left assertion failed.");
  20. assert(carry_out == 0) else $error("carry assertion failed.");
  21. assert(zero == 0) else $error("Zero assertion failed.");
  22. assert(sign == 0) else $error("Sign assertion failed.");
  23. // Test rotate right
  24. operation = ROTATE_RIGHT;
  25. a = 9;
  26. #2 assert(y == 132) else $error("Rotate right assertion failed.");
  27. assert(carry_out == 1) else $error("carry assertion failed.");
  28. assert(zero == 0) else $error("Zero assertion failed.");
  29. assert(sign == 1) else $error("Sign assertion failed.");
// Test shift left
operation = SHIFT_LEFT;
carry_in = 1;
a = 136;
#2 assert(y == 16) else $error("Shift left assertion failed.");
assert(carry_out == 1) else $error("carry assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test shift right
operation = SHIFT_RIGHT;
a = 8;
#2 assert(y == 4) else $error("Shift right assertion failed.");
assert(carry_out == 0) else $error("carry assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test rotate left
operation = ROTATE_LEFT;
a = 8;
#2 assert(y == 17) else $error("Rotate left assertion failed.");
assert(carry_out == 0) else $error("carry assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 0) else $error("Sign assertion failed.");

// Test rotate right
operation = ROTATE_RIGHT;
a = 9;
#2 assert(y == 132) else $error("Rotate right assertion failed.");
assert(carry_out == 1) else $error("carry assertion failed.");
assert(zero == 0) else $error("Zero assertion failed.");
assert(sign == 1) else $error("Sign assertion failed.");

It Works!

There it is! An ALU implementation that can handle 12 different 8-bit operations. It took 3 posts to get here, but this is a decently large design. Here’s the final alu.sv file

  1. `timescale 1ns / 1ps
  2. package ALU;
  3. typedef enum logic [3:0] {
  4. ADD,
  5. SUBTRACT,
  6. INCREMENT,
  7. DECREMENT,
  8. BIT_AND,
  9. BIT_OR,
  10. BIT_XOR,
  11. BIT_NOT,
  12. SHIFT_LEFT,
  13. SHIFT_RIGHT,
  14. ROTATE_LEFT,
  15. ROTATE_RIGHT
  16. } opcode;
  17. endpackage
  18. import ALU::*;
  19. module alu (
  20. input logic clock,
  21. input opcode operation,
  22. input logic [7:0] a,
  23. input logic [7:0] b,
  24. input logic carry_in,
  25. output logic [7:0] y,
  26. output logic zero,
  27. output logic sign,
  28. output logic carry_out,
  29. output logic overflow
  30. );
  31. // Add operation internals
  32. logic [7:0] add;
  33. logic [6:0] add_lower_bits;
  34. logic add_carry_6;
  35. logic add_carry_7;
  36. // Subtract operation internals
  37. logic [7:0] subtract;
  38. logic [6:0] subtract_lower_bits;
  39. logic subtract_borrow_6;
  40. logic subtract_borrow_7;
  41. // Increment/Decrement
  42. logic [7:0] incremented;
  43. logic [7:0] decremented;
  44. // Logic operations
  45. logic [7:0] and_result;
  46. logic [7:0] or_result;
  47. logic [7:0] xor_result;
  48. logic [7:0] not_result;
  49. // Shifting operations
  50. logic [7:0] rotated_left;
  51. logic [7:0] rotated_right;
  52. logic [7:0] shifted_left;
  53. logic [7:0] shifted_right;
  54. // Add assignments
  55. assign {add_carry_6, add_lower_bits} = a[6:0] + b[6:0] + carry_in,
  56. {add_carry_7, add} = a + b + carry_in;
  57. // Subtract assignments
  58. assign {subtract_borrow_6, subtract_lower_bits} = a[6:0] - b[6:0] - carry_in,
  59. {subtract_borrow_7, subtract} = a - b - carry_in;
  60. // Increment/decrement assignments
  61. assign incremented = a + 1,
  62. decremented = a - 1;
  63. // Logic assignments
  64. assign and_result = a & b,
  65. or_result = a | b,
  66. xor_result = a ^ b,
  67. not_result = ~a;
  68. // Shifting assignments
  69. assign rotated_left = {a[6:0], carry_in},
  70. rotated_right = {carry_in, a[7:1]},
  71. shifted_left = {a[6:0], 1'b0},
  72. shifted_right = {1'b0, a[7:1]};
  73. always_ff @ (posedge clock) begin
  74. case (operation)
  75. ADD: begin
  76. y <= add;
  77. carry_out <= add_carry_7;
  78. sign <= add[7];
  79. overflow <= add_carry_7 ^ add_carry_6;
  80. if (add == 0)
  81. zero <= 1;
  82. else
  83. zero <= 0;
  84. end
  85. SUBTRACT: begin
  86. y <= subtract;
  87. carry_out <= subtract_borrow_7;
  88. sign <= subtract[7];
  89. overflow <= subtract_borrow_7 ^ subtract_borrow_6;
  90. if (subtract == 0)
  91. zero <= 1;
  92. else
  93. zero <= 0;
  94. end
  95. INCREMENT: begin
  96. y <= incremented;
  97. sign <= incremented[7];
  98. if (incremented == 0)
  99. zero <= 1;
  100. else
  101. zero <= 0;
  102. end
  103. DECREMENT: begin
  104. y <= decremented;
  105. sign <= decremented[7];
  106. if (decremented == 0)
  107. zero <= 1;
  108. else
  109. zero <= 0;
  110. end
  111. BIT_AND: begin
  112. y <= and_result;
  113. sign <= and_result[7];
  114. if (and_result == 0)
  115. zero <= 1;
  116. else
  117. zero <= 0;
  118. end
  119. BIT_OR: begin
  120. y <= or_result;
  121. sign <= or_result[7];
  122. if (or_result == 0)
  123. zero <= 1;
  124. else
  125. zero <= 0;
  126. end
  127. BIT_XOR: begin
  128. y <= xor_result;
  129. sign <= xor_result[7];
  130. if (xor_result == 0)
  131. zero <= 1;
  132. else
  133. zero <= 0;
  134. end
  135. BIT_NOT: begin
  136. y <= not_result;
  137. sign <= not_result[7];
  138. if (not_result == 0)
  139. zero <= 1;
  140. else
  141. zero <= 0;
  142. end
  143. ROTATE_LEFT: begin
  144. y <= rotated_left;
  145. carry_out <= a[7];
  146. sign <= rotated_left[7];
  147. if (rotated_left == 0)
  148. zero <= 1;
  149. else
  150. zero <= 0;
  151. end
  152. ROTATE_RIGHT: begin
  153. y <= rotated_right;
  154. carry_out <= a[0];
  155. sign <= rotated_right[7];
  156. if (rotated_right == 0)
  157. zero <= 1;
  158. else
  159. zero <= 0;
  160. end
  161. SHIFT_LEFT: begin
  162. y <= shifted_left;
  163. carry_out <= a[7];
  164. sign <= shifted_left[7];
  165. if (shifted_left == 0)
  166. zero <= 1;
  167. else
  168. zero <= 0;
  169. end
  170. SHIFT_RIGHT: begin
  171. y <= shifted_right;
  172. carry_out <= a[0];
  173. sign <= shifted_right[7];
  174. if (shifted_right == 0)
  175. zero <= 1;
  176. else
  177. zero <= 0;
  178. end
  179. endcase
  180. end
  181. endmodule
`timescale 1ns / 1ps

package ALU;
  typedef enum logic [3:0] {
    ADD,
    SUBTRACT,
    INCREMENT,
    DECREMENT,
    BIT_AND,
    BIT_OR,
    BIT_XOR,
    BIT_NOT,
    SHIFT_LEFT,
    SHIFT_RIGHT,
    ROTATE_LEFT,
    ROTATE_RIGHT
  } opcode;
endpackage

import ALU::*;

module alu (
  input logic clock,
  input opcode operation,
  input logic [7:0] a,
  input logic [7:0] b,
  input logic carry_in,
  output logic [7:0] y,
  output logic zero,
  output logic sign,
  output logic carry_out,
  output logic overflow
);

  // Add operation internals
  logic [7:0] add;
  logic [6:0] add_lower_bits;
  logic add_carry_6;
  logic add_carry_7;

  // Subtract operation internals
  logic [7:0] subtract;
  logic [6:0] subtract_lower_bits;
  logic subtract_borrow_6;
  logic subtract_borrow_7;

  // Increment/Decrement
  logic [7:0] incremented;
  logic [7:0] decremented;

  // Logic operations
  logic [7:0] and_result;
  logic [7:0] or_result;
  logic [7:0] xor_result;
  logic [7:0] not_result;

  // Shifting operations
  logic [7:0] rotated_left;
  logic [7:0] rotated_right;
  logic [7:0] shifted_left;
  logic [7:0] shifted_right;

  // Add assignments
  assign {add_carry_6, add_lower_bits} = a[6:0] + b[6:0] + carry_in,
    {add_carry_7, add} = a + b + carry_in;

  // Subtract assignments
  assign {subtract_borrow_6, subtract_lower_bits} = a[6:0] - b[6:0] - carry_in,
    {subtract_borrow_7, subtract} = a - b - carry_in;

  // Increment/decrement assignments
  assign incremented = a + 1,
    decremented = a - 1;

  // Logic assignments
  assign and_result = a & b,
    or_result = a | b,
    xor_result = a ^ b,
    not_result = ~a;

  // Shifting assignments
  assign rotated_left = {a[6:0], carry_in},
    rotated_right = {carry_in, a[7:1]},
    shifted_left = {a[6:0], 1'b0},
    shifted_right = {1'b0, a[7:1]};

  always_ff @ (posedge clock) begin
    case (operation)
      ADD: begin
        y <= add;
        carry_out <= add_carry_7;
        sign <= add[7];
        overflow <= add_carry_7 ^ add_carry_6;
        if (add == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      SUBTRACT: begin
        y <= subtract;
        carry_out <= subtract_borrow_7;
        sign <= subtract[7];
        overflow <= subtract_borrow_7 ^ subtract_borrow_6;
        if (subtract == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      INCREMENT: begin
        y <= incremented;
        sign <= incremented[7];
        if (incremented == 0) 
          zero <= 1;
        else
          zero <= 0;
      end
      DECREMENT: begin
        y <= decremented;
        sign <= decremented[7];
        if (decremented == 0) 
          zero <= 1;
        else
          zero <= 0;
      end
      BIT_AND: begin
        y <= and_result;
        sign <= and_result[7];
        if (and_result == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      BIT_OR: begin
        y <= or_result;
        sign <= or_result[7];
        if (or_result == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      BIT_XOR: begin
        y <= xor_result;
        sign <= xor_result[7];
        if (xor_result == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      BIT_NOT: begin
        y <= not_result;
        sign <= not_result[7];
        if (not_result == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      ROTATE_LEFT: begin
        y <= rotated_left;
        carry_out <= a[7];
        sign <= rotated_left[7];
        if (rotated_left == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      ROTATE_RIGHT: begin
        y <= rotated_right;
        carry_out <= a[0];
        sign <= rotated_right[7];
        if (rotated_right == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      SHIFT_LEFT: begin
        y <= shifted_left;
        carry_out <= a[7];
        sign <= shifted_left[7];
        if (shifted_left == 0)
          zero <= 1;
        else
          zero <= 0;
      end
      SHIFT_RIGHT: begin
        y <= shifted_right;
        carry_out <= a[0];
        sign <= shifted_right[7];
        if (shifted_right == 0)
          zero <= 1;
        else
          zero <= 0;
      end
    endcase
  end

  endmodule

And the final top.sv

  1. `timescale 1ns / 1ps
  2. import ALU::*;
  3. module top ();
  4. logic clock;
  5. opcode operation;
  6. logic [7:0] a;
  7. logic [7:0] b;
  8. logic carry_in;
  9. logic [7:0] y;
  10. logic zero;
  11. logic sign;
  12. logic carry_out;
  13. logic overflow;
  14. alu myALU (
  15. clock,
  16. operation,
  17. a,
  18. b,
  19. carry_in,
  20. y,
  21. zero,
  22. sign,
  23. carry_out,
  24. overflow
  25. );
  26. initial begin
  27. clock = 0;
  28. operation = ADD;
  29. carry_in = 0;
  30. // Test 208 + 144
  31. a = 208;
  32. b = 144;
  33. #2 assert(y == 96) else $error("Sum assertion failed.");
  34. assert(zero == 0) else $error("Zero assertion failed.");
  35. assert(sign == 0) else $error("Sign assertion failed.");
  36. assert(carry_out == 1) else $error("Carry assertion failed.");
  37. assert(overflow == 1) else $error("Overflow assertion failed.");
  38. // Test 208 + 48 (signed -48 + 48)
  39. a = 208;
  40. b = 48;
  41. #2 assert(y == 0) else $error("Sum assertion failed.");
  42. assert(zero == 1) else $error("Zero assertion failed.");
  43. assert(sign == 0) else $error("Sign assertion failed.");
  44. assert(carry_out == 1) else $error("Carry assertion failed.");
  45. assert(overflow == 0) else $error("Overflow assertion failed.");
  46. // Test 80 + 80
  47. a = 80;
  48. b = 80;
  49. #2 assert(y == 160) else $error("Sum assertion failed.");
  50. assert(zero == 0) else $error("Zero assertion failed.");
  51. assert(sign == 1) else $error("Sign assertion failed.");
  52. assert(carry_out == 0) else $error("Carry assertion failed.");
  53. assert(overflow == 1) else $error("Overflow assertion failed.");
  54. // Test 100 - 80
  55. operation = SUBTRACT;
  56. a = 100;
  57. b = 80;
  58. #2 assert(y == 20) else $error("Subtract assertion failed.");
  59. assert(zero == 0) else $error("Zero assertion failed.");
  60. assert(sign == 0) else $error("Sign assertion failed.");
  61. assert(carry_out == 0) else $error("Carry assertion failed.");
  62. assert(overflow == 0) else $error("Overflow assertion failed.");
  63. // Test 80 - 100
  64. a = 80;
  65. b = 100;
  66. #2 assert(y == 236) else $error("Subtract assertion failed.");
  67. assert(zero == 0) else $error("Zero assertion failed.");
  68. assert(sign == 1) else $error("Sign assertion failed.");
  69. assert(carry_out == 1) else $error("Carry assertion failed.");
  70. assert(overflow == 0) else $error("Overflow assertion failed.");
  71. // Test 80 - 176
  72. a = 80;
  73. b = 176;
  74. #2 assert(y == 160) else $error("Subtract assertion failed.");
  75. assert(zero == 0) else $error("Zero assertion failed.");
  76. assert(sign == 1) else $error("Sign assertion failed.");
  77. assert(carry_out == 1) else $error("Carry assertion failed.");
  78. assert(overflow == 1) else $error("Overflow assertion failed.");
  79. // Test 208 - 112
  80. a = 208;
  81. b = 112;
  82. #2 assert(y == 96) else $error("Subtract assertion failed.");
  83. assert(zero == 0) else $error("Zero assertion failed.");
  84. assert(sign == 0) else $error("Sign assertion failed.");
  85. assert(carry_out == 0) else $error("Carry assertion failed.");
  86. assert(overflow == 1) else $error("Overflow assertion failed.");
  87. // Test 208 - 208
  88. a = 208;
  89. b = 208;
  90. #2 assert(y == 0) else $error("Subtract assertion failed.");
  91. assert(zero == 1) else $error("Zero assertion failed.");
  92. assert(sign == 0) else $error("Sign assertion failed.");
  93. assert(carry_out == 0) else $error("Carry assertion failed.");
  94. assert(overflow == 0) else $error("Overflow assertion failed.");
  95. // Test 0++
  96. operation = INCREMENT;
  97. a = 0;
  98. #2 assert(y == 1) else $error("Increment assertion failed.");
  99. assert(zero == 0) else $error("Zero assertion failed.");
  100. assert(sign == 0) else $error("Sign assertion failed.");
  101. // Test 200++
  102. a = 200;
  103. #2 assert(y == 201) else $error("Increment assertion failed.");
  104. assert(zero == 0) else $error("Zero assertion failed.");
  105. assert(sign == 1) else $error("Sign assertion failed.");
  106. // Test 255++
  107. a = 255;
  108. #2 assert(y == 0) else $error("Increment assertion failed.");
  109. assert(zero == 1) else $error("Zero assertion failed.");
  110. assert(sign == 0) else $error("Sign assertion failed.");
  111. // Test 0--
  112. operation = DECREMENT;
  113. a = 0;
  114. #2 assert(y == 255) else $error("Decrement assertion failed.");
  115. assert(zero == 0) else $error("Zero assertion failed.");
  116. assert(sign == 1) else $error("Sign assertion failed.");
  117. // Test 200--
  118. a = 200;
  119. #2 assert(y == 199) else $error("Decrement assertion failed.");
  120. assert(zero == 0) else $error("Zero assertion failed.");
  121. assert(sign == 1) else $error("Sign assertion failed.");
  122. // Test 1--
  123. a = 1;
  124. #2 assert(y == 0) else $error("Decrement assertion failed.");
  125. assert(zero == 1) else $error("Zero assertion failed.");
  126. assert(sign == 0) else $error("Sign assertion failed.");
  127. // Test 12 & 10
  128. operation = BIT_AND;
  129. a = 12;
  130. b = 10;
  131. #2 assert(y == 8) else $error("AND assertion failed.");
  132. assert(zero == 0) else $error("Zero assertion failed.");
  133. assert(sign == 0) else $error("Sign assertion failed.");
  134. // Test 13 | 15
  135. operation = BIT_OR;
  136. a = 13;
  137. b = 15;
  138. #2 assert(y == 15) else $error("OR assertion failed.");
  139. assert(zero == 0) else $error("Zero assertion failed.");
  140. assert(sign == 0) else $error("Sign assertion failed.");
  141. // Test 13 ^ 15
  142. operation = BIT_XOR;
  143. a = 13;
  144. b = 15;
  145. #2 assert(y == 2) else $error("XOR assertion failed.");
  146. assert(zero == 0) else $error("Zero assertion failed.");
  147. assert(sign == 0) else $error("Sign assertion failed.");
  148. // Test 13 & 15
  149. operation = BIT_NOT;
  150. a = 13;
  151. #2 assert(y == 242) else $error("NOT assertion failed.");
  152. assert(zero == 0) else $error("Zero assertion failed.");
  153. assert(sign == 1) else $error("Sign assertion failed.");
  154. // Test shift left
  155. operation = SHIFT_LEFT;
  156. carry_in = 1;
  157. a = 136;
  158. #2 assert(y == 16) else $error("Shift left assertion failed.");
  159. assert(carry_out == 1) else $error("carry assertion failed.");
  160. assert(zero == 0) else $error("Zero assertion failed.");
  161. assert(sign == 0) else $error("Sign assertion failed.");
  162. // Test shift right
  163. operation = SHIFT_RIGHT;
  164. a = 8;
  165. #2 assert(y == 4) else $error("Shift right assertion failed.");
  166. assert(carry_out == 0) else $error("carry assertion failed.");
  167. assert(zero == 0) else $error("Zero assertion failed.");
  168. assert(sign == 0) else $error("Sign assertion failed.");
  169. // Test rotate left
  170. operation = ROTATE_LEFT;
  171. a = 8;
  172. #2 assert(y == 17) else $error("Rotate left assertion failed.");
  173. assert(carry_out == 0) else $error("carry assertion failed.");
  174. assert(zero == 0) else $error("Zero assertion failed.");
  175. assert(sign == 0) else $error("Sign assertion failed.");
  176. // Test rotate right
  177. operation = ROTATE_RIGHT;
  178. a = 9;
  179. #2 assert(y == 132) else $error("Rotate right assertion failed.");
  180. assert(carry_out == 1) else $error("carry assertion failed.");
  181. assert(zero == 0) else $error("Zero assertion failed.");
  182. assert(sign == 1) else $error("Sign assertion failed.");
  183. #1 $finish();
  184. end
  185. always begin
  186. #1 clock = ~clock;
  187. end
  188. endmodule
`timescale 1ns / 1ps

import ALU::*;

module top ();
  logic clock;
  opcode operation;
  logic [7:0] a;
  logic [7:0] b;
  logic carry_in;
  logic [7:0] y;
  logic zero;
  logic sign;
  logic carry_out;
  logic overflow;

  alu myALU (
    clock,
    operation,
    a,
    b,
    carry_in,
    y,
    zero,
    sign,
    carry_out,
    overflow
  );

  initial begin
    clock = 0;
    operation = ADD;
    carry_in = 0;

    // Test 208 + 144
    a = 208;
    b = 144;
    #2 assert(y == 96) else $error("Sum assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");
    assert(carry_out == 1) else $error("Carry assertion failed.");
    assert(overflow == 1) else $error("Overflow assertion failed.");

    // Test 208 + 48 (signed -48 + 48)
    a = 208;
    b = 48;
    #2 assert(y == 0) else $error("Sum assertion failed.");
    assert(zero == 1) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");
    assert(carry_out == 1) else $error("Carry assertion failed.");
    assert(overflow == 0) else $error("Overflow assertion failed.");

    // Test 80 + 80
    a = 80;
    b = 80;
    #2 assert(y == 160) else $error("Sum assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");
    assert(carry_out == 0) else $error("Carry assertion failed.");
    assert(overflow == 1) else $error("Overflow assertion failed.");

    // Test 100 - 80
    operation = SUBTRACT;
    a = 100;
    b = 80;
    #2 assert(y == 20) else $error("Subtract assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");
    assert(carry_out == 0) else $error("Carry assertion failed.");
    assert(overflow == 0) else $error("Overflow assertion failed.");

    // Test 80 - 100
    a = 80;
    b = 100;
    #2 assert(y == 236) else $error("Subtract assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");
    assert(carry_out == 1) else $error("Carry assertion failed.");
    assert(overflow == 0) else $error("Overflow assertion failed.");

    // Test 80 - 176
    a = 80;
    b = 176;
    #2 assert(y == 160) else $error("Subtract assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");
    assert(carry_out == 1) else $error("Carry assertion failed.");
    assert(overflow == 1) else $error("Overflow assertion failed.");

    // Test 208 - 112
    a = 208;
    b = 112;
    #2 assert(y == 96) else $error("Subtract assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");
    assert(carry_out == 0) else $error("Carry assertion failed.");
    assert(overflow == 1) else $error("Overflow assertion failed.");

    // Test 208 - 208
    a = 208;
    b = 208;
    #2 assert(y == 0) else $error("Subtract assertion failed.");
    assert(zero == 1) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");
    assert(carry_out == 0) else $error("Carry assertion failed.");
    assert(overflow == 0) else $error("Overflow assertion failed.");

    // Test 0++
    operation = INCREMENT;
    a = 0;
    #2 assert(y == 1) else $error("Increment assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test 200++
    a = 200;
    #2 assert(y == 201) else $error("Increment assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");

    // Test 255++
    a = 255;
    #2 assert(y == 0) else $error("Increment assertion failed.");
    assert(zero == 1) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test 0--
    operation = DECREMENT;
    a = 0;
    #2 assert(y == 255) else $error("Decrement assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");

    // Test 200--
    a = 200;
    #2 assert(y == 199) else $error("Decrement assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");

    // Test 1--
    a = 1;
    #2 assert(y == 0) else $error("Decrement assertion failed.");
    assert(zero == 1) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test 12 & 10
    operation = BIT_AND;
    a = 12;
    b = 10;
    #2 assert(y == 8) else $error("AND assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test 13 | 15
    operation = BIT_OR;
    a = 13;
    b = 15;
    #2 assert(y == 15) else $error("OR assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test 13 ^ 15
    operation = BIT_XOR;
    a = 13;
    b = 15;
    #2 assert(y == 2) else $error("XOR assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test 13 & 15
    operation = BIT_NOT;
    a = 13;
    #2 assert(y == 242) else $error("NOT assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");

    // Test shift left
    operation = SHIFT_LEFT;
    carry_in = 1;
    a = 136;
    #2 assert(y == 16) else $error("Shift left assertion failed.");
    assert(carry_out == 1) else $error("carry assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test shift right
    operation = SHIFT_RIGHT;
    a = 8;
    #2 assert(y == 4) else $error("Shift right assertion failed.");
    assert(carry_out == 0) else $error("carry assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test rotate left
    operation = ROTATE_LEFT;
    a = 8;
    #2 assert(y == 17) else $error("Rotate left assertion failed.");
    assert(carry_out == 0) else $error("carry assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 0) else $error("Sign assertion failed.");

    // Test rotate right
    operation = ROTATE_RIGHT;
    a = 9;
    #2 assert(y == 132) else $error("Rotate right assertion failed.");
    assert(carry_out == 1) else $error("carry assertion failed.");
    assert(zero == 0) else $error("Zero assertion failed.");
    assert(sign == 1) else $error("Sign assertion failed.");

    #1 $finish();
  end

  always begin
    #1 clock = ~clock;
  end

endmodule

With the ALU working I’ll call it a wrap for this post. If you have any questions or feedback be sure to leave a comment. Keep tinkering!

Leave a Reply