# Test bench rapidly consuming all of my memory

**URL:** <https://clash-lang.discourse.group/t/test-bench-rapidly-consuming-all-of-my-memory/95>\
**Category:** Clash Help\
**Created:** [October 15, 2025, 5:30am UTC](https://clash-lang.discourse.group/t/test-bench-rapidly-consuming-all-of-my-memory/95 "2025-10-15T05:30:11Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![bry](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/bry/32/60_2.png) [@bry](https://clash-lang.discourse.group/u/bry)\
**Post date:** [October 15, 2025, 5:30am UTC](https://clash-lang.discourse.group/t/test-bench-rapidly-consuming-all-of-my-memory/95/1 "2025-10-15T05:30:11Z")

</div>

I have a few simple modules and a test bench I’ve put together, all non-recursive:

```haskell
module CPU.Forward where

import Clash.Prelude

-- Forwards non-zero-register incoming data in place of original data when
-- register numbers match. Does not forward when incoming data is Nothing.
fwdMaybe :: (HiddenClockResetEnable dom, Eq addr, Num addr)
    => Signal dom (addr, value) -- Original source register and value
    -> Signal dom (Maybe (addr, value)) -- Incoming source register and value
    -> Signal dom (Bool, value) -- True if forward is used; resultant value
fwdMaybe original maybe_incoming = 
    let (org_addr, org_val) = unbundle original
        inc_unwrapped = sequence maybe_incoming
        in case inc_unwrapped of
            Nothing -> bundle (pure False, org_val)
            Just incoming -> let 
                    (inc_addr, inc_val) = unbundle incoming
                    use_incoming = inc_addr ./=. pure 0 .&&. inc_addr .==. org_addr
                in bundle (use_incoming, mux use_incoming inc_val org_val)

-- Forwards non-zero-register incoming data in place of original data when
-- register numbers match.
forwarder :: (HiddenClockResetEnable dom, Eq addr, Num addr)
    => Signal dom (addr, value) -- Original source register and value
    -> Signal dom (addr, value) -- Incoming source register and value
    -> Signal dom (Bool, value) -- True if forward is used; resultant value
forwarder org inc = fwdMaybe org (Just <$> inc)

```

```haskell
module CPU.Regfile where

import qualified Prelude as P
import Clash.Prelude

import CPU.Forward

withZeroReg :: (Enum addr, HiddenClockResetEnable dom, NFDataX addr, Num addr, Eq addr, NFDataX a, Num a)
    => (SNat n -> Signal dom addr -> Signal dom (Maybe (addr, a)) -> Signal dom a)
    -> (SNat n -> Signal dom addr -> Signal dom (Maybe (addr, a)) -> Signal dom a)
withZeroReg backingMemory n addr write = mux (addr .==. pure 0)
    (pure 0)
    (backingMemory n addr write)

withForwarding :: (Enum addr, HiddenClockResetEnable dom, NFDataX addr, Num addr, Eq addr, NFDataX a, Num a)
    => (SNat n -> Signal dom addr -> Signal dom (Maybe (addr, a)) -> Signal dom a)
    -> (SNat n -> Signal dom addr -> Signal dom (Maybe (addr, a)) -> Signal dom a)
withForwarding backingMemory n addr write =
    let backed_value = backingMemory n addr write
        (_, result) = unbundle $ fwdMaybe (bundle (addr, backed_value)) write
    in result

asRegFile :: (Enum addr, HiddenClockResetEnable dom, NFDataX addr, NFDataX a)
    => (SNat n -> Signal dom addr -> Signal dom (Maybe (addr, a)) -> Signal dom a)
    -> SNat n -- number of registers to create
    -> Signal dom (Maybe (addr, a)) -- incoming write - Just (addr, data) if writing, Nothing otherwise
    -> [Signal dom addr] -- List of addresses to read
    -> [Signal dom a] -- List of values read
asRegFile backingMemory n write = P.map (\addr -> backingMemory n addr write)

molluscRegFile :: (Enum addr, HiddenClockResetEnable dom, NFDataX addr, Num addr, Eq addr, NFDataX a, Num a)
    => Signal dom (Maybe (addr, a))
    -> [Signal dom addr]
    -> [Signal dom a]
molluscRegFile = asRegFile (withForwarding (withZeroReg asyncRam)) (SNat @16)

```

```haskell
module Tests.CPU.Regfile where

import qualified Prelude as P
import Clash.Prelude

import Test.Tasty
import Test.Tasty.HUnit

import CPU.Regfile

regfileTests :: TestTree
regfileTests = testGroup "Tests" [
        testCase "writeRead" $ let
                out = sampleN @System 3 (
                        P.head $ molluscRegFile (pure $ Just (3 :: Unsigned 4, 12345 :: Unsigned 32)) [3]
                    )
            in out P.!! 2 @?= 12345,
        testCase "writeReadZero" $ let
                out = sampleN @System 3 (
                        P.head $ molluscRegFile (pure $ Just (0 :: Unsigned 4, 12345 :: Unsigned 32)) [0]
                    )
            in out P.!! 2 @?= 0
    ]

main :: IO ()
main = defaultMain regfileTests

```

This compiles fine, but when running the test bench, my computer rapidly runs out of memory until my OS violently kills the process. Is there something obviously wrong I’m doing here? I don’t believe there should be any recursion in any of my code so I’m unclear why this is consuming infinite memory.

This code works with the `withForwarding` wrapper removed, so I suspect the issue is there - I will make more of an effort to isolate it later but I figured I’d put up a post before I went to bed in case someone can spot the issue offhand.

---

<div class="post-metadata">

**Author:** ![bry](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/bry/32/60_2.png) [@bry](https://clash-lang.discourse.group/u/bry)\
**Post date:** [October 16, 2025, 5:18pm UTC](https://clash-lang.discourse.group/t/test-bench-rapidly-consuming-all-of-my-memory/95/2 "2025-10-16T17:18:39Z")

</div>

Update - with a bit more tinkering I was able to rewrite fwdMaybe as this:

```haskell
fwdMaybe :: (HiddenClockResetEnable dom, Eq addr, Num addr, NFDataX value)
    => Signal dom (addr, value) -- Original source register and value
    -> Signal dom (Maybe (addr, value)) -- Incoming source register and value
    -> Signal dom (Bool, value) -- True if forward is used; resultant value
fwdMaybe original maybe_incoming = let
        (org_addr, org_val) = unbundle original
        (inc_addr, inc_val) = unbundle $ fromMaybe
                <$> bundle (pure 0, deepErrorX "Forwarded from nonexistent value")
                <*> maybe_incoming
        use_incoming = inc_addr ./=. pure 0 .&&. inc_addr .==. org_addr
    in bundle (use_incoming, mux use_incoming inc_val org_val)

```

This doesn’t give the issue described above while still giving me the behavior I want. This leads me to believe that `sequence` is the problem area. Is this a known issue?

---

<div class="post-metadata">

**Author:** ![DigitalBrains](https://yyz2.discourse-cdn.com/free1/user_avatar/clash-lang.discourse.group/digitalbrains/32/28_2.png) [@DigitalBrains](https://clash-lang.discourse.group/u/DigitalBrains)\
**Post date:** [October 17, 2025, 11:14am UTC](https://clash-lang.discourse.group/t/test-bench-rapidly-consuming-all-of-my-memory/95/3 "2025-10-17T11:14:09Z")

</div>

Ah! I hadn’t looked closely before, but with that hint I get it!

So what this does:

```haskell
maybe_incoming :: Signal dom (Maybe (addr, value))
inc_unwrapped = sequence maybe_incoming

```

is that it will search all samples in the signal for a `Nothing`, and if there is one, return `Nothing`. Otherwise it will collect all the `Just` samples and return them wrapped in a `Maybe`.

However, `Signal` is an infinite stream. So you’re asking GHC to determine if there is a `Nothing` in an infinite stream. So it will run the circuit until it encounters a `Nothing`. If all the values are `Just`, GHC will run forever; or until it runs out of memory, if memory use increases with each simulation step.
