-
Notifications
You must be signed in to change notification settings - Fork 175
/
chisel.04.06.15.txt
207 lines (159 loc) · 7.71 KB
/
chisel.04.06.15.txt
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
===================================
Supporting Memory Variety in FIRRTL
===================================
----------- Masks? ------------------
== High FIRRTL ==
mem m : { tag : UInt<10> data : UInt<128> }[32]
accessor w = m[i]
== Low FIRRTL ==
mem m : { tag : UInt<10>[32] data : UInt<128>[32] }
wire w#tag : UInt<10>
wire w#data : UInt<128>
WritePort(m.tag,i,en*) := w#tag
WritePort(m.data,i,en*) := w#data
== Example Backend == ;Keep merged mem for masks, easy because mem declaration preserves bundle type
mem m : UInt<138>[32]
wire w : UInt<138>
wire w#tag : UInt<10>
wire w#data : UInt<128>
w := concat(w#tag,w#concat)
MaskedWritePort(m,i,mask*) := w ; mask* calculated from enables and mem declaration
== Example Backend == ;Split mem, easy because accessors are bundle-expanded
mem m#tag : UInt<10>[32]
mem m#data : UInt<128>[32]
wire w#tag : UInt<10>
WritePort(m#tag,i,en*) := w#tag
wire w#data : UInt<128>
WritePort(m#data,i,en*) := w#data
--------- Combination/Sequential Reads? ----------
== High FIRRTL ==
cmem m-com : UInt<128>[32]
smem m-seq : UInt<128>[32]
== Low FIRRTL ==
cmem m-com : UInt<128>[32] ;FIRRTL does nothing
smem m-seq : UInt<128>[32]
--------- Read&Write Ports? ---------------
read accessor r = m[i]
write accessor w = m[i]
readwrite accessor rw = m[i]
? accessor u = m[i] /can infer read, write, but not readwrite
== Chisel ==
val m = Mem(UInt(128),32)
val rw = ReadWritePort(m,index)
== High FIRRTL ==
mem m : UInt<128>[32]
readwrite accessor rw = m[index]
== Low FIRRTL ==
mem m<1> : UInt<128>[32] ;r/w ports are always synchronous because writes always synchronous
wire rw : UInt<128>
rw := ReadWritePort(m,index,ren*,wen*)
== Backends ==
; Example of read/write to same address, can handle differently in BRAM's on FPGA,
but is undefined for SRAMs. (Specifically for Synchronous).
----------- Notes -----------------
Catch-all is to always use black boxes
We are not absorbing registers!
User registers the address input, and chisel is allowed to retime the register into the address
Not firrtl's job to autotune - that is the library writer (ASIC backend? FIRRTL library?)
e.g. FPGA backend is an executable that iterates and does DSE
================================
Supporting Annotations in FIRRTL
================================
Example pass:
We have a decoupled interface in Chisel - {data:UInt, valid:UInt, flip ready:UInt} - and want
to test our design by adding a random number of buffers between every bulk connect of this type.
== High FIRRTL ==
wire a : { data : UInt<32>, valid : UInt<1>, flip ready : UInt<1> }
wire b : { data : UInt<32>, valid : UInt<1>, flip ready : UInt<1> }
b := a
== Low FIRRTL, no FIFO PASS ==
wire a#data : UInt<32>
wire a#valid : UInt<1>
wire a#ready : UInt<1>
wire b#data : UInt<32>
wire b#valid : UInt<1>
wire b#ready : UInt<1>
b#data := a#data
b#valid := a#valid
a#ready := b#ready
== High FIRRTL after FIFO Pass ==
wire a : { data : UInt, valid : UInt, flip ready : UInt }
reg r : { data : UInt, valid : UInt, flip ready : UInt }
wire b : { data : UInt, valid : UInt, flip ready : UInt }
r := a
b := r
== Low FIRRTL after FIFO Pass ==
wire a#data : UInt<32>
wire a#valid : UInt<1>
wire a#ready : UInt<1>
wire b#data : UInt<32>
wire b#valid : UInt<1>
wire b#ready : UInt<1>
reg r#data : UInt<32>
reg r#valid : UInt<1>
reg r#ready : UInt<1>
r#data := a#data
r#valid := a#valid
a#ready := r#ready
b#data := r#data
b#valid := r#valid
r#ready := b#ready
-------- Option 1: Only Unique IDs --------
FIRRTL provides no support for annotations, except guaranteeing that each node has a unique id.
-------------------------------------------
Generator Pass Structure:
Walk tree and build hashtable of symbol => boolean, where each reference's id matches a symbol, and the boolean is true if the type of the reference matches the decoupled interface.
Consumer Pass Structure:
Walk tree and for any ':=', check if both references are in table. If so, insert a random number of buffers
Points:
+ Very simple to implement.
- If generator operates on high firrtl and consumer operates on low firrtl, bundle-expansion breaks the consumer pass. Whose fault is it??
- Can't pass annotations from front-end to back-end in the tree, but in auxilliary data structure, which can become out of date.
TLDR: Onus is on generator pass to make it robust. Middle passes can screw things up. Easiest.
-------- Option 2: Typed Annotations ---------
FIRRTL has (order of) 10 types of annotations with known propagation properties; each pass must state which types of annotations are preserved, which are generated, and which are broken.
----------------------------------------------
Generator Pass Structure:
Walk tree and annotate all nodes that match the decoupled interface with an annotation type that propagates through bundle expansion
Consumer Pass Structure:
Walk tree and for an ':=', check if both references contain generated annotation. If so, insert a random number of buffers.
Points:
+ Clear assignment of blame - notion of support for annotations can keep passes/people responsible
- Requires thinking critically about all types of annotations that will be needed. Adds additional work to every pass.
- Pass complexity is associated with number of annotation types, not actual pass algorithm
TLDR: Onus is shared between all passes. May limit types of annotations. Strong assignment of blame.
-------- Option 3: History Trees ----------
FIRRTL records all graph transformations (think git), where nodes have pointers to deleted/replaced nodes. A pass can walk the history graph to understand how previous passes mutated the graph (and its annotations).
-------------------------------------------
Generator Pass Structure:
Walk tree and annotate all nodes that match the decoupled interface.
Consumer Pass Structure:
Walk tree and for an ':=', look at both node's history to find any ancestor node which was annotated. If so, insert random number of buffers.
Points:
+ Intermediate passes can be oblivious to all annotations.
- Hard to write consumer pass correctly, because arbitrary passes could really mess with the graph. Need significant FIRRTL support for maintaining history table, and all passes must correctly use API to ensure history is indeed correct. Hard to assign blame.
- If ever restructure upstream passes, could very easily break downstream passes because can depend on history as well as the tree
TLDR: Onus is on consumer pass. Requires significant support from FIRRTL.
--------- Option 4: Annotation Propogation Passes ----------
Each FIRRTL pass constructs a table mapping unique id nodes from the old circuit to a list of unique id nodes in the new circuit. The annotation writer writes a pass that uses this table, the old circuit, and the new circuit to create a new circuit with the correct annotations.
------------------------------------------------------------
Generator Pass Structure:
Walk tree and annotate all nodes that match the decoupled interface
Propagation Pass Structure:
Per row in the annotation table, add the annotation from the old circuit's id to each node in the new circuit that match the list of nodes.
Consumer Pass Structure:
Walk tree and for each ':=', look at both node's annotations and, if contains correct annotation, insert random number of buffers.
Points:
+ Passes remain simple - only need to create table
+ Simple passes makes writing the annotation propogation pass easier
- Up to annotation writer to validate whether a pass's constructed annotation table is correct
Debug info
Tagged Decoupled
Layout ideas
Daisy chains
Simulation annotations
Probability distribution of values
After inlining, what module things came from
Inline Module
ensure_combinational Module
throw/catch exceptions (more fanciful); on wire declaration