Skip to content

Commit 2f2d3f8

Browse files
committed
copilot-bluespec: Update Copilot.Compile.Bluespec.Compile to reflect new input/output order. Refs #677.
The current Bluespec backend leads to Verilog code that requires manual manipulations in order to work correctly. Specifically, Copilot externs, which are inputs to the Copilot monitoring system, are treated as _outputs_ in Verilog, and Copilot triggers, which can be considered outputs of the monitoring system, are treated as _inputs_. This order of inputs and outputs is the opposite what we would like users to work with, and of what other backends generate (e.g., C99). A prior commit has updated the internals of `copilot-bluespec` to invert the order in which Verilog inputs and outputs are declared. This commit adapts the top-level code in `Copilot.Compile.Bluespec.Compile` accordingly. In particular, the `compileWith` function now generates a `<Prefix>.bs` file that defines two module interfaces: one interface that contains the core methods that will comprise the generated Verilog code, and another interface that helps automate the process of defining a `Module Empty` value that is more suitable for software simulation purposes. Previously, `compileWith` generated a separate `<Prefix>Ifc.bs` file that contained nothing but the module interface in isolation so that it could be used separately from the interface's `Module` definition. This distinction no longer makes as much sense, as in the new design, as (1) there are now multiple interfaces, and (2) it is unlikely that the interfaces are not particularly useful without having the `Module` definitions to accompany them. As such, this commit now omits generating a `<Prefix>Ifc.bs` file, instead opting to generate the interfaces as part of `<Prefix>.bs`.
1 parent da44685 commit 2f2d3f8

File tree

2 files changed

+193
-101
lines changed

2 files changed

+193
-101
lines changed

copilot-bluespec/src/Copilot/Compile/Bluespec/Compile.hs

Lines changed: 188 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,11 @@ compileWith bsSettings prefix spec
5757

5858
| otherwise
5959
= do let typesBsFile = render $ pPrint $ compileTypesBS bsSettings prefix spec
60-
ifcBsFile = render $ pPrint $ compileIfcBS bsSettings prefix spec
6160
bsFile = render $ pPrint $ compileBS bsSettings prefix spec
6261

6362
let dir = bluespecSettingsOutputDirectory bsSettings
6463
createDirectoryIfMissing True dir
6564
writeFile (dir </> specTypesPkgName prefix ++ ".bs") typesBsFile
66-
writeFile (dir </> specIfcPkgName prefix ++ ".bs") ifcBsFile
6765
writeFile (dir </> "bs_fp.c") copilotBluespecFloatingPointC
6866
writeFile (dir </> "BluespecFP.bsv") copilotBluespecFloatingPointBSV
6967
writeFile (dir </> prefix ++ ".bs") bsFile
@@ -93,86 +91,166 @@ compile :: String -> Spec -> IO ()
9391
compile = compileWith mkDefaultBluespecSettings
9492

