Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
41 changes: 41 additions & 0 deletions DEVELOP.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,47 @@ The following is a running list of those writings.
* [How Bluesim provides implementations for import-BVI](https://groups.io/g/b-lang-discuss/topic/106520424)
* [How the Bluesim C API is imported into Bluetcl](https://groups.io/g/b-lang-discuss/message/554)
* There is a template for making Bluesim standalone programs (without Tcl) in `bsc/util/bsim_standalone/`
* `-c` (codegen mode): per-module byte-identity and object reuse (see below)

#### `-c` (codegen mode): per-module byte-identity

Terminology: a module generated as a `-e` link's *top* is in "top form" (its
interface methods are fired by the design schedule that the link also
generates); everywhere else -- under `-c`, or as a submodule of any design --
it is in "block form". Block form is the shared, reusable output; top form
is private to the link that made it.

`-sim -c M` emits `M`'s Bluesim C++ (and only `M`'s) without a runnable top, so
`M`'s object can be built once and reused wherever `M` appears in a design.
Reuse *trusts* byte-identity: `isStale` (`SimFileUtils.hs`) reuses an object on a
version/timestamp/`codeGenOptionDescr` match, never comparing content -- so
`M`'s `-c` output must equal the C++ it gets as a submodule. (A link's own
top is the exception: it is generated in "top form", which the descriptor
records as `top`, so the two forms are never mixed by reuse.)

It does, because both are generated from the same already-elaborated `M.ba`;
only two things differ between the runs, and both are neutralized:

* **Interned-`Id` order** varies with what else is compiled, but only *reorders*
output, and every per-module emission site is name-sorted (the four
"Canonicalize ... order" commits, plus pre-existing sorts).
* **The schedule** (`M`'s own, firing-suppressed, vs the whole design's) reaches
per-module codegen through three channels, each made `M`-intrinsic:
*top-ness* (`mkScheduleStmts` drops `M`'s own interface-method firing, so DCE
gives submodule form), *VCD clock annotation* (`clk_map`; the emitted domain
comes from `M.ba`), and *member-vs-local* (`moveDefsOntoStack`; a top
interface method's readiness is reached by the RDY call, as a parent would,
not a direct read).

`check_block_codegen_modules` (`testsuite/config/unix.exp`) enforces it: it
rebuilds every multi-module test's submodules with `-c` and byte-compares.

The Verilog backend has the same mode: `-verilog -c M` regenerates `M.v` from
`M.ba` (via `vGenMods` in `bsc.hs`), byte-identical to the `.v` that `-g`
writes for the same elaboration under the same generation flags. Codegen
flags are read from the `-c` invocation's command line (elaboration-affecting
flags are baked into the `.ba`), and foreign-function `.ba` files are found
via the same `-p`/`-bdir` search path as at link time.

### Bluetcl

Expand Down
13 changes: 3 additions & 10 deletions src/comp/ABin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ module ABin (ABin(..),
abemi_rule_relation_db
) where

import Data.Maybe(isNothing)
import PPrint
import Id(Id)
import Position(Position)
Expand All @@ -28,7 +27,6 @@ import ADumpScheduleInfo(MethodDumpInfo)
import VModInfo(VPathInfo)
import ForeignFunctions(ForeignFunction(..))
import Flags(Flags(..))
import Verilog(VProgram)


-- ===============
Expand Down Expand Up @@ -62,9 +60,7 @@ data ABinModInfo =
abmi_oqt :: CQType,
abmi_method_dump :: MethodDumpInfo,
abmi_pathinfo :: VPathInfo,
abmi_flags :: Flags,
-- the generated Verilog
abmi_vprogram :: Maybe VProgram
abmi_flags :: Flags
}

data ABinForeignFuncInfo =
Expand Down Expand Up @@ -113,19 +109,16 @@ instance PPrint ABin where


instance PPrint ABinModInfo where
pPrint d p (ABinModInfo path srcName apkg aschedinfo pps oqt mi pathinfo flags vprog) =
pPrint d p (ABinModInfo path srcName apkg aschedinfo pps oqt mi pathinfo flags) =
text "path:" <+> text path $+$
text "package:" <+> text srcName $+$
pPrint d 0 apkg $+$
pPrint d 0 aschedinfo $+$
text "pprop:" <+> pPrint d 0 pps $+$
text "oqt:" <+> pPrint d 0 oqt $+$
-- no dump of method info
text "pathinfo:" <+> pPrint d 0 pathinfo $+$
text "pathinfo:" <+> pPrint d 0 pathinfo
-- no dump of flags
text "vprog:" <+> (if (isNothing vprog)
then text "Nothing"
else text "Just ...") -- no dump of contents


instance PPrint ABinForeignFuncInfo where
Expand Down
34 changes: 32 additions & 2 deletions src/comp/ABinUtil.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module ABinUtil (
readAndCheckABin,
readAndCheckABinPath,
readAndCheckABinPathCatch,
isStaleABinFile,
) where

import Data.List(nub, partition)
Expand All @@ -16,7 +17,7 @@ import Control.Monad.State(StateT, runStateT, lift, get, put)
import Version(bscVersionStr)
import Backend
import FileNameUtil(abinSuffix)
import FileIOUtil(readBinaryFileCatch, readBinFilePath)
import FileIOUtil(readBinaryFileCatch, readBinFilePath, readBinaryFileMaybe)
import Util(fromMaybeM)

