packages feed

ForSyDe-3.0: examples/CarrySelectAdder.hs

{-# LANGUAGE TemplateHaskell #-}

-- This module models a 16-bit carry select adder


module CarrySelectAdder where

import ForSyDe     -- Definition of Bit data type
import Data.Bits   -- Operations for Bit data type
import Data.Param.FSVec
import Data.TypeLevel.Num.Reps
import Data.TypeLevel.Num.Aliases

-- First we create a four bit carry select adder.
-- It uses eight full adders and five 2/1 muxes.

------ Full Adder

fullAddFun :: ProcFun (Bit -> Bit -> Bit -> (Bit, Bit))
fullAddFun = $(newProcFun [d|fullAddFun :: Bit -> Bit -> Bit -> (Bit, Bit)
                             -- I would like to use 'where'-clauses. Is this possible?
                             -- fullAddFun a b c_in = (c_out, sum)
                             --  where c_out = (a .&. b) .|. (a .&. c_in) .|. (b .&. c_in)
                             --        sum = (a `xor` b) `xor` c_in  |])
                             fullAddFun a b c_in = ((a .&. b) .|. (a .&. c_in) .|. (b .&. c_in),
						    (a `xor` b) `xor` c_in) |])

--fullAddProc :: Signal Bit -> Signal Bit -> Signal Bit -> Signal (Bit, Bit)
--fullAddProc = zipWith3SY "fulladd" fullAddFun
fullAddProc :: Signal Bit -> Signal Bit -> Signal Bit -> (Signal Bit, Signal Bit)
fullAddProc a b c_in = (unzipSY "unzipSY") $ (zipWith3SY "fulladd" fullAddFun a b c_in)