9593
-- | Generate a @<prefix>.bs@ file from a 'Spec'. This is the main payload of
96-
-- the Bluespec backend.
97-
--
98-
-- The generated Bluespec file will import a handful of files from the standard
99-
-- library, as well as the following generated files:
100-
--
101-
-- * @<prefix>Ifc.bs@, which defines the interface containing the trigger
102-
-- functions and external variables.
103-
--
104-
-- * @<prefix>Types.bs@, which defines any structs used in the 'Spec'.
105-
--
106-
-- It will also generate a @mk<prefix> :: Module <prefix>Ifc -> Module Empty@
107-
-- function, which defines the module structure for this 'Spec'. The
108-
-- @mk<prefix>@ function has the following structure:
109-
--
110-
-- * First, bind the argument of type @Module <prefix>Ifc@ so that trigger
111-
-- functions can be invoked and external variables can be used.
112-
--
113-
-- * Next, declare stream buffers and indices.
114-
--
115-
-- * Next, declare generator functions for streams, accessor functions for
116-
-- streams, and guard functions for triggers.
117-
--
118-
-- * Next, declare rules for each trigger function.
119-
--
120-
-- * Finally, declare a single rule that updates the stream buffers and
121-
-- indices.
94+
-- the Bluespec backend. See the @copilot-bluespec/DESIGN.md@ document for a
95+
-- high-level description of what this file contains.
12296
compileBS :: BluespecSettings -> String -> Spec -> BS.CPackage
12397
compileBS _bsSettings prefix spec =
12498
BS.CPackage
12599
(BS.mkId BS.NoPos (fromString prefix))
126100
(Right [])
127101
(stdLibImports ++ genImports)
128102
[]
129-
[moduleDef]
103+
[ ifcDef
104+
, mkModuleDefPragma
105+
, mkModuleDef
106+
, ifcRulesDef
107+
, mkModuleRulesDef
108+
, addModuleRulesDef
109+
]
130110
[]
131111
where
132112
-- import <prefix>Types
133-
-- import <prefix>Ifc
134113
genImports :: [BS.CImport]
135114
genImports =
136115
[ BS.CImpId False $ BS.mkId BS.NoPos $ fromString
137116
$ specTypesPkgName prefix
138-
, BS.CImpId False $ BS.mkId BS.NoPos $ fromString
139-
$ specIfcPkgName prefix
140117
, BS.CImpId False $ BS.mkId BS.NoPos "BluespecFP"
141118
]
142119

