Sunday, April 10, 2011

Soft Core ALU, SUB Instruction

Bang! Subtraction was a lot easier than i was originally thinking. i didn't remember this from my boolean algebra but basically we can use an adder, any kind of adder as a subtractor by remembering some simple math concepts.

First, subtraction is relational, meaning that:
A - B != B - A

Remember these proofs?

Therefore subtraction must maintain a relation of the numbers that are being operated on, where the coder must realize the difference in their function that the above proof is realized. So, in subtraction, position must be maintained between the A value and the B value.

Next, i was asking myself, "Self, if there is such thing as a Carry Lookahead Adder, is there such thing as a Borrow Lookahead Subtractor?" Well, in fact yes, by simply following some boolean rules.

Remember how we would "add" a number as a negative to in actuality subtract the numbers? We take the 2's compliment of the B value. How do we accomplish this with minimal HDL restructuring? Well, we invert all of the bits of the B value and make the carry in (borrow in?) of the CLA logic a constant 1'b1.

Bingo! Borrow Lookahead Subtractor!

Here, i'll help you out:
wire bin;
assign bin = 1'b1;

wire ndin2;
assign ndin2 = din2 ^ 'hf;
The XOR only has to be done at the 4-bit level if you write HDL like me an build a hierarchical structure from base units. Meaning, instantiate the 4-bit four times, to create a 16-bit, then instantiate the 16-bit four times to get a 64-bit.....etc, etc.

Oh, the last thing i did was invert the borrow out logic decode, as i'd think seeing a 1 for borrow out, means that the number has "borrowed" from the calculation space. So the logic looks like this:
assign bout =
!((gen[3])|
(prop[3]&gen[2])|
(prop[3]&prop[2]&gen[1])|
(prop[3]&prop[2]&prop[1]&gen[0])|
(prop[3]&prop[2]&prop[1]&prop[0]&bin));

As before, here's the modified test bench that you can checkout. Note that the carry (borrow) in is removed as it has been made constant in the logic (no more borrow in). However most of the test bench is the same as the CLA test bench.
/*
-----------------------------------------------------
               OriginalD Proprietary
                        2011
-----------------------------------------------------
File     : sub_tb.v
Designer : Dustin Brothers 
Date     : April 10, 2011
Abstract : Provides testing for all levels of the SUB
         block.
-----------------------------------------------------
Description    :
   This test bench provides test ability for all levels
of the subtractor operation of the SUB block.
   This test bench is self verifying in that it will
print out the status of each test performed after the
testing has been done.

ToDo           :

Known Issues   :

-----------------------------------------------------
Development Log
-----------------------------------------------------
Date     Init     Description
-----------------------------------------------------
04/11/10 DB       Initial Design.
-----------------------------------------------------
*/

`timescale 1ns/100ps

module sub_tb;

// Common Ports
wire bout;

`ifdef DUMP
// Dumpfile
initial
begin
   $dumpfile( "file.dmp" );
   $dumpvars;
end
`endif

/**************** For 4-bit test ***************/
`ifdef SUB4
// sub4 Specific Ports
reg [3:0] din1, din2;
wire [3:0] dout;

// Task Variable
`define WIDTH 3

// Instance
sub_4bit SUB4(
   .din1(din1),
   .din2(din2),
   .dout(dout),
   .bout(bout)
   );
`endif /********* End 4-bit test **********/

/**************** For 16-bit test ***************/
`ifdef SUB16
// sub4 Specific Ports
reg [15:0] din1, din2;
wire [15:0] dout;

// Task Variable
`define WIDTH 15 

// Instance
sub_16bit SUB16(
   .din1(din1),
   .din2(din2),
   .dout(dout),
   .bout(bout)
   );
`endif /********* End 16-bit test *********/

/**************** For 64-bit test ***************/
`ifdef SUB64
// sub4 Specific Ports
reg [63:0] din1, din2;
wire [63:0] dout;

// Task Variable
`define WIDTH 63

// Instance
sub_64bit SUB64(
   .din1(din1),
   .din2(din2),
   .dout(dout),
   .bout(bout)
   );
`endif /********* End 64-bit test *********/

/**************** For 256-bit test ***************/
`ifdef SUB256
// sub4 Specific Ports
reg [255:0] din1, din2;
wire [255:0] dout;

// Task Variable
`define WIDTH 255 

// Instance
sub_256bit SUB256(
   .din1(din1),
   .din2(din2),
   .dout(dout),
   .bout(bout)
   );
`endif /********* End 256-bit test *********/

// Setup Loop Variables
reg [`WIDTH+1:0] data1, data2;            // Need the extra bit for the loop comparison

// Simulation
initial
begin
   // Simulation
   $display( "######## Start of SIM #########" );

`ifdef STRAIGHT
   // Loop Through all the awesomeness
   for( data1 = 0; data1 < 2**(`WIDTH+1); data1 = data1 + 1 )
   begin
      din1 <= data1[`WIDTH:0];
      for( data2 = 0; data2 < 2**(`WIDTH+1); data2 = data2 + 1 )
      begin
         din2 <= data2[`WIDTH:0];
         #1 subInOut( din1, din2, dout, bout );
      end
   end
`else
   din1 <= 'h0;
   din2 <= 'h1;
   #1 subInOut( din1, din2, dout, bout );

   #5
   din1 <= 2**((`WIDTH+1)/2);             // Go half way
   din2 <= 2**((`WIDTH+1)/4);             // Go quarter way
   #1 subInOut( din1, din2, dout, bout );

   #5
   din1 <= 2**((`WIDTH+1)/3);
   din2 <= 2**((`WIDTH+1)/8);
   #1 subInOut( din1, din2, dout, bout );

   #5
   din1 <= 2**((`WIDTH+1)/8);
   din2 <= 2**(`WIDTH+1) - 1;     
   #1 subInOut( din1, din2, dout, bout );
`endif

   #100
   $display( "######### End of SIM ##########" );
   $finish;
end

// Test Function
task subInOut;
   input [`WIDTH:0] in1, in2, out1;
   input bout;

begin
   if(out1 != (in1-in2)) 
      $display( "In1: %h, In2: %h, Out: %h, Exp: %h, Borrow: %b -- Fail", in1, in2, out1, (in1-in2), bout );
   else
      $display( "In1: %h, In2: %h, Out: %h, Exp: %h, Borrow: %b -- Pass", in1, in2, out1, (in1-in2), bout );
end

endtask

endmodule

0 comments: