NEXT (Adopting a Suitable Coding Style for HLS)
HLS Compiler Operational Phases
It operates rather like a software compiler, but needs more time/space guidance.
- Lexing and Parsing as for any HLL
- Type and reference checking: can an int be added to a string? Is an invoked primitive supported?
- Trimming: Unreachable code is deleted, register widths are reduced where it is manifest that the value stored is bounded, constants are propagated between code blocks and identity reductions are applied to operators, such as multiplying by unity.
- Binding: Every storage and processing element, such as a variable or an add operation or memory read, is allocated a physical resource.
- Polyhedral Mapping: A memory bandwidth optimisation for nested loops.
- Schedulling: Each physical resource will be used many times over in the time domain. A static schedule is generated. This is typically a scoreboard of what expressions are available when. (Worked example in lecuters.)
- Sequencer Generation: A controlling FSM that embodies the schedule and drives multiplexor and ALU function codes is generated.
- Quantity Surveying: The number of hardware resources and clock cycles used can now be readily computed.
- Optimisation: The binding and schedulling phase may be revisited to better match user-provided target metrics.
- RTL output: The resulting design is printed to a Verilog or VHDL file.
Some operations are intrinsically or better implemented as variable-latency. Examples are division and reading from cached DRAM.
This means the static schedule cannot be completely rigid and must be based on expected execution times.
Sometimes fully-pipelined HLS is required, where there is no scheduller and new data is input every cycle.
Or there may be a simple scheduller with no control flow: e.g. for a small initiation interval with new input every, say, 4 cycles.