SFLEXP (SFL EXPander) reads SFL files and performs logic synthesis for each SFL module.
SFLEXP produces the resultant netlist in the form of a file in HSL language. Although the netlist description language in PARTHENON is NLD, SFLEXP adopts HSL for historical development reasons. However, designers need not learn HSL because an HSL file can easily be converted into an NLD file using HSL_NLD.
Logic synthesis results given in NLD are transferred to the following programs for logic compression and assignment of components.
Let's take a simple example of logic synthesis from an SFL description.
A>sflexp abc.sfl abc.hsl
A large number of messages will be output in response. The following message, on the second line from the bottom of the message list, indicates that the logic synthesis has been executed correctly.
The following describes each switch.
'-single' specifies execution of post-opt processing for every action. The word, action, here means the write enable logic of a register or the select logic of a selector.
'-multi' specifies that post-opt is to be batch-processed for all actions.
'-nopost' specifies that no post-opt processing is to be executed.
Among these three switch options, '-multi' might appear the best selection. However, while '-multi' indeed simplifies the entire logic of the module and thus reduces the circuit well, it causes the following problems:
'-nonld' specifies that SFLEXP should output only the netlist synthesized from the SFL module
-fin 5
indicates that 'nand' and 'nor' gates with 2 to 5 inputs are to be used. If '1' is specified, no conversion from 'and' and 'or' to 'nand' and 'nor' is made and the fin-in number is not limited. If 'fin' is not specified, the default value of 8 is used.
The '-level_factor' switch indicates that potential logic part extraction is not to be performed if the number of inputs that can be reduced by bundling it is only as large as param.
For example:
-level_factor 3
indicates that, if a certain extraction would reduce the number of logic gate inputs by only 3, it is not to be performed. If 'param' is '0,' extraction is performed as long as it is effective. If 'param' is not specified, the default value of 0 is used.
The remainder is written in the C language for high-speed operation. This portion requires a dynamic heap area.
In consequence, SFLEXP requires both:
The -mem switch determines how large a static area is to be allocated for Prolog. The rest of the area is allocated for C.
The area to be used as the Prolog stack area is defined by assigning 'param' the values sss, ss, s or m, as below.
For settings sss, ss, s and m in param, the following amounts of memory are allocated:
If the available memory size is 3MB, 5MB, 10MB, or 14MB or more, sss, ss, s, and m should be specified, respectively.
The following problems may occur during logic synthesis.
(1) Syntax error
SFLEXP starts by reading the SFL description. Errors detected in the SFL description during this process are called syntax errors.
If a syntax error is detected, an error message such as the following is output:
The editor activation mechanism is specified in file 'sfl_edit.bat' in %PARTHENON%\com. The editor can be changed. (The default editor is Village Center's Vz Editor, and it is assumed that Vz Editor is installed in the directory indicated by the activation path.) When the editor is activated, the cursor is positioned in the line where the error has been detected. If you press the F4 key, the line and letter where an error may exist is displayed.
After you have corrected the error, close the editor, and type 'r.' The analysis recommences from the point where the correction was made. 'r.' is an SFLEXP sub-command indicating retry.
The only sub-commands allowed here are the following:
Unless a syntax error is detected, logic synthesis begins immediately. Since logic synthesis involves many steps, numerous messages are displayed to assure you that the program has not entered an endless loop. Although they have a meaning, you can normally ignore them.
(2) Overflow
While a software compiler only "converts one procedure to another," logic synthesis "converts a procedure to a structure" , and in doing so, is required to simplify logic expressions. Depending on the detail of the SFL description, this process sometimes requires such a huge amount of memory and calculation that overflow can occur, , even if the SFL description is correct. If an overflow occurs, you must change the description. For further details on overflow, see Section 6.4.
(3) Write collision error
A write collision error may be reported when there is a problem in the SFL description. If the error count displayed just before the completion of the SFLEXP execution is not 0, then either a write collision error or a state transition error has been detected.
<List 6.1> Example of a description causing a write collision error
1: module ng1 { 2: input a<8>; 3: input b<8>; 4: input c; 5: instrin start; 6: reg r<8>; 7: instrin start any { 8: c: r:=a; 9: c: r:=b; 10: } 11: }
In this example (List 6.1), the assignments to register 'r' specified in the 8th and 9th lines always cause a collision. Of course, a complete simulation should have detected the problem. However, since the simulator cannot report errors unless the conditions for a collision have been set up, the simulation may miss such errors. In contrast, logic synthesis develops and sorts out all logic issues, and thus can detect a collision caused by the assignment to register 'r.' The error message would appear as follows:
(4) State transition error
A state transition error, where the specified transition destination is non-existent occurs when, as shown in List 6.2, there is a description (goto statement) indicating a transition to the only effective state (only st1 is effective since a transition to st2 never occurs). In such a case, the logic synthesis cannot proceed correctly, and a state transition error is output.
A transition from one state to the same state is equivalent to no transition, and you should never write such a transition, since it is meaningless.
<List 6.2> An example of a description where an error occurs due to a meaningless state transition
1: module ng2 { 2: stage_name s { 3: task t(); 4: } 5: stage s { 6: state_name st1; 7: state_name st2; 8: first_state st1; 9: state st1 goto st1; 10: state st2 goto st2; 11: } 12: }
SFLEXP converts an SFL description into a circuit (the initial circuit) for each SFL module. As was mentioned earlier, logic cells are used for the component elements in the initial circuit, which is then optimized by the OPT_MAP, RINV and ONSET programs and finally converted into a circuit consisting of only real cells. This section (6.3) and the following section (6.4) explain more about the initial circuit.
This section describes the component elements in the initial circuit, which are directly associated with the SFL component elements, and the fixed connections, which are independent of the SFL description of operation. Section 6.4 describes how the various SFL operation descriptions are converted into connections between component elements.
External terminals of a module
The external terminals of the initial circuit (nld module) include the following four external input terminals in addition to the external terminals specified in the SFL module.
The types of the external terminals in the initial circuit correspond to the terminal types in the SFL module as follows:
A sub-module in SFL becomes a sub-module in the initial circuit. The sub-module instance name is the same as the instance name in SFL. The external terminals of the sub-module include the above four terminals (p_reset, m_clock, s_clock and b_clock) in addition to the external terminals of the SFL sub-module.
Data registers
The data registers defined in SFL by key words 'reg', 'reg_wr' and 'reg_ws' become data registers 'reg-N,' 'regr-N' and 'regs-N' for the logic cells in the initial circuit. The instance names are the same as the SFL instance names. (KDF I didn't understand the reason for the brackets, so I have changed it to read more naturally.)
State registers
The stages and segments in SFL become as many as log2N 'reg--1' state registers where N is the total number of states in the stage (including the number of segment states). The instance name is "stage name-bit_posi" or "stage name-segment name-bit_posi," where bit_posi is 0, 1, 2, ...
Task register
Task register 'reg---1' with the instance name "stage name-all" is generated from the SFL stage. A task in SFL becomes task register reg---1 with the instance name "stage name-task name."
Connections of resets and clocks
The p_reset, m_clock, s_clock and b_clock terminals of sub-modules and logic cells (data register, state register and task register) are directly connected to the p_reset, m_clock, s_clock and b_clock terminals of the module. That is, the polarity of the reset signals and clock signals, and the significance of pulse waveforms are not defined in PARTHENON programs. The information on them is given in the cell library.
For example, suppose a register of an edge trigger type using a single clock is adopted and 'm_clock' is used as a clock terminal in designing or selecting a cell library. This information is described in PCD and transferred to OPT_MAP, and the OPT_MAP function deletes the 's_clock' terminal and its connections from the final circuit.
Bus driver circuit for a bidirectional terminal and insertion of a selector
The external bidirectional terminals of a module or a sub-module are connected to and driven by bus driver circuit 'bdrv-N.' Their instance names are respectively: bidirectional data terminal name-drive, and sub-module name-bidirectional data terminal name-drive. If multiple transfer sources are connected to a bidirectional data terminal, selector 'slN-M' is inserted in front of the bus driver circuit.
Insertion of a selector before an output terminal
If only one transfer source sends data to a data output terminal, the transfer source is directly connected to the external output terminal in the initial circuit. If there are multiple transfer sources, a selector is inserted in front of the external output terminal.
Register selector insertion
If multiple transfer sources send data to a register, a selector is inserted in front of the input terminal of the register.
Cell name and instance name of inserted selectors
Logic cells 'slN-M' are used as the inserted selectors, and their instance names are sel-1, sel-2, ...
Internal control terminal
The internal control terminal in SFL becomes relay terminal 'inst-dum' for control in the initial circuit. The instance name is the same as the internal control terminal name in SFL. If the internal control terminal is activated from more than one place, an 'or' gate is inserted in front of 'inst-dum.'
Internal data terminal (situations where there are multiple data transfer sources)
If there are multiple data transfer sources, internal data terminals defined with 'bus_v', 'bus', 'sel_v' or 'sel' are converted into 'bsN-M' or 's1N-M' as follows.
Internal data terminals defined with 'bus_v' and 'sel_v' may be eliminated during logic compression. In that case, they do not appear in the initial circuit.
Internal data terminal (situations where there is only one data transfer source)
If there is only one data transfer source, an internal data terminal defined with 'sel' or 'bus' is converted into a data relay terminal 'bus-N'. The instance name of 'bus-N' is the same as the internal data terminal name in SFL.
Logic gate, constant
The instance names of logic gates and constants generated from SFL operation descriptions are as follows:
<Logic cell name> <Instance name> high- high- low- low- inv- inv-1, inv-2, inv-3, ... and--M and-1, and-2, and-3, ... nand--M nand-1, nand-2, nand-3, ... or--M or-1, or-2, or-3, ... nor--M nor-1, nor-2, nor-3, ... eor--2 eor-1, eor-2, eor-3, ...
We stated earlier that logic synthesis is the "conversion of a procedure into a structure, unlike a software compiler, which converts one procedure into another." In reality, logic synthesis operates by having a template ready for each SFL syntax or element and executing conversion of these one by one. However, without a high level of optimization, it is difficult to select appropriate templates. Thus, logic simplification can be said to be a key technique in logic synthesis (although this document does not go into the details of this subject).
As described in Section 6.3, SFLEXP converts the elements corresponding to actual entities (e.g., registers) directly into logic cells and interconnects them through control logic. During this conversion, selectors may be inserted as necessary to enable data selection.
Example in which control and data are separated
Let's synthesize List 6.3 in a batch program as follows:
sflexp %1.sfl %1.hsl mkdir %1.1st hsl_nld %1.hsl %1.1st nld_ps -o %1.ps %1 %1.1st %PARTHENON%/CELLDEMO/START type %1.ps > prnSince OPT_MAP, ONSET and RINV are not included for execution, circuit optimization may be insufficient. However, SFLEXP output may be more easily understood with this program example. This batch program requires a PostScript printer.
<List 6.3> Example in which control and data are separated
1: module test1 { 2: input abc; 3: bidirect xyz; 4: instrin start; 5: instruct start xyz = abc; 6: }
The logic synthesis result is shown in Figure 6.1.
<Fig 6.1> Logic synthesis result of List 6.3
Since a value is set to bidirectional data terminal 'xyz' in this example, 'bdrv-1' is inserted in front of 'xyz' and its output 'out' is connected to 'xyz.' Since 'abc' is the only input to 'xyz' , 'abc' is simply connected to input 'in' of 'bdrv-1.' Since the timing of setting a value to 'xyz' is when 'start' is "1," 'start' is connected to 'enb' of 'bdrv-1.'
Example in which control is eliminated
Let's look at an example in which control is eliminated. List 6.4 is the same as the above example except that xyz is defined as a data output terminal. The synthesis result is shown in Figure 6.2.
This SFL description indicates that 'abc' is set to 'xyz' if 'start' is "1", but does not say anything about the case where 'start' is '0'. That is, any value is allowed for 'xyz' when 'start' is not "1", and, therefore, synthesis is performed such that 'abc' is output continuously. As a result, 'abc' is simply connected to 'xyz', and terminal 'start' is unnecessary.
<List 6.4> Example eliminating control
1: module test2 { 2: input abc; 3: output xyz; 4: instrin start; 5: instruct start xyz = abc; 6: }
<Fig 6.2> Synthesis result of List 6.4
Example of logic compression
The next example is a case in which an operator is included. The synthesis result of List 6.5 is shown in Figure 6.3. When an operator appears as in this example, SFLEXP does not simply develop connections as described before, but attempts to simplify the logic. This circuit shows the result of simplification. Since SFLEXP does not optimize polarity from a global viewpoint, unnecessary inverters may be included. However, such redundant inverters are eliminated by OPT_MAP, ONSET or RINV.
<List 6.5> Example in which an operator is included
1: module test3 { 2: input abc; 3: input def; 4: output xyz; 5: instrin start; 6: instruct start xyz = abc & def; 7: }
<Fig 6.3> Synthesis result of List 6.5
To see how SFLEXP simplifies logic, let's consider the slightly more complicated example of logic in List 6.6. The result is shown in Figure 6.4. You will see that the logic is simpler than the original logic expression. You can also see that the logic for f1 and that for f2, which are the same, are both extracted during logic simplification.
<List 6.6> Example of logic compression
1: module test4 { 2: input a, b, c, d; 3: output f1, f2; 4: instrin start ; 5: instruct start par { 6: f1 = (^a & ^b & ^c & ^d) 7: | (^a & ^b & ^c & d) 8: | (^a & b & ^c & ^d) 9: | ( a & ^b & ^c & ^d) 10: | ( a & b & ^c & ^d) 11: | ( a & b & c & d) ; 12: f2 = (^a & ^b & ^c & ^d) 13: | (^a & ^b & ^c & d) 14: | (^a & b & ^c & ^d) 15: | ( a & ^b & ^c & ^d) 16: | ( a & b & ^c & ^d) 17: | ( a & b & c & d) ; 18: } 19: }
<Fig.6.4> Synthesis result of List 6.6
Example of conditional syntax
The next example shows how SFL conditional syntax is handled in synthesis. The description of List 6.7 denotes that, if data input terminal 'cnd' is '0', input abc is output to data output terminal 'xyz', and that if data input terminal 'cnd' is quot;1quot;, input 'def' is output to data output terminal 'xyz'. The result of the synthesis is shown in Figure 6.5. Since there are two transfer sources that send values to 'xyz', a selector is inserted and the transfer condition is simplified to the selector's select input.
<Fig.6.7> Example of a selector being inserted
1: module test5 { 2: input cnd<2>; 3: input abc<4>; 4: input def<4>; 5: output xyz<4>; 6: any { 7: cnd == 0b00 : xyz = abc; 8: cnd == 0b01 : xyz = def; 9: cnd == 0b10 : xyz = def; 10: cnd == 0b11 : xyz = abc; 11: } 12: }
<Fig. 6.5> Synthesis result of List 6.7
What would happen if data transfer sources 'abc' and 'def' were constants as shown in List 6.8? The only difference between List 6.8 and List 6.7 is that 'abc' and 'def' in the previous example are now replaced with 'ob1110' and 'ob0101', respectively. The result of synthesis is shown in Figure 6.6 (a). Since SFLEXP simplifies transfer sources and conditions separately for data transfer to the data output terminal, selector simplification is insufficient. However, OPT_MAP, ONSET and RINV achieve further simplification as shown in Figure 6.6 (b). This circuit diagram is output by the following batch program.
auto test6 ps celldemo
type test6.ps > prn
<List.6.8> Example of selecting constants
1: module test6 { 2: input cnd<2>; 3: output xyz<4>; 4: any { 5: cnd == 0b00 : xyz = 0b1110; 6: cnd == 0b01 : xyz = 0b0101; 7: cnd == 0b10 : xyz = 0b0101; 8: cnd == 0b11 : xyz = 0b1110; 9: } 10: }
<Fig. 6.6(a)> Synthesis result of List 6.8
<Fig. 6.6(b)> Synthesis result of List 6.8 (after execution of OPT_MAP, ONSET and RINV)
Example in which both conditions and constants are compressed
If a constant is to be transferred to the internal data terminal defined by 'sel_v' or 'bus_v' in an exclusive-or condition, SFLEXP simplifies transfer sources and transfer conditions collectively.
List 6.9 satisfies this condition. The synthesis by SFLEXP achieves simplification to some extent as shown in Figure 6.7 (a). However, if, as in this example, not all conditions are specified, it is recommended to use OPT_MAP, ONSET and RINV to achieve simplification (i.e., 'sel_v' should not be used in the description as in List 6.8). Theoretically, taking the 'don't care' condition for 'cnd' into account should yield a result with as much simplification as in Figure 6.6 (b). In reality, however, the simplification achieved falls short of that expectation, as may be seen in Figure 6.7 (b).
<List 6.9> Example of specifying selector part compression
1: module test7 { 2: input cnd<4>; 3: sel_v tmp<4>; 4: output xyz<4>; 5: par { 6: any { 7: cnd == 0x0 : tmp = 0b1110; 8: cnd == 0x1 : tmp = 0b0101; 9: cnd == 0x2 : tmp = 0b0101; 10: cnd == 0x3 : tmp = 0b1110; 11: } 12: xyz = tmp; 13: } 14: }
<Fig. 6.7(a)> Synthesis result of List 6.9
<Fig. 6.7(b)> Synthesis result of List 6.9 (after execution of OPT_MAP, ONSET and RINV)
Let's take an example of unsuccessful synthesis. Although List 6.10 is a simple description, a synthesis attempt causes overflow.
<List 6.10> Example of memory overflow
1: module test8 { 2: input abc<8>; 3: input def<8>; 4: output xyz; 5: xyz = /& ^ (abc & def); 6: }
<Fig. 6.8> Expansion into product sums
In simplifying the logic, SFLEXP first expands the logic expression in product sums. In the case of this logic expression, there are 28 products, i.e., 256 products as shown in Figure 6.8. Humans understand the pattern of the logic structure and think nothing of it. However, SFLEXP performs simplification of this logic expression in the same way as it does on random logic, and causes overflow.
If you know the pattern of the logic structure, you can prevent overflow by inserting terminals at appropriate places to isolate a particular part of the logic structure. The internal data terminal and sub-module terminal defined with 'sel' or 'bus' can be used for this purpose. List 6.11 shows an example where an internal data terminal divides the logic in List 6.10.
<List 6.11> Example of using an internal terminal
1: module test9 { 2: input abc<8>; 3: input def<8>; 4: sel tmp<8>; 5: output xyz; 6: par { 7: tmp = abc & def ; 8: xyz = /& ^ tmp ; 9: } 10: }
Example in which stages and state transitions are included
List 6.12 provides an example of a sequential circuit for the first time. Stage 'stg' has two states 'st1' and 'st2' and controls data transfer and processing. The state alternates between 'st1' and 'st2'. This stage does not begin operation until control input terminal 'start' is activated and a job is generated for the stage. In state st1, an in1 value is written to reg1 and the reg1 contents are output to 'out'. In state 'st2', the value of 'in2' is written into 'reg2' and the value of 'reg2' is output to 'out'. The result of synthesis with an auto command is shown in Figure 6.9.
<List 6.12> Example in which stages and state transitions are included
1: module test10 { 2: input in1,in2; 3: output out; 4: reg reg1,reg2; 5: instrin start; 6: stage_name stg { 7: task tsk(); 8: } 9: instruct start generate stg.tsk(); 10: stage stg { 11: state_name st1,st2; 12: first_state st1; 13: state st1 par { 14: reg1 := in1; 15: out = reg1; 16: goto st2; 17: } 18: state st2 par { 19: reg2 := in2; 20: out = reg2; 21: goto st1; 22: } 23: } 24: }
Register 'stg-0' indicates the state of the stage, the value "0" or "1" of this register differentiating between the two states. Task register 'stg-all' represents the on/off of the stage.
You can see that the reverse output (nout) of state register 'stg-0' is fed into input (in) and that the value is reversed in each machine cycle. You can also see that this reverse operation occurs only when the task register is "1".
Writing into 'reg1' and 'reg2' is controlled by both the state and task registers. In contrast, the value output from data output terminal 'out' is controlled only by the state register, and the on/off operation of the task register is judged unnecessary and thus omitted.
This should be a good example for clarifying what stages, tasks and states are.
<Fig. 6.9> Synthesis result of List 6.12
SFL description taking transfer path into account
Compare List 6.13 with List 6.14. Both are SFL descriptions where data input terminal 'in' and registers 'a', 'b', 'c' and 'd' are specified as transfer sources, and registers a, b, c and d are specified as transfer destinations. However, while List 6.13 directly describes all transfer operations, List 6.14 collects data in an internal data terminal 'tmp' and then transfers it to registers 'a', 'b', 'c' and 'd'.
If SFLEXP could determine what transfer operations occur concurrently, it could minimize transfer paths for any description. However, parallel operations defy such determination. Therefore, SFLEXP generates transfer paths just as they are described. As a result, List 6.13 generates a total of 20 transfer paths from 5 transfer sources to 4 transfer destinations. It is therefore recommended to write the description as shown in List 6.14.
As illustrated in this example, when using PARTHENON you should take into account details of the transfer paths that will be generated.
<List 6.13> Description not taking transfer paths into account
1: module test11 { 2: input case<4>; 3: input in<1>; 4: output out<1>; 5: reg a<1>,b<1>,c<1>,d<1>; 6: par { 7: out = d; 8: any { 9: case == 0x0: a := in; 10: case == 0x1: a := b; 11: case == 0x2: a := c; 12: case == 0x3: a := d; 13: case == 0x4: b := a; 14: case == 0x5: b := in; 15: case == 0x6: b := c; 16: case == 0x7: b := d; 17: case == 0x8: c := a; 18: case == 0x9: c := b; 19: case == 0xa: c := in; 20: case == 0xb: c := d; 21: case == 0xc: d := a; 22: case == 0xd: d := b; 23: case == 0xe: d := c; 24: case == 0xf: d := in; 25: } 26: } 27: }
<List 6.14> Description taking transfer paths into account
1: module test12 { 2: input case<4>; 3: input in<1>; 4: output out<1>; 5: reg a<1>,b<1>,c<1>,d<1>; 6: sel tmp<1>; 7: par { 8: out = d; 9: any { 10: case == 0x0: par { tmp = in; a := tmp; } 11: case == 0x1: par { tmp = b; a := tmp; } 12: case == 0x2: par { tmp = c; a := tmp; } 13: case == 0x3: par { tmp = d; a := tmp; } 14: case == 0x4: par { tmp = a; b := tmp; } 15: case == 0x5: par { tmp = in; b := tmp; } 16: case == 0x6: par { tmp = c; b := tmp; } 17: case == 0x7: par { tmp = d; b := tmp; } 18: case == 0x8: par { tmp = a; c := tmp; } 19: case == 0x9: par { tmp = b; c := tmp; } 20: case == 0xa: par { tmp = in; c := tmp; } 21: case == 0xb: par { tmp = d; c := tmp; } 22: case == 0xc: par { tmp = a; d := tmp; } 23: case == 0xd: par { tmp = b; d := tmp; } 24: case == 0xe: par { tmp = c; d := tmp; } 25: case == 0xf: par { tmp = in; d := tmp; } 26: }
27: }
28: }