fullAddSys :: SysDef (Signal Bit -> Signal Bit -> Signal Bit -> (Signal Bit, Signal Bit))
fullAddSys = $(newSysDefTHName 'fullAddProc ["a", "b", "c_in"] ["cout", "sum"])

simFullAdd :: [Bit] -> [Bit] -> [Bit] -> ([Bit], [Bit])
simFullAdd = simulate fullAddSys

--vhdlFullAdd = writeVHDL fullAddSys

a_in = [L,L,L,L,H,H,H,H]
b_in = [L,H,L,H,L,H,L,H]
c_in = [L,L,H,H,L,L,H,H]


------ 2/1 Multiplexer

--mux21Fun :: ProcFun (Bit -> Bit -> Bit -> Bit)
--mux21Fun = $(newProcFun [d|mux21Fun :: Bit -> Bit -> Bit -> Bit
--                           mux21Fun sel d1 d0 = if (sel == L) then
--                                                   d0
--                                                else
--                                                   d1 |])

mux21Proc :: Signal Bit -> Signal Bit -> Signal Bit -> Signal Bit
mux21Proc = zipWith3SY "mux21" mux21Fun

mux21Sys :: SysDef (Signal Bit -> Signal Bit -> Signal Bit -> Signal Bit)
mux21Sys = $(newSysDefTHName 'mux21Proc ["sel", "d1", "d0"] ["out"])

simMux21 :: [Bit] -> [Bit] -> [Bit] -> [Bit]
simMux21 = simulate mux21Sys

vhdlMux21 = writeVHDL mux21Sys

------ 4-bit Adder Chain

fourBitAdder :: Signal Bit   -- C_IN
	     -> Signal Bit   -- A3
             -> Signal Bit   -- A2
             -> Signal Bit   -- A1
	     -> Signal Bit   -- A0
             -> Signal Bit   -- B3
	     -> Signal Bit   -- B2
	     -> Signal Bit   -- B1
	     -> Signal Bit   -- B0
	     -> (Signal Bit, -- C_OUT
	         Signal Bit, -- SUM3
	         Signal Bit, -- SUM2
	         Signal Bit, -- SUM1
	         Signal Bit) -- SUM0
fourBitAdder c_in a3 a2 a1 a0 b3 b2 b1 b0 
                = (c_out, sum3, sum2, sum1, sum0)
		  where (c_out, sum3) = (instantiate "add3" fullAddSys) a3 b3 c2
		        (c2, sum2)    = (instantiate "add2" fullAddSys) a2 b2 c1
		        (c1, sum1)    = (instantiate "add1" fullAddSys) a1 b1 c0
		        (c0, sum0)    = (instantiate "add0" fullAddSys) a0 b0 c_in

fourBitAdderSys :: SysDef (Signal Bit   -- C_IN
			-> Signal Bit   -- A3
			-> Signal Bit   -- A2
			-> Signal Bit   -- A1
			-> Signal Bit   -- A0
			-> Signal Bit   -- B3
			-> Signal Bit   -- B2
			-> Signal Bit   -- B1
			-> Signal Bit   -- B0
			-> (Signal Bit, -- C_OUT
			    Signal Bit, -- SUM3
			    Signal Bit, -- SUM2
			    Signal Bit, -- SUM1
			    Signal Bit)) -- SUM0 	
fourBitAdderSys = $(newSysDefTHName 'fourBitAdder ["C_IN", "A3", "A2", "A1", "A0",
                                             "B3", "B2", "B1", "B0"]
                                            ["C_OUT", "SUM3", "SUM2", "SUM1", "SUM0"])

simFourBitAdder = simulate fourBitAdderSys

vhdlFourBitAdder = writeVHDL fourBitAdderSys

a0 = [L,L,L,L,L,L,L,L,H,H,H,H,H,H,H,H]
a1 = [L,L,L,L,H,H,H,H,L,L,L,L,H,H,H,H]
a2 = [L,L,H,H,L,L,H,H,L,L,H,H,L,L,H,H]
a3 = [L,H,L,H,L,H,L,H,L,H,L,H,L,H,L,H]
zero = [L,L,L,L,L,L,L,L,L,L,L,L,L,L,L,L]
one = [H,H,H,H,H,H,H,H,H,H,H,H,H,H,H,H]


simAdd_0 = simFourBitAdder zero a3 a2 a1 a0 a3 a2 a1 a0 
simAdd_1 = simFourBitAdder one a3 a2 a1 a0 a3 a2 a1 a0  

----- fourBitCarrySelectAdder


fourBitCSAdder :: Signal Bit   -- C_IN
	       -> Signal Bit   -- A3
               -> Signal Bit   -- A2
               -> Signal Bit   -- A1
	       -> Signal Bit   -- A0
               -> Signal Bit   -- B3
	       -> Signal Bit   -- B2
	       -> Signal Bit   -- B1
	       -> Signal Bit   -- B0
	       -> (Signal Bit, -- C_OUT
	          Signal Bit, -- SUM3
	          Signal Bit, -- SUM2
	          Signal Bit, -- SUM1
	          Signal Bit) -- SUM0fourBitCSAdder :: 
fourBitCSAdder c_in a3 a2 a1 a0 b3 b2 b1 b0
               = (c_out, sum3, sum2, sum1, sum0)
                 where c_out = (instantiate "mux4" mux21Sys) c_in c_out_1 c_out_0
                       sum3  = (instantiate "mux3" mux21Sys) c_in sum3_1 sum3_0
                       sum2  = (instantiate "mux2" mux21Sys) c_in sum2_1 sum2_0
                       sum1  = (instantiate "mux1" mux21Sys) c_in sum1_1 sum1_0 
                       sum0  = (instantiate "mux0" mux21Sys) c_in sum0_1 sum0_0
                       (c_out_1, sum3_1, sum2_1, sum1_1, sum0_1) 
                             = (instantiate "Adder_1" fourBitAdderSys) 
                                one a3 a2 a1 a0 b3 b2 b1 b0
                       (c_out_0, sum3_0, sum2_0, sum1_0, sum0_0) 
                             = (instantiate "Adder_1" fourBitAdderSys) 
                                zero a3 a2 a1 a0 b3 b2 b1 b0
                       one = instantiate "One" oneSys
                       zero = instantiate "Zero" zeroSys

fourBitCSAdderSys = $(newSysDefTHName 'fourBitCSAdder ["C_IN", "A3", "A2", "A1", "A0",
                                             "B3", "B2", "B1", "B0"]
                                            ["C_OUT", "SUM3", "SUM2", "SUM1", "SUM0"])


simFourBitCSAdder = simulate fourBitCSAdderSys

vhdlFourBitCSAdder = writeVHDL fourBitCSAdderSys
                           
simCSAdd_0 = simFourBitAdder zero a3 a2 a1 a0 a3 a2 a1 a0 
simCSAdd_1 = simFourBitAdder one a3 a2 a1 a0 a3 a2 a1 a0  

----- Convert Output to FSVec

convertToFSVec5 :: a -> a -> a -> a -> a -> FSVec D5 a
convertToFSVec5 x4 x3 x2 x1 x0 = x4 +> x3 +> x2 +> x1 +> (singleton x0)

convOutput :: ProcFun (Bit -> Bit -> Bit -> Bit -> Bit -> FSVec D5 Bit)
convOutput = $(newProcFun [d|convOutput :: Bit -> Bit -> Bit -> Bit -> Bit -> FSVec D5 Bit
                             convOutput x4 x3 x2 x1 x0 
                                    = convertToFSVec5 x4 x3 x2 x1 x0 |])

convOutputProc :: Signal Bit -> Signal Bit -> Signal Bit -> Signal Bit -> Signal Bit -> Signal (FSVec D5 Bit)
convOutputProc = zipWith5SY "toVector5" convOutput

convOutputSys :: SysDef (Signal Bit -> Signal Bit -> Signal Bit -> Signal Bit -> Signal Bit -> Signal (FSVec D5 Bit))
convOutputSys =  $(newSysDefTHName 'convOutputProc ["x4", "x3", "x2", "x1", "x0"] ["vec5"])

fourBitCSAdder' :: Signal Bit   -- C_IN
	        -> Signal Bit   -- A3
                -> Signal Bit   -- A2
                -> Signal Bit   -- A1
	        -> Signal Bit   -- A0
                -> Signal Bit   -- B3
	        -> Signal Bit   -- B2
	        -> Signal Bit   -- B1
	        -> Signal Bit   -- B0
	        -> Signal (FSVec D5 Bit) -- <C_OUT, SUM3, SUM2, SUM1, SUM0>
fourBitCSAdder' c_in a3 a2 a1 a0 b3 b2 b1 b0 = out5
               where
                  out5 = (instantiate "toVector5" convOutputSys) c_out sum3 sum2 sum1 sum0
                  (c_out, sum3, sum2, sum1, sum0) = (instantiate "Adder" fourBitCSAdderSys) c_in a3 a2 a1 a0 b3 b2 b1 b0  

fourBitCSAdderSys2 :: SysDef (Signal Bit   -- C_IN
	        -> Signal Bit   -- A3
                -> Signal Bit   -- A2
                -> Signal Bit   -- A1
	        -> Signal Bit   -- A0
                -> Signal Bit   -- B3
	        -> Signal Bit   -- B2
	        -> Signal Bit   -- B1
	        -> Signal Bit   -- B0
	        -> Signal (FSVec D5 Bit))
fourBitCSAdderSys2 = $(newSysDefTHName 'fourBitCSAdder' ["C_IN", "A3", "A2", "A1", "A0",
                                             "B3", "B2", "B1", "B0"]
                                            ["vect5"])

simFourBitCSAdder2 = simulate fourBitCSAdderSys2

vhdlFourBitCSAdder2 = writeVHDL fourBitCSAdderSys2

simCSAdd_0' = simFourBitCSAdder2 zero a3 a2 a1 a0 a3 a2 a1 a0 
simCSAdd_1' = simFourBitCSAdder2 one a3 a2 a1 a0 a3 a2 a1 a0  


----- Four Bit Adder 
--
-- The four bit adder is modelled as a set of equations. 
-- It uses fixed-size vectors for the 4-bit input and output values.

adder4BitFun :: ProcFun (Bit -> FSVec D4 Bit -> FSVec D4 Bit -> (Bit, FSVec D4 Bit))
adder4BitFun = $(newProcFun [d|adder4BitFun :: Bit -> FSVec D4 Bit -> FSVec D4 Bit -> (Bit, FSVec D4 Bit)
                               adder4BitFun cin a b = (cout, sum) where
                                  cout = (a!d3 .&. b!d3) .|. (a!d3 .&. c2) .|. (b!d3 .&. c2)
                                  c2 = (a!d2 .&. b!d2) .|. (a!d2 .&. c1) .|. (b!d2 .&. c1)
                                  c1 = (a!d1 .&. b!d1) .|. (a!d1 .&. c0) .|. (b!d1 .&. c0)
                                  c0 = (a!d0 .&. b!d0) .|. (a!d0 .&. cin) .|. (b!d0 .&. cin)
                                  s3 = (a!d3 `xor` b!d3) `xor` c2
                                  s2 = (a!d2 `xor` b!d2) `xor` c1
                                  s1 = (a!d1 `xor` b!d1) `xor` c0
                                  s0 = (a!d0 `xor` b!d0) `xor` cin
                                  sum = s0 +> s1 +> s2 +> s3 +> empty |])

adder4BitProc :: Signal Bit -> Signal (FSVec D4 Bit) -> Signal (FSVec D4 Bit) -> (Signal Bit, Signal (FSVec D4 Bit))
adder4BitProc cin a b = (unzipSY "unzip") $ (zipWith3SY "4BitAdder" adder4BitFun cin a b)

adder4BitSys :: SysDef (Signal Bit -> Signal (FSVec D4 Bit) -> Signal (FSVec D4 Bit) -> (Signal Bit, Signal (FSVec D4 Bit)))
adder4BitSys = $(newSysDefTHName 'adder4BitProc ["cin", "a", "b"] ["cout", "sum"])

simAdder4Bit = simulate adder4BitSys

vhdlAdder4Bit = writeVHDL adder4BitSys

----- 4-Bit 2/1 Multiplexer
--
-- The multiplexer uses fixed size vectors for input and output values.

mux21Fun :: ProcFun (Bit -> a -> a -> a)
mux21Fun = $(newProcFun [d|mux21Fun :: Bit -> a -> a -> a
                           mux21Fun sel d1 d0 = if (sel == L) then
                                                   d0
                                                else
                                                   d1 |])

mux21_4BitProc :: Signal Bit -> Signal (FSVec D4 Bit) -> Signal (FSVec D4 Bit) -> Signal (FSVec D4 Bit)
mux21_4BitProc = zipWith3SY "mux21" mux21Fun

mux21_4BitSys :: SysDef (Signal Bit -> Signal ( FSVec D4 Bit) -> Signal (FSVec D4 Bit) -> Signal (FSVec D4 Bit))
mux21_4BitSys = $(newSysDefTHName 'mux21_4BitProc ["sel", "d1", "d0"] ["out"])

simMux21_4Bit :: [Bit] -> [FSVec D4 Bit] -> [FSVec D4 Bit] -> [FSVec D4 Bit]
simMux21_4Bit = simulate mux21_4BitSys

vhdlMux21_4Bit = writeVHDL mux21_4BitSys


----- 4-Bit Carry Select Adder

-- The carry select adder has two input that are connected to 'H' or 'L' respectively

-- Constant input 'H' modeled with constSY
oneProc :: Signal Bit
oneProc = constSY "high" H

oneSys :: SysDef (Signal Bit)
oneSys = $(newSysDefTHName 'oneProc [] ["one"])

-- Constant input 'L' modeled with constSY
zeroProc :: Signal Bit
zeroProc = constSY "low" L
 
zeroSys :: SysDef (Signal Bit)
zeroSys = $(newSysDefTHName 'zeroProc [] ["zero"])

-- The 4-Bit carry select adder is implemented as a composition of components
csAdder4BitProc :: Signal Bit -> Signal (FSVec D4 Bit) -> Signal (FSVec D4 Bit) -> (Signal Bit, Signal (FSVec D4 Bit))
csAdder4BitProc cin a b = (cout, sum) where
                          cout = (instantiate "mux" mux21Sys) cin cout_1 cout_0
                          sum = (instantiate "mux4Bit" mux21_4BitSys) cin sum_1 sum_0
                          (cout_1, sum_1) = (instantiate "adder1" adder4BitSys) one a b
                          (cout_0, sum_0) = (instantiate "adder0" adder4BitSys) zero a b                  
                          one = instantiate "One" oneSys
                          zero = instantiate "Zero" zeroSys
                           
csAdder4BitSys :: SysDef (Signal Bit -> Signal (FSVec D4 Bit) -> Signal (FSVec D4 Bit) -> (Signal Bit, Signal (FSVec D4 Bit)))
csAdder4BitSys = $(newSysDefTHName 'csAdder4BitProc ["cin", "a", "b"] ["cout", "sum"])

simCSAdder4Bit = simulate csAdder4BitSys

vhdlCSAdder4Bit = writeVHDL csAdder4BitSys

----- 16 Bit Adder

csAdder16BitProc :: Signal (FSVec D16 Bit) -> Signal (FSVec D16 Bit) -> (Signal Bit, Signal (FSVec D16 Bit))
csAdder16BitProc a b = (cout, sum) where
                       sum = zipWith4SY "concat4" concat4Fun sum3_0 sum7_4 sum11_8 sum15_12
                       (cout, sum15_12) = (instantiate "csadder3" csAdder4BitSys) c11 a15_12 b15_12
                       (c11, sum11_8) = (instantiate "csadder2" csAdder4BitSys) c7 a11_8 b11_8
                       (c7, sum7_4) = (instantiate "csadder3" csAdder4BitSys) c3 a7_4 b7_4
                       (c3, sum3_0) = (instantiate "csadder3" csAdder4BitSys) zero a3_0 b3_0
                       a15_12 = mapSY "a15_12" select15_12Fun a
                       a11_8  = mapSY "a11_8"  select11_8Fun a
                       a7_4   = mapSY "a7_4"   select7_4Fun a
                       a3_0   = mapSY "a3_0"   select3_0Fun a
                       b15_12 = mapSY "b15_12" select15_12Fun b
                       b11_8  = mapSY "b11_8"  select11_8Fun b
                       b7_4   = mapSY "b7_4"   select7_4Fun b
                       b3_0   = mapSY "b3 _0"  select3_0Fun b
                       zero = instantiate "Zero" zeroSys         


csAdder16BitSys = $(newSysDefTHName 'csAdder16BitProc ["a", "b"] ["cout", "sum"])

simCSAdder16Bit = simulate csAdder16BitSys

vhdlCSAdder16Bit = writeVHDL csAdder16BitSys

-- Helper functions

select15_12Fun :: ProcFun (FSVec D16 Bit -> FSVec D4 Bit)
select15_12Fun = $(newProcFun [d|select15_12 :: FSVec D16 Bit -> FSVec D4 Bit
                                 select15_12 v = select d12 d1 d4 v |])

select11_8Fun :: ProcFun (FSVec D16 Bit -> FSVec D4 Bit)
select11_8Fun = $(newProcFun [d|select11_8 :: FSVec D16 Bit -> FSVec D4 Bit
                                select11_8 v = select d8 d1 d4 v |])

select7_4Fun :: ProcFun (FSVec D16 Bit -> FSVec D4 Bit)
select7_4Fun = $(newProcFun [d|select7_4 :: FSVec D16 Bit -> FSVec D4 Bit
                               select7_4 v = select d4 d1 d4 v |])

select3_0Fun :: ProcFun (FSVec D16 Bit -> FSVec D4 Bit)
select3_0Fun = $(newProcFun [d|select3_0 :: FSVec D16 Bit -> FSVec D4 Bit
                               select3_0 v = select d0 d1 d4 v |])

concat4Fun :: ProcFun (FSVec D4 Bit -> FSVec D4 Bit -> FSVec D4 Bit -> FSVec D4 Bit -> FSVec D16 Bit)
concat4Fun = $(newProcFun [d|concat4Fun :: FSVec D4 Bit -> FSVec D4 Bit -> FSVec D4 Bit -> FSVec D4 Bit -> FSVec D16 Bit
                             concat4Fun v1 v2 v3 v4 = v1 Data.Param.FSVec.++ 
                                                      v2 Data.Param.FSVec.++ 
                                                      v3 Data.Param.FSVec.++ 
                                                      v4 |])

-- 16 Bit Test Values

v_0000 = reallyUnsafeVector [L,L,L,L, L,L,L,L, L,L,L,L, L,L,L,L]
v_8000 = reallyUnsafeVector [L,L,L,L, L,L,L,L, L,L,L,L, L,L,L,H] -- H is MSB
v_0001 = reallyUnsafeVector [H,L,L,L, L,L,L,L, L,L,L,L, L,L,L,L]
v_ffff = reallyUnsafeVector [H,H,H,H, H,H,H,H, H,H,H,H, H,H,H,H]

a16 = v_0000 : v_0000 : v_0001 : v_8000 : v_ffff : v_ffff : []
b16 = v_0000 : v_0001 : v_0001 : v_8000 : v_ffff : v_0001 : []

test16Bit = simCSAdder16Bit a16 b16

-- 4 Bit Test Values

v_0 = reallyUnsafeVector [L,L,L,L]
v_1 = reallyUnsafeVector [H,L,L,L]
v_8 = reallyUnsafeVector [L,L,L,H]
v_f = reallyUnsafeVector [H,H,H,H]

a4 = v_0 : v_0 : v_1 : v_8 : v_f : v_1 : []
b4 = v_0 : v_1 : v_1 : v_8 : v_f : v_f : []

c_low = [L,L,L,L,L,L]
c_high = [H,H,H,H,H,H] 

test4Bit = simCSAdder4Bit c_low a4 b4 

-- Test FSVector

fv = 0 +> 1 +> 2 +> 3 +> empty -- LSB fv!d0 = 0, MSB fv!d3 = 3