diff --git a/Makefile b/Makefile index 7579e84..52863b1 100644 --- a/Makefile +++ b/Makefile @@ -61,7 +61,7 @@ $(BDPI_OBJ): $(BDPI_SRC) BSC_LINK_FLAGS += -keep-fires -BSC_PATHS = -p bs/:bs/Tests/:bsv/:+ +BSC_PATHS = -p bs/:bsv/:+ .PHONY: help help: diff --git a/bs/BusTypes.bs b/bs/BusTypes.bs index 99d0fb4..d633ee6 100644 --- a/bs/BusTypes.bs +++ b/bs/BusTypes.bs @@ -57,9 +57,9 @@ interface BusMaster = -- This has implications about for the implementor of BusMaster, namely, that it -- should hold its request until it's request method gets called. request :: BusRequest - -- From the masters's perspective, the response should not be called by the - -- arbiter until the master is ready to accept the response. In other words, - -- response should be guarded by the client. + -- From the masters's perspective, the response should not be called until + -- the client is ready to accept the response. In other words, response + -- should be guarded by the client. response :: BusResponse -> Action type Token = UInt 5 diff --git a/bs/TagEngine.bs b/bs/TagEngine.bs index 921e58e..df60839 100644 --- a/bs/TagEngine.bs +++ b/bs/TagEngine.bs @@ -5,109 +5,77 @@ package TagEngine( import Vector import Util -import FIFO -import FIFOF -import SpecialFIFOs #define UIntLog2N(n) (UInt (TLog n)) interface (TagEngine :: # -> *) numTags = requestTag :: ActionValue UIntLog2N(numTags) - retireTag :: UIntLog2N(numTags) -> Action + retireTag :: UIntLog2N(numTags) -> ActionValue BasicResult -- The tag engine returns a tag that is unique for the duration of -- the lifetime of the tag. Useful when you need to tag transactions -- on a bus for example. --- This implementation is FIFO based. +-- This implementation is stack based. mkTagEngine :: Module (TagEngine numTags) -mkTagEngine = do - -- Constants - let maxTagCount = fromInteger (valueOf numTags) +mkTagEngine = + do + let reifiedNumTags = fromInteger |> valueOf numTags - tagUsage :: Vector numTags (Reg Bool) <- replicateM (mkReg False) -- Tracks which tags are in use + freeStackVec :: Vector numTags (Reg UIntLog2N(numTags)) + freeStackVec <- mapM (\i -> mkReg |> fromInteger i) genVector - -- Since Bluespec doesn't allow us to initialize FIFOs with values at - -- reset, we can pretend as if the buffer within our freeTagQueue is populated - -- with sequentially incrementing values(starting from 0) on reset - -- by having our tag engine effectively return the value of a decrementing - -- counter initialized to (maxTagCount - 1) for the first n tag requests made - -- to TagEngine where `n := maxTagCount`. - initialTagDistributor <- mkReg (Just (maxTagCount - 1)) -- Distributes initial tags - retireQueue <- mkBypassFIFO -- Queue for tags being retired - freeTagQueue <- mkSizedFIFOF maxTagCount -- Queue of available tags + inUseVec :: Vector numTags (Reg Bool) + inUseVec <- replicateM |> mkReg False - -- Signals - retireSignal <- mkRWire -- Signals a tag retirement - requestSignal <- mkRWire -- Signals a tag request + stackPtr :: (Reg (Maybe(UIntLog2N(numTags)))) + stackPtr <- mkReg |> Just |> reifiedNumTags - 1 - -- Debug - debugOnce <- mkReg True + debugOnce <- mkReg True - -- Rules - addRules $ - rules - "debug_initial_state": when debugOnce ==> do - $display "tagUsage: " (fshow (readVReg tagUsage)) - debugOnce := False + addRules $ + rules + "display": when (debugOnce == True) ==> + do + $display "freeStackVec : " (fshow |> readVReg freeStackVec) + $display "inUseVec : " (fshow |> readVReg inUseVec) + $display "stackPtr : " (fshow stackPtr) + debugOnce := False - "retire_tag": when True ==> do - let tag = retireQueue.first - $display "Retiring tag: " (fshow tag) - retireQueue.deq - freeTagQueue.enq tag - retireSignal.wset tag + counter <- mkReg(0 :: UIntLog2N(numTags)) + return $ + interface TagEngine - -- Combined update rules (simplified below) - "update_usage": when True ==> do - let mRetireTag = retireSignal.wget - mRequestTag = requestSignal.wget - case (mRetireTag, mRequestTag) of - (Just retireTag, Just requestTag) -> do - let usage = readVReg tagUsage - usage' = update usage requestTag True - usage'' = update usage' retireTag False - writeVReg tagUsage usage'' - $display $time " Updated usage (request + retire): " (fshow |> readVReg tagUsage) - (Just retireTag, Nothing) -> do - (select tagUsage retireTag) := False - $display $time " Updated usage (retire): " (fshow (readVReg tagUsage)) - (Nothing, Just requestTag) -> do - (select tagUsage requestTag) := True - $display $time " Updated usage (request): " (fshow (readVReg tagUsage)) - (Nothing, Nothing) -> action {} - - -- Interface - return $ - interface TagEngine requestTag :: ActionValue UIntLog2N(numTags) - requestTag = do - case initialTagDistributor of - Just 0 -> do - initialTagDistributor := Nothing - requestSignal.wset 0 - return 0 - Just tag -> do - initialTagDistributor := Just (tag - 1) - requestSignal.wset tag - return tag - Nothing -> do - let tag = freeTagQueue.first - freeTagQueue.deq - requestSignal.wset tag - return tag + requestTag = + do + stackPtr := + if sampledStackPtr == 0 + then Nothing + else Just |> sampledStackPtr - 1 + (select inUseVec sampledStackPtr) := True + return |> readReg (select freeStackVec sampledStackPtr) + when + Just sampledStackPtr <- stackPtr - -- `retireTag` isn't guarded on tag validity(this would break Bluespec's safety model) - -- so it is advisable that the caller of `retireTag` only attempt to retire valid tags. - -- Internally, the tagEngine will keep a correct and consistent state since TagEngine - -- validates tags before attempting to retire them. - retireTag :: UIntLog2N(numTags) -> Action + -- retireTag isn't guarded so its up to external module to only attempt to + -- retire valid tags... At any rate, we can notify the requestor of failures + -- to retire tags - although the requestor can merely ignore this + -- notification. + retireTag :: UIntLog2N(numTags) -> ActionValue BasicResult retireTag tag = do let - tagValid = tag < maxTagCount - tagInUse = readReg (select tagUsage tag) + tagValid = tag < reifiedNumTags + tagInUse = readReg (select inUseVec tag) + nextStackPtrUint = + case stackPtr of + Nothing -> 0 + Just n -> n + 1 if (tagValid && tagInUse) then do - retireQueue.enq tag + (select inUseVec tag) := False + (select freeStackVec nextStackPtrUint) := tag + stackPtr := Just nextStackPtrUint + return Success else do - action {} + return Failure diff --git a/bs/Tests/TagEngineTester.bs b/bs/Tests/TagEngineTester.bs deleted file mode 100644 index 4fc700e..0000000 --- a/bs/Tests/TagEngineTester.bs +++ /dev/null @@ -1,64 +0,0 @@ -package TagEngineTester(mkTagEngineTester) where - -import TagEngine -import ActionSeq - -mkTagEngineTester :: Module Empty -mkTagEngineTester = do - tagEngine :: TagEngine 5 <- mkTagEngine - runOnce :: Reg Bool <- mkReg False - - s :: ActionSeq - s <- - let - requestTagAction :: Action - requestTagAction = - do - tag <- tagEngine.requestTag - $display $time " got tag : " (fshow tag) - - retireTagAction :: UInt 3 -> Action - retireTagAction tag = - do - res <- tagEngine.retireTag tag - $display $time " retiring tag : " (fshow tag) " " (fshow res) - action {} - - in - actionSeq $ - do requestTagAction - |> do requestTagAction - |> do requestTagAction - |> do requestTagAction - |> do requestTagAction - |> do retireTagAction 2 - -- |> do $display "BEGIN TRY SIMULTANEOUS RETIRE and REQUEST" - |> do - retireTagAction 4 - requestTagAction - -- |> do $display "END TRY SIMULTANEOUS RETIRE and REQUEST" - -- |> do $display "BEGIN TRY SIMULTANEOUS RETIRE and REQUEST" - |> do - retireTagAction 4 - requestTagAction - -- |> do $display "END TRY SIMULTANEOUS RETIRE and REQUEST" - |> do $finish - -- |> do retireTagAction 4 - -- |> do retireTagAction 4 - -- |> do retireTagAction 0 - -- |> do requestTagAction - -- |> do requestTagAction - -- |> do retireTagAction 1 - -- |> do requestTagAction - -- |> do $finish - - addRules $ - rules - -- "counter": when True ==> - -- do - -- count := count + 1 - -- $display "count : " (fshow count) - "testIncrement": when (runOnce == False) ==> - do - s.start - runOnce := True diff --git a/bs/Top.bs b/bs/Top.bs index f4f1cda..59344b2 100644 --- a/bs/Top.bs +++ b/bs/Top.bs @@ -10,8 +10,6 @@ import TagEngine import List import ActionSeq -import TagEngineTester - type FCLK = 25000000 type BAUD = 9600 @@ -21,6 +19,44 @@ interface ITop = { ;ftdi_txd :: Bit 1 -> Action {-# always_ready , always_enabled #-} }; +interface BusClient = + request :: Bit 1 + response :: Bit 1 -> Action + +mkBusClient :: Module BusClient +mkBusClient = module + reqReg :: Reg (Bit 1) <- mkReg 0 + return $ + interface BusClient + request = reqReg + response resp = do + reqReg := 0 -- Reset request after receiving response + +interface Bus = + request :: Bit 1 -> Action + response :: Bit 1 + +mkBus :: Module Bus +mkBus = module + respReg :: Reg (Bit 1) <- mkReg 0 + return $ + interface Bus + request req = do + respReg := req -- Simple pass-through for this example + response = respReg + +-- -- Function to connect Bus to BusClient +connectBusToClient :: Bus -> BusClient -> Rules +connectBusToClient bus client = + rules + "busConnection": when True ==> do + bus.request client.request + client.response bus.response + +-- need to implement mkBus + +-- need function that can connect Bus to BusClient + mkTop :: Module ITop mkTop = do fileHandle :: Handle <- openFile "compile.log" WriteMode @@ -28,9 +64,17 @@ mkTop = do serializer :: ISerializer FCLK BAUD <- mkSerialize fileHandle core :: Core FCLK <- mkCore + bus :: Bus <- mkBus + busClient :: BusClient <- mkBusClient + let a :: List Integer = 1 :> 2 :> Nil + b = length a + persistLed :: Reg (Bit 8) <- mkReg 0 messageM $ "Hallo!!" + (realToString 5) + -- need to instantiate a Bus and BusClient + addRules $ connectBusToClient bus busClient + addRules $ rules -- need new rule that always connects Bus to BusClient @@ -56,12 +100,58 @@ mkTop = do mkSim :: Module Empty mkSim = do - _ :: Empty <- mkTagEngineTester + let cfg :: BRAM_Configure = defaultValue + + tagEngine :: TagEngine 5 <- mkTagEngine + count :: Reg (UInt 4) <- mkReg 0; initCFunctions :: Reg Bool <- mkReg False; core :: Core FCLK <- mkCore; + s :: ActionSeq + s <- actionSeq + $ do + $display "got tag : " tagEngine.requestTag + |> do + $display "got tag : " tagEngine.requestTag + |> do + $display "got tag : " tagEngine.requestTag + |> do + res <- tagEngine.retireTag 3 + $display "retiring tag : 3 " (fshow res) + action {} + |> do + $display "got tag : " tagEngine.requestTag + |> do + $display "got tag : " tagEngine.requestTag + |> do + res <- tagEngine.retireTag 4 + $display "retiring tag : 4 " (fshow res) + action {} + |> do + res <- tagEngine.retireTag 4 + $display "retiring tag : 4 " (fshow res) + action {} + |> do + res <- tagEngine.retireTag 0 + $display "retiring tag : 0 " (fshow res) + action {} + |> do + $display "got tag : " tagEngine.requestTag + |> do + $display "got tag : " tagEngine.requestTag + |> do + res <- tagEngine.retireTag 1 + $display "retiring tag : 1 " (fshow res) + action {} + |> do + $display "got tag : " tagEngine.requestTag + addRules $ rules + "testIncrement": when (count < 10) ==> + do + count := count + 1 + s.start "initCFunctionsOnce": when not initCFunctions ==> do initTerminal