Replies: 2 comments 8 replies
|
I can see the netlist generation part happening, though you need to account for the fact that clash-compiler/clash-lib/src/Clash/Driver.hs Lines 346 to 350 in 9aacba0 As for the simulation stuff I'm much more hesitant. Perhaps it makes more sense to iterate on the
This would kill any use of |
While I clearly share the desire to have such feature for debugging and convenience purposes, I am against it in the given form, mainly for two reasons:
This clearly is the major use case, where existing solutions are mostly inconvenient with Clash designs atm. Not only if you like to use an ILA, but also if you like to use an external logic sniffer, like a Saleae or an Analog/Digital Discovery device (does anybody call that an ELA 🤔). In that regard, my proposal would be to instead limit the scope of your portal to unused/new ports in the design. So if we only can "portal" some of the internal signals to some additional output ports that are "silently" added to the top entity, e.g., are not part of the default My main point is that if we like to add such a feature, then it should be embedded into a more restrictive scope than currently proposed. That scope should make it clear to only be applicable in a debugging context, and it should be always considered as a drop-in extensions, rather than a fundamental feature, that could end up being a crucial interface as part of the final design. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Motivation
In Clash designs it is often inconvenient to thread a signal from a deeply nested component back up, or down, to where it is consumed. The Clash ILA is the clearest example: you typically define the ILA near the top-level IO boundary, where the UART pins live. Connecting an internal signal to it requires manually plumbing that signal up through every intermediate module boundary. It is not difficult to do, but it is tedious and invasive, you change signatures and instantiation sites that have nothing to do with what you are debugging.
Signal portals are a proposed escape hatch. Mark a signal at its origin with a name, and retrieve it by that name from anywhere in the hierarchy, with Clash automatically adding the necessary ports between them during HDL generation.
Proposed API
portalSourceis a pass-through, it returns the same signal it receives, but marks it in the design so it can be retrieved elsewhere by name.portalSinkretrieves that signal. The name must be a compile-time string literal for synthesis to work.resetPortalMapis there to be able to do multiple simulations runs, more on that later.HDL generation
After netlist generation a dedicated pass could walk the component hierarchy and rewrites matching portal sources and sinks into ordinary input and output ports, propagating them upward and downward through intermediate instantiations as needed. Portals that are entirely contained within a single component subtree do not produce any ports outside that subtree. Unused sources produce a warning (or error under
-Werror).Simulation
Simulation is where this gets more hairy. There is no way to implement this without breaking Haskell's referential transparency.
Concretely:
Global mutable state.
portalSourceandportalSinkcommunicate through a process-wide map which is accessed usingunsafePerformIO& friends. This could perhaps at least be made thread local.Evaluation-order sensitivity.
portalSinkwould defers its map read to first-sample time. If the source has already been registered by then this works. If the source has not been registered yet, the only thing we can do is error out as there is no way to connect these two independent lazy thunks. I doubt this is fixable, but if anyone has an idea then I'm all ears.Loss of (compile time)type safety. The proposed API would route through a
pack,unpackpath which means during simulation you can only check if the width of the source and sink agree. This check could be expanded to full simulation time type safety usingTypeRep. This is not a constraint that clash circuits typically use though. So you'd need to add it to all type signatures as well. In either case you lose compile time type checking. During HDL generation you can check for equivalentHWTypeso this is less of an issue.Re-run hygiene. Each portal name is registered once per process(or per thread) lifetime. To run a simulation a second time in the same process (e.g. in a test suite),
resetPortalMapmust be called first. This quite something to burden on users.Questions
Do we even want to offer this API? It almost feels like an anti-feature to me. But I also recognize that it would be extremely handy in a pinch. We could give them scary names like
unsafePortal*.Should portals be restricted to synthesis-only (i.e. error in simulation rather than attempting the
unsafePerformIOroute)? That would simplify the story considerably at the cost of not being able to simulate designs that use portals.Are there use cases beyond debugging instrumentation (ILA, dumpVCD-style probes) that would justify the added complexity?
All reactions