143-
moduleDef :: BS.CDefn
144-
moduleDef = BS.CValueSign $
120+
-- interface <prefix>Ifc {-# always_ready, always_enabled #-} =
121+
-- ...
122+
ifcDef :: BS.CDefn
123+
ifcDef = BS.Cstruct
124+
True
125+
(BS.SInterface [BS.PIAlwaysRdy, BS.PIAlwaysEnabled])
126+
(BS.IdK ifcId)
127+
[] -- No type variables
128+
ifcFields
129+
[] -- No derived instances
130+
131+
-- {-# properties mkFibs = { verilog } #-}
132+
mkModuleDefPragma :: BS.CDefn
133+
mkModuleDefPragma = BS.CPragma $ BS.Pproperties mkModuleDefId [BS.PPverilog]
134+
135+
-- mk<prefix> :: Module <prefix>Ifc
136+
-- mk<prefix> =
137+
-- module
138+
-- ...
139+
mkModuleDef :: BS.CDefn
140+
mkModuleDef = BS.CValueSign $
145141
BS.CDef
146-
(BS.mkId BS.NoPos $ fromString $ "mk" ++ prefix)
147-
-- :: Module <prefix>Ifc -> Module Empty
142+
mkModuleDefId
148143
(BS.CQType
149144
[]
150-
(BS.tArrow
151-
`BS.TAp` (BS.tModule `BS.TAp` ifcTy)
152-
`BS.TAp` (BS.tModule `BS.TAp` emptyTy)))
153-
[ BS.CClause [BS.CPVar ifcModId] [] $
154-
BS.Cmodule BS.NoPos $
155-
BS.CMStmt
156-
(BS.CSBind (BS.CPVar ifcArgId) Nothing [] (BS.CVar ifcModId))
157-
: map BS.CMStmt mkGlobals ++
158-
[ BS.CMStmt $ BS.CSletrec genFuns
159-
, BS.CMrules $ BS.Crules [] rules
160-
]
145+
(BS.tModule `BS.TAp` ifcTy))
146+
[ BS.CClause [] [] $
147+
BS.Cmodule BS.NoPos $
148+
wireGlobalStmts ++ genFunStmts ++ ruleIfcStmts
161149
]
162-
163-
ifcArgId = BS.mkId BS.NoPos $ fromString ifcArgName
164-
ifcModId = BS.mkId BS.NoPos "ifcMod"
165-
166-
rules :: [BS.CRule]
167-
rules = map mkTriggerRule uniqueTriggers ++ maybeToList (mkStepRule streams)
150+
where
151+
wireGlobalStmts :: [BS.CMStmt]
152+
wireGlobalStmts = map BS.CMStmt (mkExtWires ++ mkGlobals)
153+
154+
genFunStmts :: [BS.CMStmt]
155+
genFunStmts =
156+
-- language-bluespec's pretty-printer will error if it encounters a
157+
-- CSletrec with an empty list of definitions, so avoid generating a
158+
-- CSletrec if there are no streams.
159+
[ BS.CMStmt $ BS.CSletrec genFuns | not (null genFuns) ]
160+
161+
ruleIfcStmts :: [BS.CMStmt]
162+
ruleIfcStmts =
163+
[ BS.CMrules $ BS.Crules [] $ maybeToList $ mkStepRule streams
164+
, BS.CMinterface $ BS.Cinterface BS.NoPos (Just ifcId) ifcMethodImpls
165+
]
166+
167+
-- interface <prefix>RulesIfc =
168+
-- ...
169+
ifcRulesDef :: BS.CDefn
170+
ifcRulesDef =
171+
BS.Cstruct
172+
True
173+
(BS.SInterface [])
174+
(BS.IdK ifcRulesId)
175+
[] -- No type variables
176+
ifcRulesFields
177+
[] -- No derived instances
178+
179+
-- mk<prefix>Rules :: <prefix>Ifc -> <prefix>RulesIfc -> Rules
180+
-- mk<prefix>Rules ifc ifcRules =
181+
-- rules
182+
-- ...
183+
mkModuleRulesDef :: BS.CDefn
184+
mkModuleRulesDef =
185+
BS.CValueSign $
186+
BS.CDef
187+
mkModuleRulesDefId
188+
(BS.CQType [] mkModuleRulesType)
189+
[BS.CClause
190+
(map BS.CPVar [ifcArgId, ifcRulesArgId])
191+
[]
192+
(BS.Crules [] moduleRules)]
193+
where
194+
-- <prefix>Ifc -> <prefix>RulesIfc -> Rules
195+
mkModuleRulesType :: BS.CType
196+
mkModuleRulesType =
197+
BS.tArrow `BS.TAp` ifcTy `BS.TAp`
198+
(BS.tArrow `BS.TAp` ifcRulesTy `BS.TAp` BS.tRules)
199+
200+
-- rules
201+
-- ...
202+
moduleRules :: [BS.CRule]
203+
moduleRules = map mkTriggerRule uniqueTriggers ++ map mkExtRule exts
204+
205+
-- add<prefix>Rules :: <prefix>Ifc -> <prefix>RulesIfc -> Module Empty
206+
-- add<prefix>Rules ifc ifcRules = addRules (mk<prefix>Rules ifc ifcRules)
207+
addModuleRulesDef :: BS.CDefn
208+
addModuleRulesDef =
209+
BS.CValueSign $
210+
BS.CDef
211+
addModuleRulesDefId
212+
(BS.CQType [] addModuleRulesType)
213+
[BS.CClause
214+
(map BS.CPVar [ifcArgId, ifcRulesArgId])
215+
[]
216+
addModuleRulesExpr]
217+
where
218+
-- <prefix>Ifc -> <prefix>RulesIfc -> Module Empty
219+
addModuleRulesType :: BS.CType
220+
addModuleRulesType =
221+
BS.tArrow `BS.TAp` ifcTy `BS.TAp`
222+
(BS.tArrow `BS.TAp` ifcRulesTy `BS.TAp`
223+
(BS.tModule `BS.TAp` emptyTy))
224+
225+
-- addRules (mk<prefix>Rules ifc ifcRules)
226+
addModuleRulesExpr :: BS.CExpr
227+
addModuleRulesExpr =
228+
BS.CApply
229+
(BS.CVar (BS.idAddRules BS.NoPos))
230+
[BS.CApply
231+
(BS.CVar mkModuleRulesDefId)
232+
(map BS.CVar [ifcArgId, ifcRulesArgId])]
233+
234+
mkModuleDefId =
235+
BS.mkId BS.NoPos $ fromString $ "mk" ++ prefix
236+
mkModuleRulesDefId =
237+
BS.mkId BS.NoPos $ fromString $ "mk" ++ prefix ++ "Rules"
238+
addModuleRulesDefId =
239+
BS.mkId BS.NoPos $ fromString $ "add" ++ prefix ++ "Rules"
168240

169241
streams = specStreams spec
170242
triggers = specTriggers spec
171243
uniqueTriggers = mkUniqueTriggers triggers
172244
exts = gatherExts streams triggers
173245

246+
-- Remove duplicates due to multiple guards for the same trigger.
247+
triggersNoDups = nubBy compareTrigger triggers
248+
249+
ifcArgId = BS.mkId BS.NoPos $ fromString ifcArgName
250+
ifcRulesArgId = BS.mkId BS.NoPos $ fromString ifcRulesArgName
251+
174252
ifcId = BS.mkId BS.NoPos $ fromString $ specIfcName prefix
175-
ifcFields = mkSpecIfcFields triggers exts
253+
ifcFields = mkSpecIfcFields uniqueTriggers exts
176254
ifcTy = BS.TCon (BS.TyCon
177255
{ BS.tcon_name = ifcId
178256
, BS.tcon_kind = Just BS.KStar
@@ -181,81 +259,90 @@ compileBS _bsSettings prefix spec =
181259
(map BS.cf_name ifcFields)
182260
})
183261

262+
ifcRulesId = BS.mkId BS.NoPos $ fromString $ specIfcRulesName prefix
263+
ifcRulesFields = mkSpecIfcRulesFields triggersNoDups exts
264+
265+
ifcRulesTy =
266+
BS.TCon $
267+
BS.TyCon
268+
{ BS.tcon_name = ifcRulesId
269+
, BS.tcon_kind = Just BS.KStar
270+
, BS.tcon_sort =
271+
BS.TIstruct (BS.SInterface []) (map BS.cf_name ifcRulesFields)
272+
}
273+
184274
emptyTy = BS.TCon (BS.TyCon
185275
{ BS.tcon_name = BS.idEmpty
186276
, BS.tcon_kind = Just BS.KStar
187277
, BS.tcon_sort = BS.TIstruct (BS.SInterface []) []
188278
})
189279

280+
-- Bind @Wire@ variables for each extern stream.
281+
mkExtWires :: [BS.CStmt]
282+
mkExtWires = map extWireStmt exts
283+
where
284+
extWireStmt :: External -> BS.CStmt
285+
extWireStmt (External name ty) = mkExtWireDecln name ty
286+
190287
-- Make buffer and index declarations for streams.
191288
mkGlobals :: [BS.CStmt]
192289
mkGlobals = concatMap buffDecln streams ++ map indexDecln streams
193290
where
194291
buffDecln (Stream sId buff _ ty) = mkBuffDecln sId ty buff
195292
indexDecln (Stream sId _ _ _ ) = mkIndexDecln sId
196293

197-
-- Make generator functions, including trigger arguments.
294+
-- Make generator functions for streams.
198295
genFuns :: [BS.CDefl]
199-
genFuns = map accessDecln streams
200-
++ map streamGen streams
201-
++ concatMap triggerGen uniqueTriggers
296+
genFuns = map accessDecln streams ++ map streamGen streams
202297
where
203298
accessDecln :: Stream -> BS.CDefl
204299
accessDecln (Stream sId buff _ ty) = mkAccessDecln sId ty buff
205300

206301
streamGen :: Stream -> BS.CDefl
207302
streamGen (Stream sId _ expr ty) = mkGenFun (generatorName sId) expr ty
208303

209-
triggerGen :: UniqueTrigger -> [BS.CDefl]
210-
triggerGen (UniqueTrigger uniqueName (Trigger _name guard args)) =
211-
guardDef : argDefs
304+
-- Make interface methods for @<prefix>Ifc@.
305+
ifcMethodImpls :: [BS.CDefl]
306+
ifcMethodImpls =
307+
concatMap triggerMethodImpls uniqueTriggers
308+
++ map extMethodImpl exts
309+
where
310+
-- interface
311+
-- ext val = ext_wire := val
312+
extMethodImpl :: External -> BS.CDefl
313+
extMethodImpl (External name _) =
314+
BS.CLValue extMethodId [extMethodClause] []
315+
where
316+
extMethodId = BS.mkId BS.NoPos (fromString name)
317+
valId = BS.mkId BS.NoPos "val"
318+
319+
-- ext val = ext_wire := val
320+
extMethodClause :: BS.CClause
321+
extMethodClause =
322+
BS.CClause
323+
[BS.CPVar valId]
324+
[]
325+
(BS.Cwrite
326+
BS.NoPos
327+
(BS.CVar (BS.mkId BS.NoPos (fromString (wireName name))))
328+
(BS.CVar valId))
329+
330+
-- interface
331+
-- trig_guard = ...
332+
-- trig_arg0 = ...
333+
-- ...
334+
-- trig_arg(n-1) = ...
335+
triggerMethodImpls :: UniqueTrigger -> [BS.CDefl]
336+
triggerMethodImpls uniqueTrigger = guardDef : argDefs
212337
where
338+
UniqueTrigger uniqueName (Trigger _name guard args) = uniqueTrigger
339+
213340
guardDef = mkGenFun (guardName uniqueName) guard Bool
214341
argDefs = map argGen (zip (argNames uniqueName) args)
215342

216343
argGen :: (String, UExpr) -> BS.CDefl
217344
argGen (argName, UExpr ty expr) = mkGenFun argName expr ty
218345

219-
-- | Generate a @<prefix>Ifc.bs@ file from a 'Spec'. This contains the
220-
-- definition of the @<prefix>Ifc@ interface, which declares the types of all
221-
-- trigger functions and external variables. This is put in a separate file so
222-
-- that larger applications can use it separately.
223-
compileIfcBS :: BluespecSettings -> String -> Spec -> BS.CPackage
224-
compileIfcBS _bsSettings prefix spec =
225-
BS.CPackage
226-
ifcPkgId
227-
(Right [])
228-
(stdLibImports ++ genImports)
229-
[]
230-
[ifcDef]
231-
[]
232-
where
233-
-- import <prefix>Types
234-
genImports :: [BS.CImport]
235-
genImports =
236-
[ BS.CImpId False $ BS.mkId BS.NoPos $ fromString
237-
$ specTypesPkgName prefix
238-
]
239-
240-
ifcId = BS.mkId BS.NoPos $ fromString $ specIfcName prefix
241-
ifcPkgId = BS.mkId BS.NoPos $ fromString $ specIfcPkgName prefix
242-
ifcFields = mkSpecIfcFields triggers exts
243-
244-
streams = specStreams spec
245-
exts = gatherExts streams triggers
246-
247-
-- Remove duplicates due to multiple guards for the same trigger.
248-
triggers = nubBy compareTrigger (specTriggers spec)
249-
250-
ifcDef :: BS.CDefn
251-
ifcDef = BS.Cstruct
252-
True
253-
(BS.SInterface [])
254-
(BS.IdK ifcId)
255-
[] -- No type variables
256-
ifcFields
257-
[] -- No derived instances
258-
259346
-- | Generate a @<prefix>Types.bs@ file from a 'Spec'. This declares the types
260347
-- of any structs used by the Copilot specification. This is put in a separate
261348
-- file so that larger applications can more easily substitute their own struct

copilot-bluespec/src/Copilot/Compile/Bluespec/Name.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module Copilot.Compile.Bluespec.Name
1010
, lowercaseName
1111
, specIfcName
1212
, specIfcPkgName
13+
, specIfcRulesName
1314
, specTypesPkgName
1415
, streamAccessorName
1516
, streamElemName
@@ -35,6 +36,10 @@ specIfcName prefix = uppercaseName (specIfcPkgName prefix)
3536
specIfcPkgName :: String -> String
3637
specIfcPkgName prefix = prefix ++ "Ifc"
3738

39+
-- | Turn a specification name into the name of its rules-specific interface.
40+
specIfcRulesName :: String -> String
41+
specIfcRulesName prefix = uppercaseName (prefix ++ "RulesIfc")
42+
3843
-- | Turn a specification name into the name of the package that declares its
3944
-- struct types.
4045
specTypesPkgName :: String -> String

0 commit comments

Comments
 (0)