Austin
Austin

Reputation: 7319

Structural Verilog 8-Function ALU

I know how to code an ALU using behavioral style, but I'm completely lost as to how to do it using structural design. I need an 8-function bit-slice structural ALU so I can change the word size through a parameter which gets passed and it still works. I found a schematic for a 2-function ALU, but would anyone tell me how I could translate it to 8-function or possibly link me to a Verilog example for it? Here's the 2-function ALU schematic:

enter image description here

I can't remember remotely enough about truth tables, k-maps, etc. to even attempt to figure out the logic for this on my own. Not sure where to even start. Any help is greatly appreciated, thanks!

Upvotes: 0

Views: 1818

Answers (1)

Unn
Unn

Reputation: 5098

Unless you are trying to simplify the logic down to a minimal form (which is honestly wasted effort as synthesis tools are very good at doing this themselves, at least when it comes to combining terms to get smaller, functional equivalent logic), you can break this problem down further. You should typically be thinking in this way when writing behavioral Verilog, as doing so makes it more likely for your design to synthesize into a workable, solid netlist.

You have a schematic, so start by taking the major pieces of the design and implementing modules to do those functions. For example, you have a number of 2x1 muxes in the design. So, we should implement logic that selects from the correct input. Now, what is a mux? Well, it s a basic combinational function that looks like this:

S  A  B  O
----------
0  0  x  0
0  1  x  1
1  x  0  0
1  x  1  1

Ie, if S is 0, O = A, if S is 1, O = B. So, we can reformat these to logical expressions: O = ~S & A | S & B (Note, if S = 0, we will pass A and the B term will be 0'd out, and vice versa if S is 1).

Now just implement that in Verilog gate primatives:

module mux2x1(input A,
              input B,
              input S,
              output O);

  wire AO, BO, NOT_S;

  not n1(NOT_S, S);     // NOT_S = ~S;
  and a1(AO, A, NOT_S), // AO = A & ~S;
      a2(BO, B, S);     // BO = B & S;
  or  o1(O, BO, AO);    // O = (A & ~S) | (B & S);

endmodule

Now, in order to increase the width of A, B and O, we need only make a bunch of these muxes for each bit of A, B and O. We can do that but generating a much of our mux module, or but doing it to the logic inside the module like so:

module mux2x1 #(parameter W = 1)
             (input [W-1:0] A,
              input [W-1:0] B,
              input S,
              output [W-1:0] O);

  wire [W-1:0] AO, BO;
  wire NOT_S;
  genvar i;

  not n1(NOT_S, S);     // NOT_S = ~S;
  generate begin
    for (i = 0; i < W; i = i + 1) begin : mux_w
      and a1(AO[i], A[i], NOT_S),    // AO[i] = A[i] & ~S;
          a2(BO[i], B[i], S);        // BO[i] = B[i] & S;
      or  o1(O[i], BO[i], AO[i]);    // O[i] = (A[i] & ~S) | (B[i] & S);
    end
  end

endmodule

Now that you see a worked through example, I hope you can work through doing other modules the same way (like the adder and 4x1 mux). This really wasnt a formal way of doing it, but it helps to just think things through. Also note there are plenty of adder architectures online if you are having trouble figuring out the logic.

Upvotes: 1

Related Questions