Skip to content

Commit

Permalink
Clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
hydrolarus committed Jul 29, 2024
1 parent efed306 commit 33cd0ed
Show file tree
Hide file tree
Showing 36 changed files with 2,541 additions and 701 deletions.
7 changes: 7 additions & 0 deletions .github/synthesis/debug.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"top": "vexRiscvTest",
"stage": "test",
"targets": "Specific [-1]"
}
]
2 changes: 2 additions & 0 deletions bittide-instances/bittide-instances.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ library
exposed-modules:
Bittide.Instances.Domains
Bittide.Instances.Hacks
Bittide.Instances.MemoryMaps
Bittide.Instances.MemoryMapLogic

-- Hardware-in-the-loop tests
Bittide.Instances.Hitl.BoardTest
Expand Down
217 changes: 120 additions & 97 deletions bittide-instances/src/Bittide/Instances/Hitl/VexRiscv.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -fplugin=Protocols.Plugin #-}
{-# LANGUAGE NumericUnderscores #-}

-- {-# OPTIONS -fplugin-opt=Protocols.Plugin:debug #-}

Expand All @@ -27,22 +28,135 @@ import Bittide.Instances.Domains (Basic125, Ext125)
import Bittide.ProcessingElement
import Bittide.SharedTypes
import Bittide.Wishbone
import Protocols.MemoryMap (withPrefix, MemoryMapped, MemoryMap(..), BackwardAnnotated, annotationSnd')

import qualified Data.Map.Strict as Map

import Protocols.MemoryMap (withPrefix, MemoryMapped, MemoryMap(..), BackwardAnnotated, DeviceDefinition (..), Name (..), MemoryMapTree (DeviceInstance), Register (..), Access (..))
import GHC.Stack (HasCallStack, callStack, getCallStack)
import Protocols.MemoryMap.FieldType (ToFieldType (toFieldType))
import BitPackC (BitPackC)
-- import Protocols.MemoryMap (BackwardAnnotated)

data TestStatus = Running | Success | Fail
deriving (Enum, Eq, Generic, NFDataX, BitPack)
deriving (Enum, Eq, Generic, NFDataX, BitPack, ToFieldType, BitPackC)

type TestDone = Bool
type TestSuccess = Bool
type UartRx = Bit
type UartTx = Bit


-- ╭────────┬───────┬───────┬────────────────────────────────────╮
-- │ bin │ hex │ bus │ description │
-- ├────────┼───────┼───────┼────────────────────────────────────┤
-- │ 0b000. │ 0x0 │ │ │
-- │ 0b001. │ 0x2 │ │ │
-- │ 0b010. │ 0x4 │ 1 │ Data memory │
-- │ 0b011. │ 0x6 │ │ │
-- │ 0b100. │ 0x8 │ 0 │ Instruction memory │
-- │ 0b101. │ 0xA │ 2 │ Time │
-- │ 0b110. │ 0xC │ 3 │ UART │
-- │ 0b111. │ 0xE │ 4 │ Test status register │
-- ╰────────┴───────┴───────┴────────────────────────────────────╯

-- | The internal CPU circuit used for this test.
cpuCircuit ::
forall dom .
( HiddenClockResetEnable dom
, 1 <= DomainPeriod dom
, ValidBaud dom 921600
, HasCallStack
) =>
Circuit (CSignal dom Bit, MemoryMapped (Jtag dom)) (CSignal dom TestStatus, CSignal dom Bit)
cpuCircuit = circuit $ \(uartRx, jtag) -> do
[timeBus, uartBus, statusRegisterBus] <- processingElementM
0b100 (Undefined @(Div (64 * 1024) 4))
0b010 (Undefined @(Div (64 * 1024) 4)) -< jtag
withPrefix 0b101 (timeM "Timer") -< timeBus
(uartTx, _uartStatus) <- withPrefixFst 0b110
(uartM @dom "UART" d16 d16 (SNat @921600)) -< (uartBus, uartRx)
testResult <- withPrefix 0b111 statusRegM -< statusRegisterBus
idC -< (testResult, uartTx)
where
withPrefixFst ::
BitVector n ->
Circuit (BackwardAnnotated ann a, b) c ->
Circuit (BackwardAnnotated (BitVector n, ann) a, b) c
withPrefixFst prefix (Circuit f) = Circuit $ \(fwd, bwd) ->
let (((ann, bwdA), bwdB), fwd') = f (fwd, bwd) in
((((prefix, ann), bwdA), bwdB), fwd')


-- | Memory-mapped wrapper for 'statusRegister'
statusRegM ::
forall dom addr .
(HiddenClockResetEnable dom, HasCallStack) =>
Circuit
(MemoryMapped (Wishbone dom 'Standard addr (Bytes 4)))
(CSignal dom TestStatus)
statusRegM = Circuit go
where
go (fwd, _) =
((SimOnly memMap, bwd), status')
where
Circuit f = statusRegister
(bwd, status') = f (fwd, pure ())

((_, defLoc):(_, instanceLoc):_) = getCallStack callStack
deviceDef = DeviceDefinition
{ deviceName = Name { name = "StatusReg", description = "" }
, registers = [(statusRegName, defLoc, statusRegDesc)]
, defLocation = defLoc
}
statusRegName = Name { name = "status", description = "" }
statusRegDesc = Register
{ access = WriteOnly
, address = 0
, reset = Nothing
, fieldType = toFieldType @TestStatus
, fieldSize = 1
}
deviceInstance = DeviceInstance instanceLoc Nothing "StatusReg" "StatusReg"
memMap = MemoryMap { deviceDefs = Map.singleton "StatusReg" deviceDef, tree = deviceInstance }

-- | A memory mapped register to communicate the test result to the system.
statusRegister ::
forall dom addr .
(HiddenClockResetEnable dom) =>
Circuit
(Wishbone dom 'Standard addr (Bytes 4))
(CSignal dom TestStatus)
statusRegister = Circuit $ \(fwd, _) ->
let (unbundle -> (m2s, st)) = mealy go Running fwd
in (m2s, st)
where
go st WishboneM2S{..}
-- out of cycle, no response, same state
| not (busCycle && strobe) = (st, (emptyWishboneS2M, st))
-- already done, ACK and same state
| st /= Running = (st, (emptyWishboneS2M { acknowledge = True}, st))
-- read, this is write-only, so error, same state
| not writeEnable =
( st
, ((emptyWishboneS2M @(Bytes 4))
{ err = True
, readData = errorX "status register is write-only"
}
, st))
-- write! change state, ACK
| otherwise =
let state = case writeData of
1 -> Success
_ -> Fail
in (state, (emptyWishboneS2M { acknowledge = True }, state))


vexRiscvInner ::
forall dom .
( HiddenClockResetEnable dom
, 1 <= DomainPeriod dom
, ValidBaud dom 921600
, HasCallStack
) =>
Signal dom JtagIn ->
Signal dom UartRx ->
Expand Down Expand Up @@ -71,108 +185,17 @@ vexRiscvInner jtagIn0 uartRx =
circuitFn = toSignals circ'

circ' :: Circuit (CSignal dom Bit, Jtag dom) (CSignal dom TestStatus, CSignal dom Bit)
circ' = removeAnnSnd circ
circ' = removeAnnSnd cpuCircuit

removeAnnSnd :: Circuit (a, BackwardAnnotated ann b) c -> Circuit (a, b) c
removeAnnSnd (Circuit f) = Circuit $ \(fwd, bwd) ->
let ((bwdA, (_, bwdB)), fwd') = f (fwd, bwd) in
((bwdA, bwdB), fwd')

SimOnly _memoryMap = annotationSnd' circ

-- circ :: Circuit (MemoryMapped (CSignal dom Bit, Jtag dom)) (CSignal dom TestStatus, CSignal dom Bit)
-- circ = undefined

-- circ :: Circuit (MemoryMapped (CSignal dom Bit, Jtag dom)) ()
-- circ = circuit $ \(uartRx, jtag) -> do
-- [timeBus, uartBus, statusRegisterBus] <- processingElementM
-- 0b010 (Undefined @(Div (64 * 1024) 4))
-- 0b100 (Undefined @(Div (64 * 1024) 4)) -< jtag
-- (uartTx, _uartStatus) <- withPrefix 0b110 (uartM @dom "UART" d16 d16 (SNat @921600)) -< (uartBus, uartRx)
-- withPrefix 0b101 (timeM "Timer") -< timeBus
-- testResult <- withPrefix 0b111 statusRegister -< statusRegisterBus
-- idC -< (testResult, uartTx)

circ :: Circuit (CSignal dom Bit, MemoryMapped (Jtag dom)) (CSignal dom TestStatus, CSignal dom Bit)
circ = circuit $ \(uartRx, jtag) -> do
[timeBus, uartBus, statusRegisterBus] <- processingElementM
0b010 (Undefined @(Div (64 * 1024) 4))
0b100 (Undefined @(Div (64 * 1024) 4)) -< jtag
withPrefix 0b101 (timeM "Timer") -< timeBus
(uartTx, _uartStatus) <- withPrefixFst 0b110
(uartM @dom @29 @4 "UART" d16 d16 (SNat @921600)) -< (uartBus, uartRx)
testResult <- withPrefix 0b111 statusRegM -< statusRegisterBus
idC -< (testResult, uartTx)


-- circ' = circuit $ \(uartRx, jtag) -> do
-- [timeBus, uartBus, statusRegisterBus] <- processingElement peConfig -< jtag
-- (uartTx, _uartStatus) <- uartWb @dom d16 d16 (SNat @921600) -< (uartBus, uartRx)
-- timeWb -< timeBus
-- testResult <- statusRegister -< statusRegisterBus
-- idC -< (testResult, uartTx)

withPrefixFst ::
BitVector n ->
Circuit (BackwardAnnotated ann a, b) c ->
Circuit (BackwardAnnotated (BitVector n, ann) a, b) c
withPrefixFst prefix (Circuit f) = Circuit $ \(fwd, bwd) ->
let (((ann, bwdA), bwdB), fwd') = f (fwd, bwd) in
((((prefix, ann), bwdA), bwdB), fwd')

statusRegM :: Circuit (MemoryMapped (Wishbone dom 'Standard addr (Bytes 4))) (CSignal dom TestStatus)
statusRegM = Circuit go
where
go (fwd, _) =
((SimOnly memMap, bwd), status')
where
Circuit f = statusRegister
(bwd, status') = f (fwd, pure ())
memMap = MemoryMap { deviceDefs = mempty, tree = errorX "" }

statusRegister :: Circuit (Wishbone dom 'Standard addr (Bytes 4)) (CSignal dom TestStatus)
statusRegister = Circuit $ \(fwd, _) ->
let (unbundle -> (m2s, st)) = mealy go Running fwd
in (m2s, st)
where
go st WishboneM2S{..}
-- out of cycle, no response, same state
| not (busCycle && strobe) = (st, (emptyWishboneS2M, st))
-- already done, ACK and same state
| st /= Running = (st, (emptyWishboneS2M { acknowledge = True}, st))
-- read, this is write-only, so error, same state
| not writeEnable =
( st
, ((emptyWishboneS2M @(Bytes 4))
{ err = True
, readData = errorX "status register is write-only"
}
, st))
-- write! change state, ACK
| otherwise =
let state = case writeData of
1 -> Success
_ -> Fail
in (state, (emptyWishboneS2M { acknowledge = True }, state))

-- ╭────────┬───────┬───────┬────────────────────────────────────╮
-- │ bin │ hex │ bus │ description │
-- ├────────┼───────┼───────┼────────────────────────────────────┤
-- │ 0b000. │ 0x0 │ │ │
-- │ 0b001. │ 0x2 │ │ │
-- │ 0b010. │ 0x4 │ 1 │ Data memory │
-- │ 0b011. │ 0x6 │ │ │
-- │ 0b100. │ 0x8 │ 0 │ Instruction memory │
-- │ 0b101. │ 0xA │ 2 │ Time │
-- │ 0b110. │ 0xC │ 3 │ UART │
-- │ 0b111. │ 0xE │ 4 │ Test status register │
-- ╰────────┴───────┴───────┴────────────────────────────────────╯
--
-- peConfig :: PeConfig 5
_peConfig = PeConfig
(0b100 :> 0b010 :> 0b101 :> 0b110 :> 0b111 :> Nil)
(Undefined @(Div (64 * 1024) 4)) -- 64 KiB
(Undefined @(Div (64 * 1024) 4)) -- 64 KiB




vexRiscvTest ::
"CLK_125MHZ" ::: DiffClock Ext125 ->
Expand Down
99 changes: 99 additions & 0 deletions bittide-instances/src/Bittide/Instances/MemoryMapLogic.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
-- SPDX-FileCopyrightText: 2024 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0

{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE RecordWildCards #-}

-- | Logic for extracting memory maps from circuits in this project.
-- This is a separate module from MemoryMaps because of GHC's stage restrictions
-- around TemplateHaskell.
module Bittide.Instances.MemoryMapLogic where

import Clash.Prelude

import Control.Monad (forM_)

import Protocols.MemoryMap ( annotationSnd, MemoryMap )
import Bittide.Instances.Hitl.VexRiscv (cpuCircuit)
import Protocols.MemoryMap.Check (CheckConfiguration(..), check, MemoryMapValidationErrors(..), shortLocation, prettyPrintPath)
import Project.FilePath (findParentContaining, buildDir)
import System.FilePath
import Language.Haskell.TH (runIO, reportError, Q)
import System.Directory (createDirectoryIfMissing)
import Protocols.MemoryMap.Check.Overlap (OverlapError(..))
import Protocols.MemoryMap.Check.AbsAddress (AbsAddressValidateError(..))

import qualified Data.List as L
import qualified Data.ByteString.Lazy as BS
import Protocols.MemoryMap.Json (memoryMapJson)
import Data.Aeson (encode)
import Text.Printf (printf)

data MemMapProcessing = MemMapProcessing
{ name :: String
, memMap :: MemoryMap
, checkConfig :: CheckConfiguration
, jsonOutput :: Maybe FilePath
}

defaultCheckConfig :: CheckConfiguration
defaultCheckConfig = CheckConfiguration
{ startAddr = 0x0000_0000
, endAddr = 0xFFFF_FFFF
}

unSimOnly :: SimOnly a -> a
unSimOnly (SimOnly x) = x

memMaps :: [MemMapProcessing]
memMaps =
[ MemMapProcessing
{ name = "VexRiscv"
, memMap = unSimOnly $ annotationSnd @System cpuCircuit
, checkConfig = defaultCheckConfig
, jsonOutput = Just "vexriscv.json"
}
]

processMemoryMaps :: Q ()
processMemoryMaps = do
memMapDir <- runIO $ do
root <- findParentContaining "cabal.project"
let dir = root </> buildDir </> "memory_maps"
createDirectoryIfMissing True dir
pure dir


forM_ memMaps $ \(MemMapProcessing{..}) -> do
case check checkConfig memMap of
Left MemoryMapValidationErrors{..} -> do
let absErrorMsgs = flip L.map absAddrErrors $ \AbsAddressValidateError{..} ->
let path' = prettyPrintPath path
component = case componentName of
Just name' -> name'
Nothing -> "interconnect " <> path'
in
printf "Expected component %s at %08X but found %08X (%s)" component expected got (shortLocation location)

let overlapErrorMsgs = flip L.map overlapErrors $ \case
OverlapError{..} ->
printf "Component %s (%08X + %08X) overlaps with %s at address (%08X) (%s)"
(prettyPrintPath path) startAddr componentSize
(prettyPrintPath overlapsWith) overlapsAt
(shortLocation location)
SizeExceedsError{..} ->
printf "Component %s (%08X + %08X) exceeds available size %08X (%s)"
(prettyPrintPath path) startAddr requestedSize
availableSize
(shortLocation location)
reportError (unlines $ absErrorMsgs <> overlapErrorMsgs)

Right checkedMemMap -> do
case jsonOutput of
Nothing -> pure ()
Just path -> do
let json = memoryMapJson checkedMemMap
runIO $ BS.writeFile (memMapDir </> path) (encode json)
pure ()
pure ()
15 changes: 15 additions & 0 deletions bittide-instances/src/Bittide/Instances/MemoryMaps.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- SPDX-FileCopyrightText: 2024 Google LLC
--
-- SPDX-License-Identifier: Apache-2.0

{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE RecordWildCards #-}
module Bittide.Instances.MemoryMaps where

import Clash.Prelude

import Bittide.Instances.MemoryMapLogic (processMemoryMaps)

$(do
processMemoryMaps
pure [])
Loading

0 comments on commit 33cd0ed

Please sign in to comment.