-
Notifications
You must be signed in to change notification settings - Fork 1
/
prompts.json
760 lines (760 loc) · 47.6 KB
/
prompts.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
[{
"desc": "Initial code"
}, {
"desc": "Module declaration",
"prompt": "The Verilog file should declare a single module. If the file contains multiple modules or no module, report an issue using the \"issue\" field of the response."
}, {
"desc": "Code sections",
"prompt": "Partition the code into three sections: \"Begin File\", \"Begin Body\", and \"End Body\". Each section will be identified by a header comment line including its name, as \"// LLM: Section: <name>\" (with no preceding whitespace). The first section of the file will be named \"Begin File\", so add a first line to the file: \"// LLM: Section: Begin File\". The second section of the file will be called \"Begin Body\". It will begin immediately following the \";\" ending the module interface declaration. The final (third) section will be called \"End Body\". It will begin immediately preceding the \"endmodule\" line. Add the appropriate header comment lines to identify these sections. For example, your response might look like this:
+
+```verilog
+// LLM: Section: Begin File
+module my_module (
+ input logic a,
+ output logic b
+);
+// LLM: Section: Begin Body
+ assign a = b;
+// LLM: Section: End Body
+endmodule
+```
+
+Note, the \"Begin File\" and \"End Body\" sections might include other things like \"`define\" statements, etc."
}, {
"desc": "Analyze tabs",
"must_produce": ["tab_width"],
"prompt": "Try to determine the assumed width of tabs in the given Verilog code. Make no changes to the Verilog, but report the determined tab width in a field called \"tab_width\" in the response. If the width is not clear, provide a \"tab_width\" value of \"unknown\". If there are no tabs in the code, provide a \"tab_width\" value of \"none\"."
}, {
"desc": "Fix tabs",
"unless": {"tab_width": "none"},
"needs": ["tab_width"],
"prompt": "Tab characters do not have a standardized width. The developer's assumption for the tab width has been determined and is listed below in the field \"tab_width\". Replace tabs with the appropriate number of spaces."
}, {
"desc": "Three-space indentation",
"needs": ["tab_width"],
"prompt": "Each level of code scope in TL-Verilog is indented exactly three spaces. Update the Verilog codes's line indentation to conform to this standard of three spaces of indentation for its Verilog scopes, such as within `begin`/`end`.
+
+Here is some additional guidance. The module declaration as well as the \"endmodule\" should have no indentation. Any indentation of module parameter in the module definition may be left unchanged. The body of the module should have one level (three spaces) of indentation. For multiline statements, lines after the first line of each statement must be indented, but this indentation may be preserved (if > 0). This indentation does not have to be three spaces.
+
+Note that if the Verilog code originally used tabs, the indentation has already been updated to use spaces in the original code for this refactoring step, and this indentation likely matches the assumed tab width reported below in the field \"tab_width\". If the original code was consistent with its scope indentation, your updates will consistently update from this indentation to the new three-space indentation convention. If the original code was not consistent with its indentation, you will make it consistently three spaces."
}, {
"desc": "Clocking",
"must_produce": ["clock"],
"prompt":
"The FEV flow we are using in the refactoring process requires a single free-running input clock (or no clock). We cannot currently automate the conversion of a module with other clock inputs. Further, internally generated clocks can be problematic for conversion to TL-Verilog.
+
+In this refactoring step, you will scan through the Verilog code to understand and report on its use of clocks in the module. Most modules take a global clock as input and use it for all sequential elements (which primarily tend to be D-type flip-flops). If this is the case for this module, you will make no code changes and simply provide a \"clock\" field in your response whose value is the name of the global clock input signal.
+
+It is also possible that the module is purely combinational and has no input clock signal(s). In this case, provide a \"clock\" field value of \"NONE\".
+
+In other cases, you may encounter more sophisticated clocking that could be problematic. Specifically, any use of a clock other than a global input clock could be problematic. You will report on these issues so the user can address them. In no circumstance will you make changes to the Verilog logic for this refactoring step. You may, however, add or modify code comments to capture your findings for the benefit of those who will work with the translated code. Let's discuss various scenarios you might encounter, how to recognize them, and how to best deal with them.
+
+Any code that generates a clock internally should be identified and reported as an issue. \"TODO: LLM: ...\" comments should be inserted to identify such code. This could include code that generates a clock for simulation using (non-synthesizable) delay statements, e.g. `@5 clk = ! clk`. It could also include code that generates an internal clock based on an input clock. This would include gated clocks and divided clocks, discussed next.
+
+Gated clocks might be generated in various ways. Verilog logic can infer clock gating implicitly. In this case, the gated clock is not explicitly declared as a signal. This is actually a case you don't need to worry about, but let me explain it so you know not to report on it. As an example, consider the following code:
+
+```verilog
+always_ff @(posedge clk) if (valid) y <= x;
+```
+
+Logic synthesis could produce from this a gated clock that pulses only when the `valid` signal is asserted. This gated clock would clock the flip-flop that updates `y`. Again, this implicit clock gating will be addressed later, so you can ignore such implicit clock gating for now.
+
+Explicit clock gating, on the other hand, should be identified and reported as an issue. A clock gating module or macro might be used to generate the gated clock signal. Or the gating logic itself might be explicit. Such logic might use a clock enable signal that would be ANDed with the global clock signal. Report any such code in the \"issues\" response field, and add \"TODO: LLM: ...\" comments to identify such code.
+
+Divided clocks are also problematic. They can be generated from a global clock by counting clock pulses. They might be implemented as a special case of clock gating by enabling a pulse once every n cycles. This would produce a divided clock with an imbalanced duty cycle, where, for example, the high duration of the clock pulse is the same as the high duration of the global clock, but the low duration is extended. Alternatively, a half-frequency clock with a balanced duty cycle might be generated by toggling a signal on every rising edge of the global clock. Divided clocks might also be generated through the use of module or macro instantiation.
+
+Clock signals can also be identified based on their names ('clock', 'clk', etc.), and by code comments. Any input signals beyond the global clock input that also appear to be clock signals should be reported.
+
+Clock signals can also be identified based on their usage. A clock signal will be used in a `posedge` or `negedge` condition of an `always @` or `always_ff`. Any edge-triggered use of a signal other than the global clock can be reported, however, it is sufficient to report the generation of or the input of such a clock. If the generation or input of the clock is reported, it is not necessary to report each use.
+
+You might find the use of multiple independent clocks that do not share a common global clock. Each clock might be an independent input to the module or might be generated by a phase-locked loop (PLL)--the circuit typically used to generate clocks. Generally, though different clocks would be in separate clock domains and different modules. You might see a module that is specifically providing clock crossing logic that has multiple clocks. Such modules are not good candidates for conversion to TL-Verilog.
+
+In the \"notes\" field of your response, report on the global clock signal, either which signal it is, that there isn't one, or that it is not clear which signal is the global clock. Again, include an additional field in your response called \"clock\" whose value is the name of the clock input signal. If there is no input clock signal, provide a value \"NONE\" for \"clock\".
+
+In the \"issues\" field of the response, list all other potential explicit input and internal clock signals (if any) with a brief description for each of what type of clock it is (or might be) and how it is used. Also, updated the code with \"TODO: LLM: ...\" comments to identify these issues in the code."
}, {
"desc": "Clock signal",
"unless": {"clock": ["NONE", "clk"]},
"needs": ["clock"],
"background":
"TL-Verilog has a requirement that, if there is a clock signal, it is named `clk`.",
"prompt":
"The global clock signal name is reported below in the field \"clock\". Create a `clk` signal at the beginning of the module. For example, if the input clock name is 'input_clk', add the line `logic clk = input_clock;` at the beginning of the module body and replace `input_clock` (in this example) with `clk` throughout the code.",
"TODO": "Add some automation to detect code that uses `negedge` and not `posedge` and invert the clock in this case."
}, {
"desc": "Reset issues",
"background":
"Reset methodology varies across designs. Most designs will use an external global (\"cold\") reset signal to initialize machine state to known reset values. This reset will be propagated throughout the design, beginning as an asynchronous condition, and possibly being synchronized with the clock at some point in its distribution. Synchronous reset signals may be delayed through D-flip-flops before reaching the states they control.
+
+TL-Verilog constructs are for synchronous logic only. Designers often like to drive asynchronous reset signals directly into flip-flops, which would not be possible in TL-Verilog. Use of asynchronous resets can be recognized as a reset signal used as a `posedge`/`negedge` condition in an `always @` or `always_ff` block. It may also be used in an `if` condition of a non-blocking assignment.
+
+Often Verilog developers prefer to use inverted (aka negatively-asserted) reset signals (that are low (zero) during reset, and high (one) during normal operation), and this is fine, though FEV needs to be aware of the assertion level. Negatively-asserted reset signals might have names like `nrst`, `reset_n`, `resetb`, etc. (where 'n' stands for \"not\" and 'b' stands for \"bar\").
+
+Some circuits may have lesser reset signals that might reset a subset of the states in the overall circuit. These might be termed \"soft reset\", \"logic reset\", \"local reset\", etc. These should be synchronous",
"prompt":
"Unless it is purely combinational, our current module should have a primary reset input signal and may have other reset signals. All non-clock inputs should be synchronous. This may not be obvious from the interface definition. A name like `arst` might indicate an asynchronous reset, or code comments might indicate intent. The use of the signal as edge-triggering may also indicate an asynchronous nature. Flip-flop module names might also suggest the use of an asynchronous reset. If it appears an asynchronous input is used, report an \"issue\", and add a \"TODO: LLM: ...\" comment.
+
+If it is clear which is the module's primary reset signal, include two additional fields in the response. The first will be called \"reset\" and its value will be the name of the reset signal. The second will be called \"reset_assertion\". This field indicates the assertion level of the reset signal, and it must have a value of \"high\" or \"low\". If the circuit is purely combinational and contains no reset input signals, return a \"reset\" field value of \"NONE\" and no \"reset_assertion\" field. If it is not clear which is the primary reset signal, return a \"reset\" field value of \"UNKNOWN\" and no \"reset_assertion\" field.
+
+Reset signals can be identified by their names (e.g. reset, rst, reset_n, resetb, nrst, etc.) and by their usage. Aside from possible comment additions/changes, there is no need to modify the Verilog code. Use \"issues\" to comment briefly on additional reset signals, describing in at most one sentence how broadly they are used in the module. Also comment and report issues for any asynchronous use of lesser reset signals.",
"must_produce": ["reset"],
"may_produce": ["reset_assertion"]
},{
"desc": "Non-synthesizable, analog, and tri-state code",
"background":
"Our convesion process does convert non-synthesizable logic, analog modeling, and multi-driven buses (that use tri-state logic).
+
+Starting with non-synthesizable logic, in SystemVerilog, certain constructs are intended primarily for simulation purposes and are not synthesizable, meaning they can't be directly translated into hardware components during the synthesis process. Here's a summary of some common non-synthesizable constructs in SystemVerilog:
+
+Initial Blocks: Used primarily in testbenches, initial blocks execute only once at the beginning of simulation. These are used for setting up simulation parameters or initializing variables and are not suitable for hardware synthesis which requires continuously operating circuits.
+
+Always Blocks with Delay: Constructs like always #10 ... use simulation delays (#) to control timing, which can't be directly implemented in hardware. Delays are purely for simulation to mimic real-time behavior and are ignored in synthesis.
+
+Procedural Timing Controls: Timing control statements such as #, wait, and @ (event control) are used to manage simulation time and event ordering. These constructs do not have a direct hardware counterpart as hardware operation is continuous and not event-based.
+
+Simulation-Specific System Tasks and Functions: Functions like $display, $stop, and $monitor are used for debugging and monitoring during simulation. These constructs provide output to the console or control simulation flow but do not translate to any hardware logic.
+
+Fork-Join Constructs: The fork ... join construct allows multiple procedural blocks to execute concurrently in simulation, which is useful for describing parallel operations in test environments. However, the actual implementation of parallelism in hardware needs to be explicitly defined using synthesizable constructs.
+
+Non-Synthesizable Data Types: Certain data types, like real and string, are used for modeling and simulation purposes only. For instance, floating-point types (real, realtime) are typically used in algorithmic modeling but require explicit hardware implementation through fixed-point arithmetic or dedicated floating-point units for synthesis.
+
+Certain Conditional Statements: Constructs like assert and assume are used in formal verification to check properties and assumptions within the design during simulation. These are not synthesized into hardware but are crucial for ensuring design correctness in pre-synthesis simulation.
+
+Dynamic Memory Allocation: Dynamic constructs such as dynamic arrays, queues, and associative arrays are primarily used in testbenches for flexible data storage. These are typically not synthesizable as hardware requires fixed memory allocation.
+
+
+Analog modeling is another area that is not supported by our conversion process. Analog modeling is used to describe continuous-time signals and behavior, which is fundamentally different from the discrete-time, digital logic that is synthesized into hardware. Analog constructs like continuous assignments, real numbers (`wreal`), and `analog` blocks are not supported by hardware synthesis tools and are not part of the digital logic design flow.
+
+
+Tri-state logic is a type of logic that allows a signal to assume one of three states: logic 0, logic 1, or high impedance (Z-state). Tri-state logic is commonly used in bus systems to allow multiple devices to share a common bus. However, tri-state logic is not directly synthesizable into hardware and can lead to issues like bus contention and undefined logic levels. Synthesizable hardware designs typically use multiplexers or other techniques to avoid tri-state logic.",
"prompt":
"TL-Verilog and FEV are tools for working with digital, sequential logic. They are not intended for working with non-synthesizable verification (test bench) modeling. They are also not meant for analog logic and tri-state (Z-state) buses. Analyze the Verilog code for any use of non-synthesizable, analog, and/or tri-state logic. If any of these are found, add \"TODO: LLM: ...\" comments to the code to identify these issues, and report them in the \"issues\" field of the response. There is no need to make any code changes other than comments. If no non-synthesizable, analog, or tri-state code is found, do not make code/comment changes, and do not report issues."
},{
"desc": "Proper reset signal",
"if": {"reset_assertion": "low"},
"needs": ["reset", "reset_assertion"],
"prompt":
"The primary reset input signal (identified in the \"reset\" field listed below) is negatively-asserted (as determined earlier and reported in the \"reset_assertion\" field, also listed below). Create a signal called `reset`, generated by inverting the primary reset input signal.
+
+This new signal should be used in the module in place of the primary reset input signal. Update the code to use this new `reset` signal, inverting the polarity of its use, in all cases, to preserve the original behavior."
},{
"desc": "Separate declarations",
"prompt":
"In SystemVerilog, 'logic' and 'wire' signal declarations may be followed by an '=' and an assignment. For any statements that combine the declaration and assignment, separate these into two statements with the declaration on its own line. For example:
+
+```verilog
+logic y = a & b;
+```
+
+should be transformed to:
+
+```verilog
+logic y;
+y = a & b;
+```
+
+Since the module interface declares output signals, no changes are required for module output assignments."
},{
"desc": "Identify non-deterministic behavior",
"background":
"Some constructs in Verilog can lead to non-deterministic behavior or inconsistent behavior on different simulation tools. The following are some examples of non-deterministic code:
+
+- Inconsistent use of blocking and non-blocking assignments. Blocking assignments should be used for combinational logic, and non-blocking assignments should be used for sequential logic triggered by a clock. If blocking and non-blocking assignments are not used properly, race conditions can occur.
+- Use of `initial` blocks to initialize signals. This can lead to non-deterministic behavior because the order of execution of `initial` blocks is not guaranteed.
+- Use of `#` delays in combinational logic. This can lead to non-deterministic behavior because the order of execution of the logic is not guaranteed.
+- Use of `initial` blocks.
+- Consumption of dont-care values. Use of dont-cares can be good practice, but care must be taken to ensure that they do not affect behavior. Dont-care propagation is not consistent across simulation tools.
+- Consumption of signals that will not settle to a known value during reset.
+- Multiple drivers for a signal.
+- Use of `#` delays in combinational logic.
+- Incomplete sensitivity lists in `always` blocks.
+- Implicit nets (in other words, signals that aren't declared).
+- Indeterminate loop bounds (those that cannot be statically determined).
+- Case statements without a `default` case. This can lead to non-deterministic behavior if the case statement is not fully enumerated.",
"prompt":
"Identify non-deterministic code and summarize issues in the \"issues\" field of the response. Add \"TODO: LLM: ...\" comments to non-deterministic code to identify these issues and to provide suggested corrections where possible. Do not make any changes to the code at this time other than adding comments."
},{
"desc": "Avoid partial signal assignments",
"prompt":
"TL-Verilog currently only supports assignment statements that assign all bits of a signal. Try to eliminate all situations where an assignment statement's assigned signal (on the left-hand side of the \"=\") specifies an explicit bit range, such as \"foo[FOO_WIDTH-1:3] = ...;\". Bit ranges used on the right-hand side of an assignment statement are not a problem.
+
+In the simplest case, the specified bit range might refer to the entire signal, in which case, it can be removed. If different bit ranges of a signal are assigned by different statements, attempt to refactor the code. A few strategies are possible:
+
+Multiple assignments can be turned into one by using concatenation. This requires the assigned bit ranges to be contiguous. For example, in this code:
+
+```verilog
+logic y[7:0];
+assign y[3:0] = a;
+assign y[7:4] = b;
+```
+
+`y[7:4]` and `y[3:0]` are contiguous and comprise the complete signal `y`. We combine their assignments by concatenating their left-hand-sides as:
+
+```verilog
+logic y[7:0];
+assign y = {b, a};
+```
+
+Another approach is to define intermediate signals for the partial bit ranges. In the example above, the original code, separately assigning `y[3:0]` and `y[7:4]` could alternatively have been refactored as:
+
+```verilog
+logic [7:0] y;
+logic [3:0] y_low; // LLM: Temporary: Intermediate signal for partial assignment.
+logic [7:4] y_high; // LLM: Temporary: Intermediate signal for partial assignment.
+assign y_low = a;
+assign y_high = b;
+assign y = {y_high, y_low}; // LLM: Temporary: Combined the partial assignments.
+```
+
+This strategy preserves the structure of the various assignments of the signal. It can be the best choice for signals whose various bit ranges are assigned under different conditions within an always block.
+
+Look for assignment statements that assign a partial bit range of a signal and refactor the code to eliminate these partial assignments. If you find any partial assignments that are difficult to refactor, report them in the \"issues\" field of the response and add \"TODO: LLM: ...\" comments to identify these issues in the code."
},{
"desc": "Replace if/else with ternary expressions",
"prompt":
"For signals assigned in all cases of an inner-most `if`/`else` statement or chain. Transform the signal's assignments into a ternary expression. For example, transform:
+
+```verilog
+if (cond)
+ y = b;
+else
+ y = c;
+```
+
+into:
+
+```verilog
+// LLM: Temporary: Transformed from if/else chain.
+y = cond ? b : c;
+```
+
+Let's look at a more interesting example.
+
+```verilog
+...
+ if (valid) begin
+ if (cond1)
+ y = b;
+ else if (cond2)
+ y = c;
+ else begin
+ y = d;
+ z = e;
+ end
+ else
+ y = f;
+ end
+...
+```
+
+might be transformed into:
+
+```verilog
+...
+ // LLM: Task: This \"if\" block needs further consideration.
+ if (valid) begin
+ // LLM: Temporary: Transformed from if/else chain.
+ y = cond1 ? b :
+ cond2 ? c :
+ d;
+
+ if (!cond1 && !cond2) // LLM: Temporary: Removed the original `if` and `if else` cases and updated the condition accordingly.
+ z = e; // LLM: Temporary: Cannot be transformed because not all conditions result in an assignment.
+ else
+ y = f;
+ end
+...
+```
+
+Notice a few things in the above example:
+ - The \"z\" signal is not transformed because not all conditions result in an assignment. With the \"y\" signal removed, the `if`/`else` chain was simplified for the remaining \"z\" signal.
+ - Having reduced the inner expression for \"y\", the outer `if`/`else` can then be turned into an extension of the ternary expression for \"y\". This transformation is tagged as a subsequent task. rather than tackling too much at once.
+
+A subsequent transformation of the above example might result in this further-updated verilog:
+
+```verilog
+...
+ // LLM: Temporary: Extended with `valid` case from `if` condition.
+ y = valid ? cond1 ? b :
+ cond2 ? c :
+ d :
+ f;
+
+ if (valid && !cond1 && !cond2) // LLM: Temporary: Incorporated `valid` from `if` expression.
+ z = e;
+...
+```
+
+This would complete the refactoring of `y`, and there is nothing more to do for `z` either.
+
+As you go through the Verilog code, you may find that it already contains ternary expressions. Since these look like refactoring progress, but are not, mark them with comments like \"// LLM: Temporary: Nothing changed here.\" Otherwise you might mistakenly believe you have made forward progress when you have not. Since these will be removed from your response they will have no other impact and will cause no harm."
},{
"desc": "Merge conditional assignments using ternary expressions",
"prompt":
"Where a signal is assigned within an always block, then assigned conditionally (under an `if` or case statement), combine the conditional assignment with the unconditional assignment using a ternary expression. These assignments could be nested under an outer condition--that doesn't matter. The conditional assignment's condition becomes the condition of the added ternary expression added to the first assignment. If these are followed by another conditional assignment, this transformation can be applied again, adding a new first ternary expression, resulting in a new ternary chain. For example:
+
+```verilog
+always_comb begin
+ if (a)
+ begin
+ y = 1'b0; // first assignment
+ if (b)
+ y = d; // conditional assignment
+ if (c)
+ y = e; // another conditional assignment
+ end
+end
+```
+
+can be transformed to:
+
+```verilog
+always_comb begin
+ if (a)
+ begin
+ y = c ? e : // another conditional assignment
+ b ? d : // conditional assignment
+ 1'b0; // first assignment
+ end
+end
+```
+
+As always, don't tackle too much at once. Do at least one transformation if there is one to be done, but don't feel compelled to do more than a few. If any assignments remain to be combined, respond with an \"incomplete\" value of \"true\"."
},{
"desc": "No implied latches",
"background":
"In digital design using Verilog, an \"implied latch\" refers to a storage element that is created due to incomplete specification of conditions in combinational logic coding. This happens when the Verilog code does not explicitly define the output for all input conditions, often within an `always` block.
+
+Implied latches are typically formed in two scenarios:
+
+Missing Else Condition: This is common in conditional statements (`if`, `case`) where not all possible conditions are accounted for. For example, in an `if` statement without a corresponding `else` part, if the `if` condition is not met, the output retains its previous state, implying a latch to store that state.
+
+Incomplete Case Statements: Similarly, in a `case` statement, if not all possible cases are covered and there is no default condition, a latch will be implied to hold the output state until a covered case occurs.
+
+Example of Implied Latches:
+
+```verilog
+always @(a or b)
+begin
+ if (a == 1'b1)
+ y = b;
+ // No else part; what happens when a is not 1?
+end
+```
+
+In this example, when `a` is not 1, the value of `y` is not defined, which leads to the creation of an implied latch. To maintain its last state, hardware for a latch will be synthesized.
+
+It is important to understand that this implied-latch case only relates to combinational always blocks, such as `always_comb` blocks and `always` blocks that are not edge-sensitive. The term \"implied latch\" does not apply to similar scenarios for non-blocking assignments in edge-triggered blocks. Though latches could be implied by non-blocking assignments, they are not considered implied latches because their are other ways to treat these cases that do not involve latches.",
"prompt":
"Make sure there are no implied latches in the design. Verify that all signals that are assigned combinationally (by blocking `=` assignments) are fully specified. In other words, there must be no condition under which the signal is unassigned.
+
+This analysis can be non-trivial. Since semantics are sequential within an always block, the best strategy is to analyze the assignments of the signal sequentially. Once the signal is determined to be fully specified, subsequent assignments are immaterial. For `if` statements and nested `if` statements, if every `if` has a corresponding `else`, and each case assigns the signal in question, that signal is fully specified......
+
+Any issues will be addressed by the user, so make no changes to the code at this time other than adding comments.
+
+Identify any issues in the \"issues\" field of the response, and add \"TODO: LLM: ...\" comments to capture these issues in the code without making corrections."
},{
"desc": "Avoid latches",
"prompt":
"Our conversion flow does not support designs containing latches. At this point, if there are any latches in our design to address, they should be level-sensitive latches, allowing values to propagate during one of the phases of the clock. A typical coding pattern for such a latch might be:
+
+```verilog
+always @(clk or d) begin
+if (clk == 1'b1) begin
+ q = d; // Output follows input while clock is high
+end
+// When clk is low, q holds its value
+end
+```
+
+If there are latches in the design, identify them in the \"issues\" field of the response and add \"TODO: LLM: ...\" comments to capture these issues in the code."
},{
"desc": "Rising edge D-type flip-flops only",
"background":
"It is most typical for flip-flop-based sequential logic to consistently use flip-flops that are triggered on the rising edge of the clock.
+
+In sequential logic design, D flip-flops are the most common type of flip-flop used. They are edge-triggered, meaning that the output of the flip-flop changes only on the rising or falling edge of the clock signal. (In our case, they should be triggered by the rising edge.) For D-type flip-flops, this clock edge results in the input value being driven at the output. Other types of flip-flops, such as T flip-flops and JK flip-flops, are less common in modern designs. They incorporate a logic function in addition to their sequential behavior.",
"prompt":
"If the code contains any sequentials other than rising-edge-triggered D-flip-flops, report issues in the \"issues\" field of the response and add \"TODO: LLM: ...\" comments to capture these issues in the code. Do not make any changes to the code other than adding these comments (if needed)."
},{
"desc": "No incomplete conditionals",
"background":
"Signals should be assigned by one and only one statement or block.
+
+In a combinational statement or block (sensitive to logic signals, not to a clock edge), each signal should be assigned for all possible inputs to avoid implied latches. At this point, our Verilog code should be free of implied latches.
+
+In `always` blocks that are triggered by a clock, such as `always @(posedge clk)` and `always_ff @(posedge clk)`, input combinations that result in no assignment, imply that the value must be held. A logic synthesis tool could implement this is various ways. The most direct interpretation might imply a latch after the logic expression that prevents the result of the expression from propagating through the latch in cases where no assignment would be made. Thus the enable input for the latch would be this no-assignment condition. This would be an awkward use of a latch in the context of otherwise flip-flop-based logic. Logic synthesis might instead derive a circuit with an explicit recirculation path to preserve the unchanged value. In this case, the edge-triggered always block results in a D-flip-flop that is driven by the logic within the always block. The implied recirculation path would feed the flop output through a multiplexer back into the flop. The multiplexer would select this recirculation path in cases where no assignment is made. Alternatively, logic synthesis might infer clock gating to retain the value by gating off the clock pulse when no update is to be made to the always block's output value.",
"prompt":
"For signals assigned by a clock-edge-triggered always block whose assignment is incomplete (in other words, the signal is not assigned under all possible input conditions), update the Verilog code to provide explicit recirculation of the value through a multiplexer and D-flip-flop. For example:
+
+```verilog
+always_ff @(posedge clk)
+begin
+ if (reset)
+ y <= 1'b0;
+ else if (a)
+ y <= b;
+end
+```
+
+should be updated to:
+
+```verilog
+always_ff @(posedge clk)
+begin
+ if (reset)
+ y <= 1'b0;
+ else if (a)
+ y <= b;
+ else
+ y <= y; // Recirculate the value explicitly
+end
+```
+
+Similary, for a `case` statement:
+
+```verilog
+always_ff @(posedge clk)
+begin
+ case (sel)
+ 2'b00: y <= a;
+ 2'b01: y <= b;
+ endcase
+end
+```
+
+should be updated to:
+
+```verilog
+always_ff @(posedge clk)
+begin
+ case (sel)
+ 2'b00: y <= a;
+ 2'b01: y <= b;
+ default: y <= y; // Recirculate the value explicitly
+ endcase
+end
+```
+
+If there are no incomplete assignments, do not make any changes to the code. And remember, even though block quotes are provided here to delimit Verilog code snippets, the \"verilog\" field of your response should provide the literal Verilog code without block quotes."
},{
"desc": "Use SystemVerilog always blocks",
"prompt":
"Get rid of Verilog `always` blocks and replace them with SystemVerilog `always_ff` and `always_comb` blocks. For example, `always @(posedge clk)` should be replaced with `always_ff @(posedge clk)`. Such blocks should already use non-blocking (`=>`) assignments, not blocking ones, and no internal changes should be needed within the blocks. `always @*` or `always` blocks with non-edge-triggered sensitivity lists should be replaced by `always_comb`. These should already use blocking (`=`) assignments, not non-blocking ones, and no internal changes should be needed within the blocks. Update the code to use these SystemVerilog always blocks. Only modify pre-existing `always` blocks. In particular, do not modify `assign` statements."
},{
"desc": "Separate combinational and sequential logic blocks",
"prompt":
"Let's avoid having combinational logic in `always_ff` blocks. Modify `always_ff` blocks as and if necessary to separate combinational and sequential logic (D flip-flops) into separate always blocks. Combinational logic should be in `always_comb` blocks, and flip-flops should be in `always_ff` blocks.
+
+For example:
+
+```verilog
+always_ff @(posedge clk)
+begin
+ if (reset)
+ y <= 1'b0;
+ else if (a)
+ y <= b;
+ else
+ y <= y; // Recirculate the value
+end
+```
+
+should become:
+
+```verilog
+logic NEXT_y;
+
+always_comb
+begin
+ if (reset)
+ NEXT_y = 1'b0;
+ else if (a)
+ NEXT_y = b;
+ else
+ NEXT_y = y; // Recirculate the value
+end
+
+always_ff @(posedge clk)
+begin
+ y <= NEXT_y;
+end
+```
+
+Generally, to transform an `always_ff` block that includes combinational logic:
+
+- Declare new signals that represent the values that are flopped. Use the prefix `NEXT_` for these
+- Change `always_ff` blocks to `always_comb` and non-blocking assignments to blocking ones. These blocking assignments should assign the `NEXT_` versions of the signals.
+- Add `always_ff` blocks to flop the `NEXT_` signals to the original signals."
},{
"desc": "Use 'logic' for all signals",
"background":
"SystemVerilog introduced the `logic` data type to replace the `reg` and `wire` data types in Verilog. The `reg` and `wire` data types are still supported in SystemVerilog for backward compatibility, but it is recommended to use `logic` for all signal declarations.",
"prompt":
"Replace all `reg` and `wire` declarations with `logic`."
},{
"desc": "Individual flip-flops",
"prompt":
"Use a separate `always_ff` blocks for each flopped signal. Each blocks may be written on a single line without `begin`/`end`, such as: `always_ff @(posedge clk) y <= NEXT_y;`."
},{
"desc": "Short always blocks",
"prompt":
"TL-Verilog favors individual, independent assignment statements per signal over large, combinational `always_comb` blocks with sequential semantics. To work incrementally toward this, break up `always_comb` blocks into smaller blocks. Be careful not to separate portions of a block that assign the same signal.
+
+At this time, do not do any substantial code restructuring. Just make the easy changes.
+
+Be sure to preserve the comments from within the original block. Determine how these comments correspond to the code. Comments that associate with multiple of the new block can be moved outside of their `always_comb` block. Those that associate with the entirety of a new block can also be moved outside the new block. Other comments may associate with internal portions of a block and should remain internal to the new blocks."
},{
"desc": "Combinational logic block per signal",
"prompt":
"For the first `always_comb` block in which multiple signals are assigned, break the block into multiple `always_comb` blocks, one per assigned signal. For example:
+
+```verilog
+always_comb
+begin
+ if (type == 2'b00)
+ begin
+ y = a;
+ z = b;
+ else
+ begin
+ y = c;
+ if (big)
+ z = d;
+ else
+ z = e;
+ end
+end
+```
+
+should be transformed to:
+
+```verilog
+always_comb
+begin
+ if (valid && type == 2'b00)
+ begin
+ y = a;
+ else
+ begin
+ y = c;
+ end
+end
+
+always_comb
+begin
+ if (valid && type == 2'b00)
+ begin
+ z = b;
+ else
+ begin
+ if (big)
+ z = d;
+ else
+ z = e;
+ end
+end
+```
+
+The recommended strategy for doing this is to identify the first signal to separate out. Walk through the code of the block and include those parts of the block that affect that particular signal to form its `always_comb` block. Then, repeat this process for the remaining signals.
+
+Handling comments appropriately can be tricky. Some comments might be relevant to multiple signals, and the code for these signals is getting separated. In some cases it might be best to move the comment outside the the `always_comb` blocks. The comment may need some rewording in its new context. Be sure not to lose any comments, their meaning, or their association. When uncertain, replicate the comments in each new block. Add \"TODO: LLM: ...\" comments to the code to identify any such commenting issues that would benefit from human review, and report them in \"issues\".
+
+If breaking up a particular `always_comb` block would be overly disruptive to the code structure, leave it as is and add a comment such as \"LLM: This block should be translated to TL-Verilog using a TL-Verilog `\\always_comb` block\". If you encounter a block that already has such a comment, be sure to process the next block.
+
+If there are other `always_comb` blocks that assign multiple signals that you have not processed, respond with an \"incomplete\" field of \"true\""
},{
"desc": "Remove unnecessary begin/end",
"prompt":
"Anywhere `begin`/`end` are used around a single statement, remove them."
},{
"desc": "Use ternary expressions instead of if/else",
"prompt":
"Transform `if`/`else` statements that assign a value to a signal into ternary expressions. For example, transform:
+
+```verilog
+if (a)
+ y = b;
+else
+ y = c;
+```
+
+into:
+
+```verilog
+y = a ? b : c;
+```"
},{
"desc": "Use ternary expressions instead of case",
"prompt":
"Transform `case` statements that assign a value to a signal into ternary expressions. For example, transform:
+
+```verilog
+case (a)
+ 2'b00: y = b;
+ 2'b01: y = c;
+ default: y = d;
+endcase
+```
+
+into:
+
+```verilog
+y = (a == 2'b00) ? b : (a == 2'b01) ? c : d;
+```"
},{
"desc": "Use assign",
"prompt":
"Transform `always_comb` blocks that assign a single signal into `assign` statements. For example, transform:
+
+```verilog
+always_comb
+begin
+ y = a & b;
+end
+```
+
+into:
+
+```verilog
+assign y = a & b;
+```"
},{
"desc": "Common subexpressions",
"prompt":
"Scan the code for common subexpressions. Where doing so would simplify the code, extract such a subexpressions into a separate `assign` statements. For example:
+
+```verilog
+assign foo = (valid && type == 2'b00) ? a : c;
+assign bar = (valid && type == 2'b00) ? b : (big ? d : e);
+```
+
+could be transformed to:
+
+```verilog
+assign valid_type0 = valid && type == 2'b00;
+assign foo = valid_type0 ? a : c;
+assign bar = valid_type0 ? b : (big ? d : e);
+```
+
+As always, if the needed changes are significant, make a few changes, and leave the rest as is, indicating that changes are incomplete and outlining a plan for the remaining changes of this refactoring step."
},{
"desc": "Named block syntax",
"background":
"In Verilog, `generate` blocks can be named. For example:
+
+```verilog
+genvar i;
+generate
+ for (i = 0; i < 4; i = i + 1) begin: my_block
+ ...
+ end
+endgenerate
+```
+
+The `generate`/`endgenerate` keywords are optional in SystemVerilog, so this can be:
+
+```verilog
+for (genvar i = 0; i < 4; i = i + 1) begin: my_block
+ ...
+end
+```",
"prompt":
"For consistency, give every generate block a short, appropriate name, and remove all uses of `generate`/`endgenerate`."
},{
"desc": "Localize declarations",
"prompt":
"Make declarations as localized as possible, for example, if a signal is only used within a generate block it should be declared within that block. Signals used only within a `for` loop that are declared outside that loop must be declared with an array dimension that provides a definition per loop instance. When moved inside the loop, this array replication should be eliminated. If the logic references the signal with an index other than the loop index, the reference can be updated to explicitly reference the signal through the other named loop index. For example:
+
+```verilog
+logic [31:0] x [3:0];
+logic [31:0] y [3:0];
+for (genvar i = 0; i < 4; i = i + 1) begin: my_block
+ assign x[i] = i;
+ assign y[i] = x[(i + 1) % 4];
+end
+```
+
+should be transformed to:
+
+```verilog
+for (genvar i = 0; i < 4; i = i + 1) begin: my_block
+ logic [31:0] x;
+ logic [31:0] y;
+ assign x = i;
+ assign y = my_block[(i + 1) % 4].x;
+end
+```"
},{
"desc": "Embed declarations in assignments",
"prompt":
"`logic` signal declarations may be follow by an assignment. Combine declarations and assignments. For example:
+
+```verilog
+logic y;
+assign y = a & b;
+```
+
+becomes:
+
+```verilog
+logic y = a & b;
+```"
},{
"desc": "Elevate declarations",
"prompt":
"Reorder the code to elevate all signal declarations to the top of the module body or to the top of the loop or conditional block containing their declaration."
},{
"desc": "Determine the signal naming conventions",
"comment": "This would work better as a code analysis step that analyzes the entire codebase.",
"prompt":
"Analyze the signal names in the code, looking for any suffixes or prefixes that might indicate the nature of the signals. Any prefixes or suffixes used to group related logic are less important. Pay particular attention to the staging of signals in the code and its relation to the signal names. Popular naming conventions might identify pipelines and pipeline stages, or they might indicate that one signal is a staged version of another signal. There might be conventions that indicate whether signals change on the rising or falling edge of the clock or have unique behavior on either edge of the clock. One convention used by the conversion process thus far is the use of the prefix `NEXT_` for signals that will immediately be flopped.
+
+It is also common to use `i` or `o` to indicate input and output signals.
+
+Add a \"naming\" string field in your response that describes the signal naming convention."
},{
"desc": "Data flow",
"comment": "This would work better as a code analysis step that analyzes the entire codebase.",
"needs": ["naming"],
"prompt":
"Analyze the code to determine how data flows through the design. Add \"LLM: ...\" comments to the code to describe this data flow. Pay attention to high-level code comments that might describe the microarchitecture of the design. You also might get hints from signal naming conventions, as described below."
},{
"desc": "Pipelines",
"needs": ["naming"],
"prompt":
"Analyze the code to determine where the design uses pipelines. In this context a pipeline involves computations or processing that is stretched out over multiple clock cycles. It could even simply be the staging of data. This processing must flow freely without any form of backpressure or stalling to be considered part of the same pipeline. Determine meaningful names for the identified pipelines. Choose a pipeline stage numbering for each such pipeline (or if one has already been determined, keep it). The first pipeline stage with any appreciable logic can be identified as stage 1. Add \"LLM: ...\" comments to the code to annotate the code with these pipeline stages.
+
+If no pipelines are identified, add a field to the response called \"pipelines\" with a value of \"none\".
+
+Pay attention to signal naming conventions that might indicate pipeline stages. These conventions have been analyzed and are described below."
},{
"desc": "Eliminate unnecessary use of reset",
"prompt":
"Often, designers apply reset more aggressively than necessary. We want to use a reset methodology where reset will be asserted for a minimum of five cycles to initialize the circuit. Analyze all places where reset is applied to force a value on a signal during reset. See if you can determine the value the signal would have if reset were not applied to it directly. If it would be the same, remove the reset assignment."
},{
"desc": "Stages",
"needs": ["naming"],
"prompt":
"Apply a signal naming convention to signals that are part of pipelines. Pay attention to \"LLM: \" comments identifying pipelines and stage numbers. Use the naming convention <name>__<PIPELINE><stage>, e.g. pc__CPU_A3 for the program counter at stage 3 of a CPU pipeline. Use upper case for pipeline mnemonics like \"CPU\" and \"A\" (for at) before the stage number. Each such signal will have an associated pipeline mnemonic and stage number. Apply this consistently such that all flip-flops produce signals with names that differ only in that the output signal has an incremented stage number. This may require renaming signals in the code."
},{
"desc": "Stage reset",
"unless": {"pipelines": "none"},
"prompt":
"We would like to use a reset methodology where reset signals traverses pipelines as data would. A pipeline carries \"transactions\" that proceed to the next stage every clock cycle. The reset signal should also traverse the pipeline in the same manner. In other words, some transactions are reset transactions.
+
+Since `reset` is held for multiple cycles, there is usually no functional impact from applying `reset` after a delay. Where `reset` is applied to pipelined logic, pipeline the reset signal, and apply the staged version of the reset signal to the appropriate pipeline stage."
},{
"desc": "TL-Verilog-formatted signal names",
"background":
"Signals in TL-Verilog are referred to as \"pipesignals\". They follow a specific naming convention:
+
+- Letters are lower case.
+- Words are separated by underscores.
+- Numbers can only appear directly following words.
+- The name must be at least two characters long, and those first two characters must be letters.
+
+For example: 'data_op2'.",
"prompt":
"Update the names of signals in the design to adhere to the TL-Verilog naming convention. Some existing signals will have a suffix indicating their pipelines and pipeline stages. These use the naming convention <name>__<PIPELINE><stage>, e.g. pc__CPU_A3 for the program counter at stage 3 of a CPU pipeline. For these signals, correct the <name> portion without modifying the part after `__`. For single-letter signal names like `a`, consider using a more descriptive name or `aa`."
}]