import Error(internalError, EMsg, EMsgs(..), ErrMsg(..),
Expand All @@ -29,7 +30,9 @@ import ASyntaxUtil(getForeignCallNames)
import VModInfo(vName, getVNameString)
import ForeignFunctions(ForeignFunction(..), ForeignFuncMap)
import ABin
import GenABin(readABinFile)
import GenABin(readABinFile, readABinFileMaybe)

import qualified Control.Exception as CE

import qualified Data.Map as M

Expand Down Expand Up @@ -532,4 +535,31 @@ decodeABin errh backend filename contents =
-- from this point
(ABinModSchedErr {}) -> Right abi

-- Tolerant counterpart of the decodeABin checks, for deciding whether
-- an existing .ba file can be used by the current compilation: it must
-- be readable, in the current format and BSC version, and elaborated
-- for a compatible backend. A missing file returns False (not stale);
-- absence is the timestamp check's concern. Used by the -u
-- recompilation check, where an unusable .ba (e.g. one left by
-- "-verilog -g" when compiling with -sim, or written by another BSC
-- version) must force re-elaboration rather than be trusted as an
-- up-to-date generated product.
isStaleABinFile :: Maybe Backend -> String -> IO Bool
isStaleABinFile be fname = do
mbytes <- readBinaryFileMaybe fname
case mbytes of
Nothing -> return False
Just bytes ->
let beOf (ABinMod mi _) = apkg_backend (abmi_apkg mi)
beOf (ABinModSchedErr mi _) = apkg_backend (abmsei_apkg mi)
beOf (ABinForeignFunc {}) = Nothing
stale = case readABinFileMaybe bytes of
Nothing -> True
Just abin ->
(ab_version abin /= bscVersionStr True) ||
not (backendMatches be (beOf abin))
in CE.evaluate stale `CE.catch` handler
where handler :: CE.SomeException -> IO Bool
handler _ = return True

-- ===============
12 changes: 10 additions & 2 deletions src/comp/Depend.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ import FStringCompat
import Lex
import Parse
import FileNameUtil(hasDotSuf, dropSuf, baseName, dirName,
bscSrcSuffix, bsvSrcSuffix, binSuffix,
bscSrcSuffix, bsvSrcSuffix, binSuffix, abinSuffix,
mkAName, mkVName, mkVPIHName, mkVPICName,
createEncodedFullFilePath)
import FileIOUtil(readFilesPath, readBinFilePath, readFileCatch, writeFileCatch,
removeFileCatch)
import ABinUtil(isStaleABinFile)
import Id
import PreIds(idPrelude, idPreludeBSV)
import Parser.Classic(pPackage, errSyntax, classicWarnings)
Expand Down Expand Up @@ -263,7 +264,14 @@ chkUpd flags doneMap resultList (pi:pis) = do
--putStrLn (show genfs)
genfsClks <- mapM getModTime genfs
incfsClks <- mapM getModTime incfs
let needGenUpd = any (srcMod pi >) genfsClks
-- a .ba that exists (and is fresh by timestamp) is still not a
-- valid generated product if it cannot be read (another BSC
-- version's format) or was elaborated for an incompatible backend
-- (a Verilog-tagged .ba left by "-verilog -g" must not satisfy a
-- -sim compile, or vice versa); codegen must run again
staleAbins <- mapM (isStaleABinFile (backend flags))
(filter (hasDotSuf abinSuffix) genfs)
let needGenUpd = any (srcMod pi >) genfsClks || or staleAbins
needIncUpd = any (lastMod pi <) incfsClks
--putStrLn (show (fileName pi, genfs, map (srcMod pi >) genfsClks))
--putStr (ppReadable (pkgName pi, imports pi, DM.keys doneMap))
Expand Down
21 changes: 21 additions & 0 deletions src/comp/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,11 @@ data ErrMsg =
-- Bluesim-specific errors/warnings
| EBluesimNoXZ String

-- Errors for the .ba -> code generation mode (-c)
| EGenWithEntry String
| EGenWithSrcFile String
| EGenWithSystemC

-- Errors/warnings from the SystemC wrapper generator
| ESystemCWrapperComboPaths String
| ESystemCWrapperInvalidMethods [String]
Expand Down Expand Up @@ -4500,6 +4505,22 @@ getErrorText (EMissingVPIWrapperFile fname is_dpi) =
in s2par ("Cannot find the " ++ ifctype ++ " file " ++ ishow fname ++
" in the Verilog search path."))

getErrorText (EGenWithEntry entry) =
(System 96, empty,
s2par ("The flag -c generates code from an elaborated module; " ++
"it cannot be combined with -e (linking). To link " ++
ishow entry ++ ", run bsc again with -e."))

getErrorText (EGenWithSrcFile fname) =
(System 97, empty,
s2par ("The flag -c operates on elaborated (.ba) files, so a " ++
"source file (" ++ ishow fname ++ ") cannot be provided. " ++
"To compile and generate from source, use -g."))

getErrorText EGenWithSystemC =
(System 98, empty,
s2par ("The flag -c is not supported with -systemc; use -sim."))

-- Runtime errors
getErrorText (EMutuallyExclusiveRulesFire r1 r2) =
(Runtime 1, empty,
Expand Down
6 changes: 5 additions & 1 deletion src/comp/Flags.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ data Flags = Flags {
backend :: Maybe Backend,
bdir :: Maybe String,
biasMethodScheduling :: Bool,
-- internal: set by the driver when in -c mode (generate a module's
-- code from its .ba, as a reusable block rather than a runnable top);
-- never settable from the command line -- see codegenNames
blockCodegen :: Bool,
bluespecDir :: String,
cIncPath :: [String],
cLibPath :: [String],
Expand All @@ -45,13 +49,13 @@ data Flags = Flags {
dumpAll :: Maybe (Maybe FilePath), -- maybe dump to file or stdout
dumps :: [(DumpFlag, Maybe FilePath)], -- dump to file or stdout
enablePoisonPills :: Bool,
codegenNames :: [String],
entry :: Maybe String,
expandATSlimit :: Int,
expandIf :: Bool,
fdir :: Maybe String,
finalcleanup :: Int,
genABin :: Bool,
genABinVerilog :: Bool,
genName :: [String],
genSysC :: Bool,
ifcPathRaw :: [String],
Expand Down
Loading
Loading