📄 addcore.tdf
字号:
----------------------------------------------------------------------
-- addcore: The adder core subdesign of LPM_ADD_SUB --
-- addcore implements an adder optimized for FLEX/FAST, --
-- FLEX/NORMAL, and MAX cases by using --
-- --
-- FLEX/FAST: a carry-chain implementation with chain breaking --
-- when a maximum carry chain length smaller than --
-- adder width has been specified. --
-- --
-- FLEX/NORMAL: a ripple carry structure. --
-- --
-- MAX : a ripple carry structure between 8-bit sub-adders --
-- and 8-bit carry-look-ahead within each sub-adder. --
----------------------------------------------------------------------
INCLUDE "addcore.inc";
PARAMETERS
(
WIDTH,
CONSTANT_CIN, -- Is cin connected to a fixed value? (0 No, 1 Yes)
CARRY_CHAIN,
CARRY_CHAIN_LENGTH,
DEVICE_FAMILY
);
INCLUDE "aglobal.inc"; % device definitions %
------------------------------------------
-- parameters related to FLEX/FAST case
------------------------------------------
-- CARRY_LEN is the number of LCELLs in full carry chain, excluding
-- the beginning and terminating LCELLs when chain brek is needed
CONSTANT CARRY_LEN = (CARRY_CHAIN_LENGTH <= 2) ? 0 : (CARRY_CHAIN_LENGTH - 2);
-- FULL_WIDTH determines the full length of the adder carry chain taking
-- usage of cin and cout outputs into conideration. Note that overflow
-- generated from cout.
DEFINE FULL_WIDTH() = WIDTH + (-(USED(cin) & (CONSTANT_CIN == 0))) + (-USED(cout));
-- FULL_CNT and PART_CNT are functions used to determine the number of full- and
-- partial carry chains, respectively
DEFINE FULL_CNT(n, c, i) = (c <= 2 # n < c) ? 0 : ((n == c) ? ((i == 1) ? 0 :
(1 + FULL_CNT(n-(c-2), c, i+1))) :
((i == 1) ? (1 + FULL_CNT(n-((c-2)+1), c, i+1)) :
(1 + FULL_CNT(n-(c-2), c, i+1))));
DEFINE PART_CNT(n, c, i) = (n < c) ? ((n < (c-1)) # ((n == (c-1)) & (I == 1)) ? (n) : 0) :
((n == c) ? ((i == 1) ? 0 : PART_CNT(n-(c-2), c, i+1)) :
((i == 1) ? PART_CNT(n-((c-2)+1), c, i+1) :
PART_CNT(n-(c-2), c, i+1)));
-- The number of full-length carry chain segements
DEFINE FULL_SEGS() = FULL_CNT (FULL_WIDTH(), CARRY_CHAIN_LENGTH, 1);
-- The length of a (possible) partial chain
DEFINE PART_WIDTH() = FULL_WIDTH() - (FULL_SEGS() * CARRY_LEN + CBASE());
-- index base, depending on the usage of cin
DEFINE CBASE() = -(!(USED(cin) & CONSTANT_CIN == 0));
DEFINE ADJ_WIDTH() = WIDTH + (-USED(cout));
DEFINE ADJ_PART_WIDTH() = (PART_WIDTH() == 0) ? 0 :
(ADJ_WIDTH() - (CARRY_LEN*FULL_SEGS()+CBASE()));
DEFINE NEED_PART_SEG() = (PART_WIDTH() == 0) ? 0 : 1;
DEFINE TOT_SEGS() = FULL_SEGS()+NEED_PART_SEG();
------------------------------------
-- parameters related to MAX cases
------------------------------------
CONSTANT TOT_BLOCKS = CEIL(WIDTH DIV 8);
CONSTANT FULL_BLOCKS = FLOOR(WIDTH DIV 8);
CONSTANT REM_WIDTH = WIDTH MOD 8;
CONSTANT REM_BLOCKS = (REM_WIDTH > 0) ? 1 : 0;
-- use FLEX/FAST or switch to NORMAL style?
DEFINE NEED_CHAIN() = (WIDTH > 2) & --# (WIDTH == 2 & USED(cin))) &
(CARRY_CHAIN != "IGNORE") & (CARRY_LEN > 1) ? 1 : 0;
SUBDESIGN addcore
(
dataa[WIDTH-1..0] : INPUT = GND;
datab[WIDTH-1..0] : INPUT = GND;
cin : INPUT = GND;
result[WIDTH-1..0] : OUTPUT;
cout : OUTPUT;
bg_out, bp_out : OUTPUT; -- block generate/propagate outputs
)
VARIABLE
IF WIDTH == 1 GENERATE
cin_node : NODE;
ELSE GENERATE
IF (FAMILY_FLEX() == 1) GENERATE
IF NEED_CHAIN() == 1 GENERATE
----------------------
-- FLEX/FAST cases --
----------------------
result_node[ADJ_WIDTH()-1..0] : NODE;
IF TOT_SEGS() == 1 GENERATE
cin_node : CARRY;
IF ADJ_WIDTH() > 1 GENERATE
pcarry[0][ADJ_WIDTH()-2..0] : CARRY;
END GENERATE;
ELSE GENERATE
cin_node : NODE;
first_seg_adder : addcore WITH (WIDTH = CARRY_LEN+CBASE(),
CONSTANT_CIN = CONSTANT_CIN);
IF (FULL_SEGS() > 1) GENERATE
full_seg_adder[FULL_SEGS()-2..0] : addcore WITH (WIDTH = CARRY_LEN,
CONSTANT_CIN = 0);
END GENERATE;
IF NEED_PART_SEG() > 0 GENERATE
part_seg_adder : addcore WITH (WIDTH = ADJ_PART_WIDTH(),
CONSTANT_CIN = 0);
END GENERATE;
END GENERATE;
-- block gen/prop signals are non-GND only when
-- width of the adder is 8.
IF WIDTH == 8 GENERATE
prop_node[3..0] : NODE;
genr_node[3..0] : NODE;
gp0 : NODE;
END GENERATE;
ELSE GENERATE
--------------------------
-- FLEX/NORMAL cases --
--------------------------
cin_node : NODE;
pcarry[WIDTH-1..0] : NODE;
IF WIDTH == 8 GENERATE
prop_node[3..0] : NODE;
genr_node[3..0] : NODE;
gp0 : NODE;
END GENERATE;
END GENERATE;
ELSE GENERATE
------------------------------
-- MAX cases with WIDTH = 8 --
------------------------------
-- this special case implements the 8-bit gdf version in tdf.
IF WIDTH == 8 GENERATE
gn[7..0] : NODE;
gs[7..1] : SOFT;
pp[7..0] : NODE;
ps[7..0] : SOFT;
psi[7..0] : NODE;
pc[6..0] : NODE;
gc[2..0] : NODE;
g2c[2..0] : NODE;
p2c[2..0] : NODE;
g3 : NODE;
g4 : SOFT;
g2cp[2..1] : SOFT;
gcp[2] : SOFT;
cin_node : NODE;
tot_cin_node[6..0] : NODE;
result_node[7..0] : SOFT;
cout_node : SOFT;
prop_node[3..0] : SOFT;
genr_node[3..0] : SOFT;
gp0 : NODE;
ELSE GENERATE
--------------------------------------
-- all MAX cases with WIDTH != 8 --
--------------------------------------
-- this case will use recursive call to itself to
-- implement a group of 8-bit MAX adders.
cin_node : NODE;
adder[TOT_BLOCKS-1..0] : addcore WITH (WIDTH = 8);
END GENERATE;
END GENERATE;
END GENERATE;
BEGIN
assert report "WIDTH = %, USED(cin) = %, NEED_CHAIN = %, CBASE = %" WIDTH, USED(cin), NEED_CHAIN(), CBASE() SEVERITY DEBUG;
assert report "WIDTH = %, TOT_SEGS = %, FULL_SEGS = %, FULL_WIDTH = %, PART_WIDTH = % , ADJ_PART_WIDTH = %, CBASE = %"
WIDTH, TOT_SEGS(), FULL_SEGS(), FULL_WIDTH(), PART_WIDTH(), ADJ_PART_WIDTH(), CBASE() SEVERITY DEBUG;
assert report "CIN_CONST = %, USED(cin) = %, RESULT = %,USED_COUT = %"
CONSTANT_CIN, USED(cin), USED(cin) & (CONSTANT_CIN == 0), (-USED(cout)) SEVERITY DEBUG;
-- cin is common between single-segment and multi-segment chains.
cin_node = cin;
IF WIDTH == 8 GENERATE
FOR I IN 0 TO 3 GENERATE
prop_node[I] = (dataa[2*I+1] # datab[2*I+1]) & (dataa[2*I] # datab[2*I]);
genr_node[I] = (dataa[2*I+1] & datab[2*I+1]) # (dataa[2*I+1] # datab[2*I+1]) &
(dataa[2*I] & datab[2*I]);
END GENERATE;
gp0 = prop_node[2] & (genr_node[1] # prop_node[1] & genr_node[0]);
bg_out = genr_node[3] # prop_node[3] & (genr_node[2] # gp0);
bp_out = prop_node[0] & prop_node[1] & prop_node[2] & prop_node[3];
ELSE GENERATE
bg_out = GND;
bp_out = GND;
END GENERATE;
-- the special case WIDTH = 1 is straightforward and no carry chains are needed.
IF WIDTH == 1 GENERATE
result[0] = dataa[0] $ datab[0] $ cin_node;
cout = dataa[0] & datab[0] # dataa[0] & cin_node # datab[0] & cin_node;
ELSE GENERATE
IF (FAMILY_FLEX() == 1) GENERATE
IF NEED_CHAIN() == 1 GENERATE
----------------------
-- FLEX/FAST cases --
----------------------
IF TOT_SEGS() == 1 GENERATE
-- Single-segment chain case
result_node[0] = dataa[0] $ datab[0] $ cin_node;
IF ADJ_WIDTH() > 1 GENERATE
pcarry[0][0] = (dataa[0] & datab[0]) #
(dataa[0] # datab[0]) & cin_node;
IF ADJ_WIDTH() > 2 GENERATE
FOR I IN 1 TO ADJ_WIDTH()-2 GENERATE
result_node[I] = dataa[I] $ datab[I] $ pcarry[0][I-1];
pcarry[0][I] = (dataa[I] & datab[I]) #
(dataa[I] # datab[I]) & pcarry[0][I-1];
END GENERATE;
END GENERATE;
IF USED(cout) GENERATE
result_node[ADJ_WIDTH()-1] = pcarry[0][ADJ_WIDTH()-2];
ELSE GENERATE
result_node[ADJ_WIDTH()-1] = dataa[ADJ_WIDTH()-1] $
datab[ADJ_WIDTH()-1] $
pcarry[0][ADJ_WIDTH()-2];
END GENERATE;
END GENERATE;
result[] = result_node[WIDTH-1..0];
IF USED(cout) GENERATE
cout = result_node[ADJ_WIDTH()-1];
END GENERATE;
ELSE GENERATE
-- Multi-segment chain case
-- First full segment
first_seg_adder.cin = cin_node;
first_seg_adder.dataa[] = dataa[CARRY_LEN+CBASE()-1..0];
first_seg_adder.datab[] = datab[CARRY_LEN+CBASE()-1..0];
result_node[CARRY_LEN+CBASE()-1..0] = first_seg_adder.result[];
-- Intermediate full segments
IF FULL_SEGS() > 1 GENERATE
full_seg_adder[0].cin = LCELL(first_seg_adder.cout);
full_seg_adder[0].dataa[] = dataa[2*CARRY_LEN+CBASE()-1..CARRY_LEN+CBASE()];
full_seg_adder[0].datab[] = datab[2*CARRY_LEN+CBASE()-1..CARRY_LEN+CBASE()];
result_node[2*CARRY_LEN+CBASE()-1..CARRY_LEN+CBASE()] = full_seg_adder[0].result[];
IF FULL_SEGS() > 2 GENERATE
FOR I IN 1 TO FULL_SEGS()-2 GENERATE
full_seg_adder[I].cin = LCELL(full_seg_adder[I-1].cout);
full_seg_adder[I].dataa[] = dataa[(I+2)*CARRY_LEN+CBASE()-1..(I+1)*CARRY_LEN+CBASE()];
full_seg_adder[I].datab[] = datab[(I+2)*CARRY_LEN+CBASE()-1..(I+1)*CARRY_LEN+CBASE()];
result_node[(I+2)*CARRY_LEN+CBASE()-1..(I+1)*CARRY_LEN+CBASE()] = full_seg_adder[I].result[];
END GENERATE;
END GENERATE;
END GENERATE;
-- Possible partially full segment
IF NEED_PART_SEG() > 0 GENERATE
IF FULL_SEGS() == 1 GENERATE
part_seg_adder.cin = LCELL(first_seg_adder.cout);
ELSE GENERATE
part_seg_adder.cin = LCELL(full_seg_adder[FULL_SEGS()-2].cout);
END GENERATE;
IF USED(cout) GENERATE
part_seg_adder.dataa[] = (GND, dataa[WIDTH-1..FULL_SEGS()*CARRY_LEN+CBASE()]);
part_seg_adder.datab[] = (GND, datab[WIDTH-1..FULL_SEGS()*CARRY_LEN+CBASE()]);
ELSE GENERATE
part_seg_adder.dataa[] = dataa[WIDTH-1..FULL_SEGS()*CARRY_LEN+CBASE()];
part_seg_adder.datab[] = datab[WIDTH-1..FULL_SEGS()*CARRY_LEN+CBASE()];
END GENERATE;
result_node[ADJ_WIDTH()-1..FULL_SEGS()*CARRY_LEN+CBASE()] = part_seg_adder.result[];
END GENERATE;
result[] = result_node[WIDTH-1..0];
IF USED(cout) GENERATE
cout = result_node[ADJ_WIDTH()-1];
END GENERATE;
END GENERATE;
ELSE GENERATE
assert report "FLEX/NORMAL" severity DEBUG;
--------------------------
-- FLEX/NORMAL cases --
--------------------------
pcarry[0] = (dataa[0] & datab[0]) # (dataa[0] & cin_node) #
(datab[0] & cin_node);
FOR I IN 1 TO WIDTH-1 GENERATE
pcarry[I] = (dataa[I] & datab[I]) # (dataa[I] # datab[I]) & pcarry[I-1];
END GENERATE;
result[0] = dataa[0] $ datab[0] $ cin_node;
result[WIDTH-1..1] = (dataa[WIDTH-1..1] $ pcarry[WIDTH-2..0]) $ datab[WIDTH-1..1];
cout = pcarry[WIDTH-1];
END GENERATE;
ELSE GENERATE
IF WIDTH == 8 GENERATE
assert report "MAX device with size 8" severity DEBUG;
------------------------------
-- MAX cases with WIDTH = 8 --
------------------------------
-- GENERATE (gn, gs) and PROPAGATE (!pp, !ps) functions
pp[0] = dataa[0] !# datab[0];
ps[0] = pp[0];
psi[0] = !ps[0];
gn[0] = dataa[0] & datab[0];
gc[0] = gn[0];
FOR I in 1 TO 7 GENERATE
pp[I] = dataa[I] !# datab[I];
ps[I] = pp[I];
psi[I] = !ps[I];
gn[I] = dataa[I] & datab[I];
gs[I] = gn[I];
END GENERATE;
-- Propagate cin all through 7 stages
pc[0] = psi[0] & cin_node;
FOR I in 1 TO 6 GENERATE
pc[I] = psi[I] & pc[I-1];
END GENERATE;
g3 = psi[3] & !gs[3];
-- g4 is the GENERATE function of first 4 bit positions
g4 = gn[3] $ (gc[2] & g3);
-- Propagate g4 through the positions 4-7
-- p2c is the propagated carry with g4 as carry input.
p2c[0] = g4 & psi[4];
p2c[1] = p2c[0] & psi[5];
p2c[2] = p2c[1] & psi[6];
-- gc is the generated carry at poistions 0 - 3.
gc[0] = gn[0];
gc[1] = gn[1] # psi[1] & gc[0];
gc[2] = gn[2] # psi[2] & gc[1];
-- gcp is the generated carry at poistion 4 - 6.
gcp[2] = gc[2];
g2c[0] = gn[4];
g2c[1] = gn[5] # psi[5] & g2c[0];
g2c[2] = gn[6] # psi[6] & g2c[1];
g2cp[1] = g2c[1];
g2cp[2] = g2c[2];
-- tot_cin_node is the total (propagated + generated) carry
-- input to each bit post
tot_cin_node[0] = gc[0] # pc[0];
tot_cin_node[1] = gc[1] # pc[1];
tot_cin_node[2] = gcp[2] # pc[2];
tot_cin_node[3] = g4 # pc[3];
tot_cin_node[4] = g2c[0] # pc[4] # p2c[0];
tot_cin_node[5] = g2cp[1] # pc[5] # p2c[1];
tot_cin_node[6] = g2cp[2] # pc[6] # p2c[2];
-- compute result (sum) bits. Note that (!ps[I] & !gs[I])
-- is the same as (data[I] $ datab[I]). However, using ps[I]
-- and gs[I] (or equivalently, pp[I] and gn[I]) results
-- in more common factors that can be crammed in shared
-- expanders and thus reduce cell count.
result_node[0] = (pp[0] # gn[0]) !$ cin_node;
FOR I in 1 TO 7 GENERATE
IF I == 3 GENERATE
result_node[I] = g3 $ tot_cin_node[I-1];
ELSE GENERATE
result_node[I] = (psi[I] & !gs[I]) $ tot_cin_node[I-1];
END GENERATE;
END GENERATE;
-- cout
cout_node = gn[7] $ (psi[7] & !gs[7] & tot_cin_node[6]);
-- all outputs are SOFT-buffered.
result[] = result_node[];
cout = cout_node;
ELSE GENERATE
----------------------------------
-- MAX cases with WIDTH != 8 --
----------------------------------
IF FULL_BLOCKS > 0 GENERATE
FOR I IN 0 TO FULL_BLOCKS-1 GENERATE
adder[I].dataa[] = dataa[(I+1)*8-1..I*8];
adder[I].datab[] = datab[(I+1)*8-1..I*8];
result[(I+1)*8-1..I*8] = adder[I].result[];
END GENERATE;
END GENERATE;
IF REM_BLOCKS == 1 GENERATE
adder[TOT_BLOCKS-1].dataa[REM_WIDTH-1..0] = dataa[WIDTH-1..(TOT_BLOCKS-1)*8];
adder[TOT_BLOCKS-1].datab[REM_WIDTH-1..0] = datab[WIDTH-1..(TOT_BLOCKS-1)*8];
result[WIDTH-1..(TOT_BLOCKS-1)*8] = adder[TOT_BLOCKS-1].result[REM_WIDTH-1..0];
END GENERATE;
adder[0].cin = cin_node;
IF TOT_BLOCKS > 1 GENERATE
FOR I IN 1 TO TOT_BLOCKS-1 GENERATE
adder[I].cin = adder[I-1].cout;
END GENERATE;
END GENERATE;
IF REM_BLOCKS == 1 GENERATE
cout = adder[TOT_BLOCKS-1].result[REM_WIDTH];
ELSE GENERATE
cout = adder[TOT_BLOCKS-1].cout;
END GENERATE;
END GENERATE;
END GENERATE;
END GENERATE;
END;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -