Skip to content

Commit

Permalink
Add blockRam1 (#645)
Browse files Browse the repository at this point in the history
Fixes #638
  • Loading branch information
martijnbastiaan authored Jun 25, 2019
1 parent 1d4ef5e commit 39d9dbf
Show file tree
Hide file tree
Showing 10 changed files with 429 additions and 8 deletions.
48 changes: 48 additions & 0 deletions clash-lib/prims/systemverilog/Clash_Explicit_BlockRam.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,52 @@ assign ~RESULT = ~FROMBV[~SYM[2]][~TYP[9]];
// blockRam end"
}
}
, { "BlackBox" :
{ "name" : "Clash.Explicit.BlockRam.blockRam1#"
, "kind" : "Declaration"
, "type" :
"blockRam1#
:: ( KnownDomain dom conf ARG[0]
, HasCallStack -- ARG[1]
, Undefined a ) -- ARG[2]
=> Clock dom -- clk, ARG[3]
-> Enable dom -- en, ARG[4]
-> SNat n -- len, ARG[5]
-> a -- init, ARG[6]
-> Signal dom Int -- rd, ARG[7]
-> Signal dom Bool -- wren, ARG[8]
-> Signal dom Int -- wr, ARG[9]
-> Signal dom a -- din, ARG[10]
-> Signal dom a"
, "template" :
"// blockRam1 begin,
~TYPO ~GENSYM[~RESULT_RAM][1] [0:~LIT[5]-1];
logic [~SIZE[~TYP[10]]-1:0] ~GENSYM[~RESULT_q][2];
initial begin
~SYM[1] = '{default: ~CONST[6]};
end~IF ~ISALWAYSENABLED[4] ~THEN
always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~GENSYM[~COMPNAME_blockRam][3]~IF ~VIVADO ~THEN
if (~ARG[4]) begin
if (~ARG[8]) begin
~SYM[1][~ARG[9]] <= ~TOBV[~ARG[10]][~TYP[10]];
end
~SYM[2] <= ~SYM[1][~ARG[7]];
end~ELSE
if (~ARG[8] & ~ARG[4]) begin
~SYM[1][~ARG[9]] <= ~TOBV[~ARG[10]][~TYP[10]];
end
if (~ARG[4]) begin
~SYM[2] <= ~SYM[1][~ARG[7]];
end~FI
end~ELSE
always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~SYM[3]
if (~ARG[8]) begin
~SYM[1][~ARG[9]] <= ~TOBV[~ARG[10]][~TYP[10]];
end
~SYM[2] <= ~SYM[1][~ARG[7]];
end~FI
assign ~RESULT = ~FROMBV[~SYM[2]][~TYP[10]];
// blockRam1 end"
}
}
]
52 changes: 52 additions & 0 deletions clash-lib/prims/verilog/Clash_Explicit_BlockRam.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,56 @@ end~FI
// blockRam end"
}
}
, { "BlackBox" :
{ "name" : "Clash.Explicit.BlockRam.blockRam1#"
, "kind" : "Declaration"
, "type" :
"blockRam1#
:: ( KnownDomain dom conf ARG[0]
, HasCallStack -- ARG[1]
, Undefined a ) -- ARG[2]
=> Clock dom -- clk, ARG[3]
-> Enable dom -- en, ARG[4]
-> SNat n -- len, ARG[5]
-> a -- init, ARG[6]
-> Signal dom Int -- rd, ARG[7]
-> Signal dom Bool -- wren, ARG[8]
-> Signal dom Int -- wr, ARG[9]
-> Signal dom a -- din, ARG[10]
-> Signal dom a"
, "outputReg" : true
, "template" :
"// blockRam1 begin
reg ~TYPO ~GENSYM[~RESULT_RAM][0] [0:~LIT[5]-1];
integer ~GENSYM[i][1];
initial begin
for (~SYM[1]=0;~SYM[1]<~LIT[5];~SYM[1]=~SYM[1]+1) begin
~SYM[0][~SYM[1]] = ~CONST[6];
end
end

~IF ~ISALWAYSENABLED[4] ~THEN
always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~GENSYM[~RESULT_blockRam][5]~IF ~VIVADO ~THEN
if (~ARG[4]) begin
if (~ARG[8]) begin
~SYM[0][~ARG[9]] <= ~ARG[10];
end
~RESULT <= ~SYM[0][~ARG[7]];
end~ELSE
if (~ARG[8] & ~ARG[4]) begin
~SYM[0][~ARG[9]] <= ~ARG[10];
end
if (~ARG[4]) begin
~RESULT <= ~SYM[0][~ARG[7]];
end~FI
end~ELSE
always @(~IF~ACTIVEEDGE[Rising][0]~THENposedge~ELSEnegedge~FI ~ARG[3]) begin : ~SYM[5]
if (~ARG[8]) begin
~SYM[0][~ARG[9]] <= ~ARG[10];
end
~RESULT <= ~SYM[0][~ARG[7]];
end~FI
// blockRam1 end"
}
}
]
67 changes: 67 additions & 0 deletions clash-lib/prims/vhdl/Clash_Explicit_BlockRam.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,71 @@ end block;
--end blockRam"
}
}
, { "BlackBox" :
{ "name" : "Clash.Explicit.BlockRam.blockRam1#"
, "kind" : "Declaration"
, "type" :
"blockRam1#
:: ( KnownDomain dom conf ARG[0]
, HasCallStack -- ARG[1]
, Undefined a ) -- ARG[2]
=> Clock dom -- clk, ARG[3]
-> Enable dom -- en, ARG[4]
-> SNat n -- len, ARG[5]
-> a -- init, ARG[6]
-> Signal dom Int -- rd, ARG[7]
-> Signal dom Bool -- wren, ARG[8]
-> Signal dom Int -- wr, ARG[9]
-> Signal dom a -- din, ARG[10]
-> Signal dom a"
, "template" :
"-- blockRam1 begin
~GENSYM[~RESULT_blockRam][1] : block
type ~GENSYM[ram_t][8] is array (0 to integer'(~LIT[5])-1) of ~TYP[6];
signal ~GENSYM[~RESULT_RAM][2] : ~SYM[8] := (others => ~CONST[6]);
signal ~GENSYM[rd][4] : integer range 0 to ~LIT[5] - 1;
signal ~GENSYM[wr][5] : integer range 0 to ~LIT[5] - 1;
begin
~SYM[4] <= to_integer(~ARG[7])
-- pragma translate_off
mod ~LIT[5]
-- pragma translate_on
;

~SYM[5] <= to_integer(~ARG[9])
-- pragma translate_off
mod ~LIT[5]
-- pragma translate_on
;
~IF ~VIVADO ~THEN
~SYM[6] : process(~ARG[3])
begin
if ~IF~ACTIVEEDGE[Rising][0]~THENrising_edge~ELSEfalling_edge~FI(~ARG[3]) then
if ~ARG[8] ~IF ~ISALWAYSENABLED[4] ~THEN and ~ARG[4] ~ELSE ~FI then
~SYM[2](~SYM[5]) <= ~TOBV[~ARG[10]][~TYP[10]];
end if;
~RESULT <= fromSLV(~SYM[2](~SYM[4]))
-- pragma translate_off
after 1 ps
-- pragma translate_on
;
end if;
end process; ~ELSE
~SYM[6] : process(~ARG[3])
begin
if ~IF~ACTIVEEDGE[Rising][0]~THENrising_edge~ELSEfalling_edge~FI(~ARG[3]) then
if ~ARG[8] ~IF ~ISALWAYSENABLED[4] ~THEN and ~ARG[4] ~ELSE ~FI then
~SYM[2](~SYM[5]) <= ~ARG[10];
end if;
~RESULT <= ~SYM[2](~SYM[4])
-- pragma translate_off
after 1 ps
-- pragma translate_on
;
end if;
end process; ~FI
end block;
--end blockRam1"
}
}
]
116 changes: 109 additions & 7 deletions clash-prelude/src/Clash/Explicit/BlockRam.hs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ This concludes the short introduction to using 'blockRam'.
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
Expand All @@ -393,25 +394,32 @@ module Clash.Explicit.BlockRam
( -- * BlockRAM synchronized to the system clock
blockRam
, blockRamPow2
, blockRam1
, ResetStrategy(..)
-- * Read/Write conflict resolution
, readNew
-- * Internal
, blockRam#
)
where

import Control.Applicative (liftA2)
import Data.Maybe (isJust)
import qualified Data.Vector as V
import GHC.Stack (HasCallStack, withFrozenCallStack)
import GHC.TypeLits (KnownNat, type (^))
import Prelude hiding (length)
import GHC.TypeLits (KnownNat, type (^), type (<=))
import Prelude hiding (length, replicate)

import Clash.Annotations.Primitive (hasBlackBox)
import Clash.Class.Num (SaturationMode(SatBound), satAdd)
import Clash.Explicit.Signal (KnownDomain, Enable, register, fromEnable)
import Clash.Signal.Internal
(Clock(..), Reset, Signal (..), (.&&.), mux)
(Clock(..), Reset, Signal (..), invertReset, (.&&.), mux)
import Clash.Promoted.Nat (SNat(..))
import Clash.Signal.Bundle (unbundle)
import Clash.Sized.Unsigned (Unsigned)
import Clash.Sized.Vector (Vec, toList)
import Clash.Sized.Index (Index)
import Clash.Sized.Vector (Vec, replicate, toList)
import Clash.XException
(maybeIsX, seqX, Undefined, deepErrorX, defaultSeqX, errorX)

Expand Down Expand Up @@ -681,6 +689,10 @@ prog2 = -- 0 := 4
-}

fromJustX :: HasCallStack => Maybe a -> a
fromJustX Nothing = errorX "fromJustX: Nothing"
fromJustX (Just x) = x

-- | Create a blockRAM with space for @n@ elements
--
-- * __NB__: Read value is delayed by 1 cycle
Expand Down Expand Up @@ -725,9 +737,6 @@ blockRam = \clk gen content rd wrM ->
(wr,din) = unbundle (fromJustX <$> wrM)
in withFrozenCallStack
(blockRam# clk gen content (fromEnum <$> rd) en (fromEnum <$> wr) din)
where
fromJustX Nothing = errorX "fromJustX"
fromJustX (Just x) = x
{-# INLINE blockRam #-}

-- | Create a blockRAM with space for 2^@n@ elements
Expand Down Expand Up @@ -776,6 +785,98 @@ blockRamPow2 = \clk en cnt rd wrM -> withFrozenCallStack
(blockRam clk en cnt rd wrM)
{-# INLINE blockRamPow2 #-}

data ResetStrategy (r :: Bool) where
ClearOnReset :: ResetStrategy 'True
NoClearOnReset :: ResetStrategy 'False

-- | Version of blockram that is initialized with the same value on all
-- memory positions.
blockRam1
:: forall n dom a r addr conf
. ( KnownDomain dom conf
, HasCallStack
, Undefined a
, Enum addr
, 1 <= n )
=> Clock dom
-- ^ 'Clock' to synchronize to
-> Reset dom
-- ^ 'Reset' line to listen to. Needs to be held at least /n/ cycles in order
-- for the BRAM to be reset to its initial state.
-> Enable dom
-- ^ Global enable
-> ResetStrategy r
-- ^ Whether to clear BRAM on asserted reset ('ClearOnReset') or
-- not ('NoClearOnReset'). Reset needs to be asserted at least /n/ cycles to
-- clear the BRAM.
-> SNat n
-- ^ Number of elements in BRAM
-> a
-- ^ Initial content of the BRAM (replicated /n/ times)
-> Signal dom addr
-- ^ Read address @r@
-> Signal dom (Maybe (addr, a))
-- ^ (write address @w@, value to write)
-> Signal dom a
-- ^ Value of the @blockRAM@ at address @r@ from the previous clock cycle
blockRam1 clk rst0 en rstStrategy n@SNat a rd0 mw0 =
case rstStrategy of
ClearOnReset ->
-- Use reset infrastructure
blockRam1# clk en n a rd1 we1 wa1 w1
NoClearOnReset ->
-- Ignore reset infrastructure, pass values unchanged
blockRam1# clk en n a
(fromEnum <$> rd0)
we0
(fromEnum <$> wa0)
w0
where
rstBool = register clk rst0 en True (pure False)
rstInv = invertReset rst0

waCounter :: Signal dom (Index n)
waCounter = register clk rstInv en 0 (liftA2 (satAdd SatBound) (pure 1) waCounter)

wa0 = fst . fromJustX <$> mw0
w0 = snd . fromJustX <$> mw0
we0 = isJust <$> mw0

rd1 = mux rstBool 0 (fromEnum <$> rd0)
we1 = mux rstBool (pure True) we0
wa1 = mux rstBool (fromInteger . toInteger <$> waCounter) (fromEnum <$> wa0)
w1 = mux rstBool (pure a) w0

-- | blockRAM1 primitive
blockRam1#
:: forall n dom a conf
. ( KnownDomain dom conf
, HasCallStack
, Undefined a )
=> Clock dom
-- ^ 'Clock' to synchronize to
-> Enable dom
-- ^ Global Enable
-> SNat n
-- ^ Number of elements in BRAM
-> a
-- ^ Initial content of the BRAM (replicated /n/ times)
-> Signal dom Int
-- ^ Read address @r@
-> Signal dom Bool
-- ^ Write enable
-> Signal dom Int
-- ^ Write address @w@
-> Signal dom a
-- ^ Value to write (at address @w@)
-> Signal dom a
-- ^ Value of the @blockRAM@ at address @r@ from the previous clock cycle
blockRam1# clk en n a =
-- TODO: Generalize to single BRAM primitive taking an initialization function
blockRam# clk en (replicate n a)
{-# NOINLINE blockRam1# #-}
{-# ANN blockRam1# hasBlackBox #-}

-- | blockRAM primitive
blockRam#
:: ( KnownDomain dom conf
Expand Down Expand Up @@ -821,6 +922,7 @@ blockRam# (Clock _) gen content rd wen =
Nothing -> V.map (const (seq waddr d)) ram
Just wa -> ram V.// [(wa,d)]
_ -> ram
{-# ANN blockRam# hasBlackBox #-}
{-# NOINLINE blockRam# #-}

-- | Create read-after-write blockRAM from a read-before-write one
Expand Down
2 changes: 2 additions & 0 deletions clash-prelude/src/Clash/Explicit/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ module Clash.Explicit.Prelude
-- * BlockRAM primitives
, blockRam
, blockRamPow2
, blockRam1
, ResetStrategy(..)
-- ** BlockRAM primitives initialized with a data file
, blockRamFile
, blockRamFilePow2
Expand Down
3 changes: 3 additions & 0 deletions clash-prelude/src/Clash/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ module Clash.Prelude
-- * BlockRAM primitives
, blockRam
, blockRamPow2
, blockRam1
, E.ResetStrategy(..)
-- ** BlockRAM primitives initialized with a data file
, blockRamFile
, blockRamFilePow2
Expand Down Expand Up @@ -167,6 +169,7 @@ import Clash.Hidden
import Clash.NamedTypes
import Clash.Prelude.BitIndex
import Clash.Prelude.BitReduction
import Clash.Prelude.BlockRam
import Clash.Prelude.BlockRam.File
import Clash.Prelude.DataFlow
import Clash.Prelude.ROM.File
Expand Down
Loading

0 comments on commit 39d9dbf

Please sign in to comment.