diff --git a/bs/Bus.bs b/bs/Bus.bs index 0faaa54..7df4955 100644 --- a/bs/Bus.bs +++ b/bs/Bus.bs @@ -1,7 +1,65 @@ -package Bus(a) where +package Bus(mkBus) where import Types import BusTypes +import TagEngine +import Vector +import Util +import Arbiter -a :: UInt 5 -a = 3 +clientRequest :: Arbiter.ArbiterClient_IFC -> Action +clientRequest ifc = ifc.request + +busRequestToAddr :: BusRequest -> Addr +busRequestToAddr req = case req of + BusReadRequest (ReadRequest addr _) -> addr + WriteReadRequest (WriteRequest addr _) -> addr + +mkBus :: (Addr -> Integer) + -> Vector numClients (BusClient inFlightTransactions) + -> Vector numServers (BusServer inFlightTransactions numClients) + -> Module Empty +mkBus addrToServerTranslation clientVec serverVec = do + tagEngineByClientVec :: Vector numClients (TagEngine inFlightTransactions) + tagEngineByClientVec <- replicateM mkTagEngine + + arbiterByServerVec :: Vector numServers (Arbiter_IFC numClients) + arbiterByServerVec <- replicateM (mkArbiter False) + + -- statically determinate criteria + let + clientIdx :: Integer = 0 + selectedClient ::(BusClient inFlightTransactions) + selectedClient = (select clientVec clientIdx) + selectedTagEngine = (select tagEngineByClientVec clientIdx) + + addRules |> + rules + "placeholder rule": when True ==> do + let selectedServerArbiter = (select arbiterByServerVec 0) + mapM_ clientRequest selectedServerArbiter.clients + + "connect request client 0": + when True + ==> do + tag <- selectedTagEngine.requestTag + + busRequest :: BusRequest + busRequest <- selectedClient.dequeueRequest tag + + -- let + -- addr = busRequestToAddr busRequest + -- targetServerIdx = addrToServerTranslation addr + -- targetServer = (select serverVec targetServerIdx) + -- targetServerArbiter = (select arbiterByServerVec targetServerIdx) + + -- targetServerArbiter.request + + -- if targetServerArbiter.grant + -- then targetServer.enqueueRequest (tag, busRequest) + -- else action {} + + -- targetServer + action {} + + return $ interface Empty { } diff --git a/bs/BusTypes.bs b/bs/BusTypes.bs index 99d0fb4..818fd3d 100644 --- a/bs/BusTypes.bs +++ b/bs/BusTypes.bs @@ -1,12 +1,16 @@ package BusTypes( - BusVal(..), - BusError(..), - TransactionSize(..), - ReadRequest(..), - WriteRequest(..) + MkClientTagType, + BusClient(..), BusServer(..), + BusRequest(..), BusResponse(..), + ReadRequest(..), ReadResponse(..), WriteRequest(..), WriteResponse(..), + BusVal(..), BusError(..), TransactionSize(..) ) where import Types +import Vector +import TagEngine + +type MkClientTagType a = (UInt (TLog a)) data BusError = UnMapped @@ -48,21 +52,47 @@ data BusResponse | BusWriteResponse WriteResponse deriving (Bits, Eq, FShow) -interface BusMaster = - -- The Bus arbiter will call the Bus Master's request method - -- if and only if it's the Bus Master's turn to make a request, and the Bus Master - -- has a request to make. - -- It is up to the BusMaster to guard it's request method such that calling - -- it's request method is only valid when the BusMaster has a request to make. - -- 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. - response :: BusResponse -> Action +-- # BusClient.dequeueRequest +-- * The Bus arbiter will call the Bus Client's request method if it is +-- the Bus Client's turn to make a request, or if another client forfits +-- its turn. +-- * The BusClient must guard its request method such that calling its +-- request method is only valid when the BusClient has a request to make. +-- * This has implications about for the implementor of BusClient, +-- namely, that it should hold its request until it's request method +-- gets called. The arbiter tags the request so that the client can +-- later correctly correlate the response. +-- * Although the tag is technically passed in as an argument from the +-- arbiter to the client's request method, given that methods are +-- atomic in Bluespec, this is effectively equivalent to tagging the +-- transaction from the client's perspective. Thus, the client must +-- take care to appropiately store the tag. +-- # BusClient.enqueueResponse +-- * From the client's perspective, the response should not be called +-- by the arbiter until the client is ready to accept the response. +-- In other words, the response method should be guarded by the client. +interface (BusClient :: # -> *) inFlightTransactions = + dequeueRequest :: MkTagType inFlightTransactions + -> ActionValue BusRequest + enqueueResponse :: (BusResponse, MkTagType inFlightTransactions) + -> Action -type Token = UInt 5 - -a :: UInt 5 -a = 3 +-- # BusServer.dequeueResponse +-- * If the arbiter is able to successfully call `dequeueResponse`, then +-- the BusServer's internal logic must update such that it understands +-- the response has been handed off. +-- # BusServer.peekClientTagDestination +-- * The arbiter looks at (peekClientTagDestination :: MkClientTagType) to +-- determine whether or not it is currently safe whether to dequeue the +-- response as well as where to route the response should it dequeue the +-- response. +-- * `peekClientTagDestination` should be guarded on whether or not there is +-- a valid response available. +interface (BusServer :: # -> # -> *) inFlightTransactions numClients = + enqueueRequest :: (MkTagType inFlightTransactions, BusRequest) + -> Action + dequeueResponse :: ActionValue ( + MkClientTagType numClients, + BusResponse, transactionTagType + ) + peekClientTagDestination :: MkClientTagType numClients diff --git a/bs/TagEngine.bs b/bs/TagEngine.bs index 921e58e..2ddb304 100644 --- a/bs/TagEngine.bs +++ b/bs/TagEngine.bs @@ -1,4 +1,5 @@ package TagEngine( + MkTagType, TagEngine(..), Util.BasicResult(..), mkTagEngine) where @@ -9,11 +10,11 @@ import FIFO import FIFOF import SpecialFIFOs -#define UIntLog2N(n) (UInt (TLog n)) +type MkTagType numTags = (UInt (TLog numTags)) interface (TagEngine :: # -> *) numTags = - requestTag :: ActionValue UIntLog2N(numTags) - retireTag :: UIntLog2N(numTags) -> Action + requestTag :: ActionValue (MkTagType numTags) + retireTag :: (MkTagType numTags) -> Action -- 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 @@ -44,7 +45,7 @@ mkTagEngine = do debugOnce <- mkReg True -- Rules - addRules $ + addRules |> rules "debug_initial_state": when debugOnce ==> do $display "tagUsage: " (fshow (readVReg tagUsage)) @@ -77,9 +78,9 @@ mkTagEngine = do (Nothing, Nothing) -> action {} -- Interface - return $ + return |> interface TagEngine - requestTag :: ActionValue UIntLog2N(numTags) + requestTag :: ActionValue (MkTagType numTags) requestTag = do case initialTagDistributor of Just 0 -> do @@ -100,7 +101,7 @@ mkTagEngine = do -- 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 :: (MkTagType numTags) -> Action retireTag tag = do let