Now that we know about module ports and wires, we can put together
some simple combinatorial logic blocks.  We'll stick to what we've
covered so far and just add math and logic operators.  C programmers
will feel right at home.


module simple_math (
   input1, input2, sel_in,
   out_sum, out_dif,
   out_shl, out_shr,
   out_bit_and, out_bit_or, out_bit_xor, out_bit_not,
   out_bool_and, out_bool_or, out_bool_not,
   out_reduction_and, out_reduction_or,
   out_mux
   out_eq, out_ne, out_gt, out_lt, out_ge, out_le);

input [7:0] input1, input2;  // 8-bit inputs for simplicity
input sel_in;  // selector for ternary operator

// Outputs will be explained below
output [8:0] out_sum, out_dif;   // extra bit for carry
output [15:0] out_shl;
output [7:0] out_shr;
output [7:0] out_bit_and, out_bit_or, out_bit_xor, out_bit_not;
output out_bool_and, out_bool_or, out_bool_not;
output out_reduction_and, out_reduction_or;
output [7:0] out_mux;
output out_eq, out_ne, out_gt, out_lt, out_ge, out_le;

// Add and sub are simple enough.  In Verilog, if the sum were a
sub-expression, its size (google for "natural size") would be 8 bits,
but since it's being assigned to a 9-bit wire, it'll correctly produce
the extra carry bit.
// The data types are unsigned from the point of view of Verilog, so
if we care about signs, we have to add extra logic.

assign out_sum = input1 + input2;
assign out_dif = input1 - input2;

// We've given the shift-left some extra bits just for fun.  If you
shift right or left too far, you'll just get zero as a result.  It's
often useful to do a bit slice on the shift amount just to save logic,
so if your input and output are 8-bit, you only need a 3 or 4 bit
shift, unless you want to be able to shift more and get zero.

assign out_shl = input1 << input2;
assign out_shr = input1 >> input2[2:0];  // Demonstrating the bit-slice

// Bit-wise operators are just like in C.  Corresponding bits are
operated on in parallel.

assign out_bit_and = input1 & input2;
assign out_bit_or = input1 | input2;
assign out_bit_xor = input1 ^ input2;
assign out_bit_not = ~input1;

// Boolean operators are a bit different from the bit-wise operators.
Just like in C, the whole bus is considered to be zero (false) or any
non-zero value (true).

assign out_bool_and = input1 && input2;
assign out_bool_or = input1 || input2;
assign out_bool_not = !input1;

// Verilog has reduction operators.  They take all bits in the bus and
reduce them to a single bit that indicates if they're all 1's (and) or
any of them are 1's (or).

assign out_reduction_or = |input1;
assign out_reduction_and = &input1;

// Note:  ~|input1 means no bits are 1, and ~&input1 means some bits are zero.

// C has this ?: operator that takes a boolean and chooses between two
other expressions.  Verilog has the same thing.

assign out_mux = sel_in ? input1 : input2;

// How about some comparison operators

assign out_eq = input1 == input2;
assign out_ne = input1 != input2;
assign out_gt = input1 > input2;   // all of these are unsigned comparisons
assign out_lt = input1 < input2;
assign out_ge = input1 >= input2;
assign out_le = input1 <= input2;

endmodule



I'm sure I've missed a few, but I have the basics covered.  Others can
point out anything I didn't think of.  There are also multiply (*),
divide (/), and I think mod (%) operators, but you avoid them for
synthesis.  They are, however, quite useful for simulation.  Some
chips have built-in multipliers, and the synthesis tools will infer
them from *, but I tend to manually instantiate them because then I
have more control over additional features that the blocks tend to
provide.


I don't know about Lattice, but Xilinx's synthesizer doesn't handle a
carry-in correctly for an add, so if you do this:

wire [7:0] x, y;
wire c;
wire [8:0] z = x + y + c;

You'll get very poor results.  The solution I use is to subtract the
1's compliment:

wire [8:0] z = c ? (x - (~y)) : (x + y);

The analogue for borrowing for subtract is to add the 1's compliment.

For synthesis, I would structure it a bit differently to get the
synthesizer to infer a unified addsub block.  (The extra parens
generally are not necessary; I just like to make things clear to the
reader.)
_______________________________________________
Open-graphics mailing list
[email protected]
http://lists.duskglow.com/mailman/listinfo/open-graphics
List service provided by Duskglow Consulting, LLC (www.duskglow.com)

Reply via email to