You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Oftentimes, components can have different sets of behavior depending on the subset of the signals being assigned to. For example, a memory will often have two different interfaces: one for reads and one for writes
Of course, this gives you the usual goodness of knowing that writes take two cycles while reads take one cycle. However, the weird thing is that it has two interface ports: bothread_en and write_en represent the event G. Additionally, only a subset of ports are meaningful. For example, when the memory is being used to perform a read, the out port will have a meaningful output while performing a write, it won't. Similarly, the in port doesn't require an input if we're performing a write.
Enumeration: Representing Method Calls
The solution proposed here is using enumerations (similar to Rust's enum) as a way to represent method calls. For example:
(TK: Not sure what the best way to represent the output associated with the enum is here. Just using something dumb for now)
When using this component, you must explicitly construct the enumeration associated with the "method" you're trying to use: either a read or a write
comp main<G:1>)(...){M:= new Mem;
mw := M<G>(1/*addr*/,MemInterface::Write{in:15})// again, not the best syntax here
out = mw.out;// error because we called the Write method}
This all gives us the usual goodness of Filament of checking that signals are available at the right times etc. However, this leaves out a big question.
A Matter of Delay
Delays are the heart of Filament's reasoning about pipelining. The challenge with enumerations is that different methods might have different affects on pipelining: do reads and writes use the same underlying circuits and therefore might affect each other's delay. The simple solution is just making the whole enum have the same delay which might be a deal breaker but perhaps something to start with.
The other question is how to represent methods at the source level? This just talks about external primitives but overall, we want people to implement their own methods. I think the solution to this second question will probably elucidate the answer for the first one.
The text was updated successfully, but these errors were encountered:
Doing a good job with modules (A package manager and module system for Filament #118) becomes even more important now since the enumerations might be tied to the definition or usage of particular components. A pleasant experience with methods requires careful thought about namespacing and various related issues
Drive-by comment that may be entirely obvious: in an extremely high-level way, this resembles method overloading in OO languages. That is, in overloading, the behavior (and the return type) depends on the types of the arguments at the call site. Anyway, this isn't the same because you're explicitly choosing which behavior to use at the cal site rather than using the types, but it's not completely different!
A close analogy is Scala's match types which allow return types to be changed based on the call site argument. Unsurprisingly, they very quickly become useful in defining dependently typed methods.
Oftentimes, components can have different sets of behavior depending on the subset of the signals being assigned to. For example, a memory will often have two different interfaces: one for reads and one for writes
This component has two interfaces:
write_en
tells the component that the data on the input needs to be written to the address.read_en
tells the component that the user is trying to read data from an address.In Filament land, we can write the following signature:
Of course, this gives you the usual goodness of knowing that writes take two cycles while reads take one cycle. However, the weird thing is that it has two interface ports: both
read_en
andwrite_en
represent the eventG
. Additionally, only a subset of ports are meaningful. For example, when the memory is being used to perform a read, theout
port will have a meaningful output while performing a write, it won't. Similarly, thein
port doesn't require an input if we're performing a write.Enumeration: Representing Method Calls
The solution proposed here is using enumerations (similar to Rust's enum) as a way to represent method calls. For example:
(We use the function-like port signature to represent the inputs and outputs related to the call)
Next, we can change the definition of the component to use this enum:
(TK: Not sure what the best way to represent the output associated with the enum is here. Just using something dumb for now)
When using this component, you must explicitly construct the enumeration associated with the "method" you're trying to use: either a read or a write
This all gives us the usual goodness of Filament of checking that signals are available at the right times etc. However, this leaves out a big question.
A Matter of Delay
Delays are the heart of Filament's reasoning about pipelining. The challenge with enumerations is that different methods might have different affects on pipelining: do reads and writes use the same underlying circuits and therefore might affect each other's delay. The simple solution is just making the whole
enum
have the same delay which might be a deal breaker but perhaps something to start with.The other question is how to represent methods at the source level? This just talks about external primitives but overall, we want people to implement their own methods. I think the solution to this second question will probably elucidate the answer for the first one.
The text was updated successfully, but these errors were encountered: