seemingly reasonable stopping point
This commit is contained in:
parent
6247ae3b70
commit
d436209f54
115
bs/TagEngine.bs
115
bs/TagEngine.bs
|
@ -5,40 +5,41 @@ package TagEngine(
|
||||||
|
|
||||||
import Vector
|
import Vector
|
||||||
import Util
|
import Util
|
||||||
|
import FIFO
|
||||||
|
import FIFOF
|
||||||
|
|
||||||
#define UIntLog2N(n) (UInt (TLog n))
|
#define UIntLog2N(n) (UInt (TLog n))
|
||||||
|
|
||||||
interface (TagEngine :: # -> *) numTags =
|
interface (TagEngine :: # -> *) numTags =
|
||||||
requestTag :: ActionValue (Maybe UIntLog2N(numTags))
|
requestTag :: ActionValue UIntLog2N(numTags)
|
||||||
retireTag :: UIntLog2N(numTags) -> ActionValue BasicResult
|
retireTag :: UIntLog2N(numTags) -> Action
|
||||||
|
|
||||||
-- The tag engine returns a tag that is unique for the duration of
|
-- 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
|
-- the lifetime of the tag. Useful when you need to tag transactions
|
||||||
-- on a bus for example.
|
-- on a bus for example.
|
||||||
-- This implementation is stack based.
|
-- This implementation is FIFO based.
|
||||||
mkTagEngine :: Module (TagEngine numTags)
|
mkTagEngine :: Module (TagEngine numTags)
|
||||||
mkTagEngine =
|
mkTagEngine =
|
||||||
do
|
do
|
||||||
|
|
||||||
let reifiedNumTags = fromInteger |> valueOf numTags
|
let reifiedNumTags = fromInteger |> valueOf numTags
|
||||||
|
|
||||||
freeStackVec :: Vector numTags (Reg UIntLog2N(numTags))
|
|
||||||
freeStackVec <- mapM (\i -> mkReg |> fromInteger i) genVector
|
|
||||||
|
|
||||||
inUseVec :: Vector numTags (Reg Bool)
|
inUseVec :: Vector numTags (Reg Bool)
|
||||||
inUseVec <- replicateM |> mkReg False
|
inUseVec <- replicateM |> mkReg False
|
||||||
|
|
||||||
stackPtr :: (Reg (Maybe(UIntLog2N(numTags))))
|
-- Since Bluespec doesn't allow us to initialize FIFOs with values at
|
||||||
stackPtr <- mkReg |> Just |> reifiedNumTags - 1
|
-- reset, we can pretend as if the buffer within our tagFIFO 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 (numTags - 1) for the first n tag requests made
|
||||||
|
-- to TagEngine where `n := numTags`.
|
||||||
|
resetTagCounter :: (Reg (Maybe UIntLog2N(numTags)))
|
||||||
|
resetTagCounter <- mkReg |> Just |> reifiedNumTags - 1
|
||||||
|
|
||||||
methodRequestTagCalled :: PulseWire
|
retireQueue :: FIFOF UIntLog2N(numTags)
|
||||||
methodRequestTagCalled <- mkPulseWire
|
retireQueue <- mkSizedFIFOF reifiedNumTags
|
||||||
|
|
||||||
methodRetireTagCalledValid :: RWire UIntLog2N(numTags)
|
freeQueue :: FIFOF UIntLog2N(numTags)
|
||||||
methodRetireTagCalledValid <- mkUnsafeRWire
|
freeQueue <- mkSizedFIFOF reifiedNumTags
|
||||||
|
|
||||||
-- computedTagResult :: BypassWire (Maybe UIntLog2N(numTags))
|
|
||||||
-- methodRetireTagCalledValid <- mkBypassWire
|
|
||||||
|
|
||||||
debugOnce <- mkReg True
|
debugOnce <- mkReg True
|
||||||
|
|
||||||
|
@ -46,71 +47,46 @@ mkTagEngine =
|
||||||
rules
|
rules
|
||||||
"display": when (debugOnce == True) ==>
|
"display": when (debugOnce == True) ==>
|
||||||
do
|
do
|
||||||
$display "freeStackVec : " (fshow |> readVReg freeStackVec)
|
|
||||||
$display "inUseVec : " (fshow |> readVReg inUseVec)
|
$display "inUseVec : " (fshow |> readVReg inUseVec)
|
||||||
$display "stackPtr : " (fshow stackPtr)
|
|
||||||
debugOnce := False
|
debugOnce := False
|
||||||
|
|
||||||
"update stack pointer": when True ==>
|
-- The "retire_tags" rule can't fire when the `requestTag` method is called.
|
||||||
|
-- In practice, this is Ok since:
|
||||||
|
-- 1. the `requestTag` method should take priority over the "retire_tags" rule
|
||||||
|
-- 2. the `requestTag` method handles the case where there are some tags to retire.
|
||||||
|
"retire_tags": when True ==>
|
||||||
do
|
do
|
||||||
stackPtr :=
|
let tag = retireQueue.first
|
||||||
case (methodRequestTagCalled, methodRetireTagCalledValid.wget) of
|
$display "firing retire_tags" (fshow tag)
|
||||||
(True, Just _) -> stackPtr
|
retireQueue.deq
|
||||||
(True, Nothing) ->
|
freeQueue.enq tag
|
||||||
case stackPtr of
|
|
||||||
Just 0 -> Nothing
|
|
||||||
Just sampledStackPtr -> Just |> sampledStackPtr - 1
|
|
||||||
Nothing -> Nothing
|
|
||||||
(False, Just _) ->
|
|
||||||
case stackPtr of
|
|
||||||
Just sampledStackPtr -> Just |> sampledStackPtr + 1
|
|
||||||
Nothing -> Nothing
|
|
||||||
(False, Nothing) -> stackPtr
|
|
||||||
|
|
||||||
"update free stack": when True ==>
|
|
||||||
do
|
|
||||||
case (methodRequestTagCalled, methodRetireTagCalledValid.wget) of
|
|
||||||
(True, Just _) -> do action {}
|
|
||||||
(True, Nothing) -> do action {}
|
|
||||||
(False, Just tag) -> do
|
|
||||||
case stackPtr of
|
|
||||||
Just sampledStackPtr -> do
|
|
||||||
(select freeStackVec (sampledStackPtr + 1)) := tag
|
|
||||||
Nothing -> do
|
|
||||||
(select freeStackVec 0) := tag
|
|
||||||
(False, Nothing) -> do action {}
|
|
||||||
|
|
||||||
"update in use": when True ==>
|
|
||||||
do
|
|
||||||
case (methodRequestTagCalled, methodRetireTagCalledValid.wget) of
|
|
||||||
(True, Just _) -> do action {}
|
|
||||||
(True, Nothing) ->
|
|
||||||
case stackPtr of
|
|
||||||
Just sampledStackPtr -> do
|
|
||||||
(select inUseVec sampledStackPtr) := True
|
|
||||||
Nothing -> do action {}
|
|
||||||
(False, Just tag) -> do
|
|
||||||
(select inUseVec tag) := False
|
(select inUseVec tag) := False
|
||||||
(False, Nothing) -> do action {}
|
|
||||||
|
|
||||||
return $
|
return $
|
||||||
interface TagEngine
|
interface TagEngine
|
||||||
|
|
||||||
requestTag :: ActionValue (Maybe UIntLog2N(numTags))
|
requestTag :: ActionValue UIntLog2N(numTags)
|
||||||
requestTag =
|
requestTag =
|
||||||
do
|
do
|
||||||
methodRequestTagCalled.send
|
case resetTagCounter of
|
||||||
case methodRetireTagCalledValid.wget of
|
Just 0 -> do
|
||||||
|
resetTagCounter := Nothing
|
||||||
|
(select inUseVec 0) := True
|
||||||
|
return 0
|
||||||
Just tag -> do
|
Just tag -> do
|
||||||
return |> Just tag
|
resetTagCounter := Just |> tag - 1
|
||||||
|
(select inUseVec tag) := True
|
||||||
|
return tag
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
return |>
|
let tag = freeQueue.first
|
||||||
case stackPtr of
|
freeQueue.deq
|
||||||
Just sampledStackPtr ->
|
return tag
|
||||||
Just |> readReg (select freeStackVec sampledStackPtr)
|
|
||||||
Nothing -> Nothing
|
|
||||||
|
|
||||||
retireTag :: UIntLog2N(numTags) -> ActionValue BasicResult
|
-- `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 tag =
|
retireTag tag =
|
||||||
do
|
do
|
||||||
let
|
let
|
||||||
|
@ -118,7 +94,6 @@ mkTagEngine =
|
||||||
tagInUse = readReg (select inUseVec tag)
|
tagInUse = readReg (select inUseVec tag)
|
||||||
if (tagValid && tagInUse)
|
if (tagValid && tagInUse)
|
||||||
then do
|
then do
|
||||||
methodRetireTagCalledValid.wset tag
|
retireQueue.enq tag
|
||||||
return Success
|
|
||||||
else do
|
else do
|
||||||
return Failure
|
action {}
|
||||||
|
|
|
@ -44,6 +44,7 @@ mkTagEngineTester = do
|
||||||
|> do requestTagAction
|
|> do requestTagAction
|
||||||
|> do retireTagAction 1
|
|> do retireTagAction 1
|
||||||
|> do requestTagAction
|
|> do requestTagAction
|
||||||
|
|> do $finish
|
||||||
|
|
||||||
addRules $
|
addRules $
|
||||||
rules
|
rules
|
||||||
|
|
Loading…
Reference in a new issue