In my previous blog about transaction-level synthesis, I discussed the notions of dependency in both the control and data senses. Dependency provides a guide to the synthesis tool about where and how concurrency can be created.
We also have considered the notion of micro-architecture in terms of rough resource allocation and performance. Now it is time to start thinking about building some real circuitry. I am going to continue using the simple data flow from the last blog, reproduced here for your convenience (the expression is A = B + (C*D) - (E+F) * G):
If we wanted the fastest implementation, we could allocate two adders, two multipliers, and a subtractor and then map each of the operators to these allocated resources.
Purely for the sake of these discussions, let us also assume that a multiplier takes longer than an adder, which in turn takes longer than a subtractor. Based on this, we can determine the shortest (i.e., fastest) and longest (i.e., slowest) paths through the design. The longest are caused by changes in inputs C, D, E, and F, while the shortest is associated with a change in input B.
Each critical path requires the use of a multiplier, and several alternative implementations could be chosen to match the desired performance. Keep in mind that this solution would also require a large area and consume a lot of power.
At this stage, you are probably thinking that this looks very much like RTL synthesis, and it is… until we take the next step. This is to look at multi-cycle solutions to this problem, which is generally referred to as scheduling. With RTL synthesis, this all has to fit into one clock cycle. However, with transaction-level synthesis, we can consider a variety of other solutions that share resources over time. The process of looking at multiple architectures without having to modify the original source is referred to as architectural exploration.
Next page >