1use crate::conv::Context;
2use crate::ir::assign_table::{AssignContext, AssignTable};
3use crate::ir::{
4 AssignDestination, Component, Comptime, Expression, FfTable, Statement, VarId, VarIndex,
5 VarSelect,
6};
7use indent::indent_all_by;
8use std::fmt;
9use std::sync::Arc;
10use veryl_parser::resource_table::StrId;
11use veryl_parser::token_range::TokenRange;
12
13#[derive(Clone, Default)]
14pub struct DeclarationBlock(pub Vec<Declaration>);
15
16impl DeclarationBlock {
17 pub fn new(decl: Declaration) -> Self {
18 Self(vec![decl])
19 }
20}
21
22#[derive(Clone)]
23pub enum Declaration {
24 Comb(CombDeclaration),
25 Ff(Box<FfDeclaration>),
26 Inst(Box<InstDeclaration>),
27 Initial(InitialDeclaration),
28 Final(FinalDeclaration),
29 Unsupported(TokenRange),
30 Null,
31}
32
33impl Declaration {
34 pub fn new_comb(statements: Vec<Statement>) -> Self {
35 Self::Comb(CombDeclaration { statements })
36 }
37
38 pub fn new_ff(clock: FfClock, reset: Option<FfReset>, statements: Vec<Statement>) -> Self {
39 Self::Ff(Box::new(FfDeclaration {
40 clock,
41 reset,
42 statements,
43 }))
44 }
45
46 pub fn is_null(&self) -> bool {
47 matches!(self, Declaration::Null)
48 }
49
50 pub fn eval_assign(&self, context: &mut Context, assign_table: &mut AssignTable) {
51 match self {
52 Declaration::Comb(x) => x.eval_assign(context, assign_table),
53 Declaration::Ff(x) => x.eval_assign(context, assign_table),
54 Declaration::Inst(x) => x.eval_assign(context, assign_table),
55 Declaration::Initial(x) => x.eval_assign(context, assign_table),
56 Declaration::Final(x) => x.eval_assign(context, assign_table),
57 Declaration::Unsupported(_) => (),
58 Declaration::Null => (),
59 }
60 assign_table.refernced.clear();
61 }
62
63 pub fn gather_ff(&self, context: &mut Context, table: &mut FfTable, decl: usize) {
64 match self {
65 Declaration::Ff(x) => x.gather_ff(context, table, decl),
66 Declaration::Comb(x) => x.gather_ff_comb(context, table, decl),
67 Declaration::Inst(x) => x.gather_ff(context, table, decl),
68 _ => {}
69 }
70 }
71}
72
73impl fmt::Display for Declaration {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 match self {
76 Declaration::Comb(x) => x.fmt(f),
77 Declaration::Ff(x) => x.fmt(f),
78 Declaration::Inst(x) => x.fmt(f),
79 Declaration::Initial(x) => x.fmt(f),
80 Declaration::Final(x) => x.fmt(f),
81 Declaration::Unsupported(_) => "/* unsupported */".fmt(f),
82 Declaration::Null => "".fmt(f),
83 }
84 }
85}
86
87#[derive(Clone)]
88pub struct CombDeclaration {
89 pub statements: Vec<Statement>,
90}
91
92impl CombDeclaration {
93 pub fn eval_assign(&self, context: &mut Context, assign_table: &mut AssignTable) {
94 for x in &self.statements {
95 x.eval_assign(context, assign_table, AssignContext::Comb, &[]);
96 }
97 }
98
99 pub fn gather_ff_comb(&self, context: &mut Context, table: &mut FfTable, decl: usize) {
100 for x in &self.statements {
101 x.gather_ff_comb_assign(context, table, decl);
102 }
103 }
104}
105
106impl fmt::Display for CombDeclaration {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 let mut ret = "comb {\n".to_string();
109
110 for x in &self.statements {
111 let text = format!("{}\n", x);
112 ret.push_str(&indent_all_by(2, text));
113 }
114
115 ret.push('}');
116 ret.fmt(f)
117 }
118}
119
120#[derive(Clone)]
121pub struct FfClock {
122 pub id: VarId,
123 pub index: VarIndex,
124 pub select: VarSelect,
125 pub comptime: Comptime,
126}
127
128impl fmt::Display for FfClock {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 format!("{}{}{}", self.id, self.index, self.select).fmt(f)
131 }
132}
133
134#[derive(Clone)]
135pub struct FfReset {
136 pub id: VarId,
137 pub index: VarIndex,
138 pub select: VarSelect,
139 pub comptime: Comptime,
140}
141
142impl fmt::Display for FfReset {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 format!("{}{}{}", self.id, self.index, self.select).fmt(f)
145 }
146}
147
148#[derive(Clone)]
149pub struct FfDeclaration {
150 pub clock: FfClock,
151 pub reset: Option<FfReset>,
152 pub statements: Vec<Statement>,
153}
154
155impl FfDeclaration {
156 pub fn eval_assign(&self, context: &mut Context, assign_table: &mut AssignTable) {
157 for x in &self.statements {
158 x.eval_assign(context, assign_table, AssignContext::Ff, &[]);
159 }
160 }
161
162 pub fn gather_ff(&self, context: &mut Context, table: &mut FfTable, decl: usize) {
163 for x in &self.statements {
164 x.gather_ff(context, table, decl);
165 }
166 }
167}
168
169impl fmt::Display for FfDeclaration {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 let mut ret = if let Some(x) = &self.reset {
172 format!("ff ({}, {}) {{\n", self.clock, x)
173 } else {
174 format!("ff ({}) {{\n", self.clock)
175 };
176
177 for x in &self.statements {
178 let text = format!("{}\n", x);
179 ret.push_str(&indent_all_by(2, text));
180 }
181
182 ret.push('}');
183 ret.fmt(f)
184 }
185}
186
187#[derive(Clone)]
188pub struct InstInput {
189 pub id: VarId,
190 pub expr: Expression,
191}
192
193impl fmt::Display for InstInput {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 write!(f, "{} <- {}", self.id, self.expr)
196 }
197}
198
199#[derive(Clone)]
200pub struct InstOutput {
201 pub id: VarId,
202 pub dst: Vec<AssignDestination>,
203}
204
205impl fmt::Display for InstOutput {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 let mut ret = format!("{} -> ", self.id);
208
209 if self.dst.len() == 1 {
210 ret.push_str(&format!("{}", self.dst[0]));
211 } else if !self.dst.is_empty() {
212 ret.push_str(&format!("{{{}", self.dst[0]));
213 for d in &self.dst[1..] {
214 ret.push_str(&format!(", {}", d));
215 }
216 ret.push('}');
217 }
218
219 ret.fmt(f)
220 }
221}
222
223#[derive(Clone)]
224pub struct InstDeclaration {
225 pub name: StrId,
226 pub inputs: Vec<InstInput>,
227 pub outputs: Vec<InstOutput>,
228 pub component: Arc<Component>,
231}
232
233impl InstDeclaration {
234 pub fn eval_assign(&self, context: &mut Context, assign_table: &mut AssignTable) {
235 for x in &self.outputs {
236 for dst in &x.dst {
237 dst.eval_assign(context, assign_table, AssignContext::Ff);
238 }
239 }
240
241 if let Component::SystemVerilog(x) = self.component.as_ref() {
242 for dst in &x.connects {
243 dst.eval_assign(context, assign_table, AssignContext::SystemVerilog);
244 }
245 }
246 }
247
248 pub fn gather_ff(&self, context: &mut Context, table: &mut FfTable, decl: usize) {
254 for input in &self.inputs {
255 input.expr.gather_ff(context, table, decl, None, false);
256 }
257 }
258}
259
260impl fmt::Display for InstDeclaration {
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 let mut ret = format!("inst {} (\n", self.name);
263
264 for x in &self.inputs {
265 let text = format!("{};\n", x);
266 ret.push_str(&indent_all_by(2, text));
267 }
268
269 for x in &self.outputs {
270 let text = format!("{};\n", x);
271 ret.push_str(&indent_all_by(2, text));
272 }
273
274 ret.push_str(") {\n");
275
276 let text = format!("{}\n", self.component);
277 ret.push_str(&indent_all_by(2, text));
278
279 ret.push('}');
280 ret.fmt(f)
281 }
282}
283
284#[derive(Clone)]
285pub struct InitialDeclaration {
286 pub statements: Vec<Statement>,
287}
288
289impl InitialDeclaration {
290 pub fn eval_assign(&self, context: &mut Context, assign_table: &mut AssignTable) {
291 for x in &self.statements {
292 x.eval_assign(context, assign_table, AssignContext::Initial, &[]);
293 }
294 }
295}
296
297impl fmt::Display for InitialDeclaration {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 let mut ret = "initial {\n".to_string();
300
301 for x in &self.statements {
302 let text = format!("{}\n", x);
303 ret.push_str(&indent_all_by(2, text));
304 }
305
306 ret.push('}');
307 ret.fmt(f)
308 }
309}
310
311#[derive(Clone)]
312pub struct FinalDeclaration {
313 pub statements: Vec<Statement>,
314}
315
316impl FinalDeclaration {
317 pub fn eval_assign(&self, context: &mut Context, assign_table: &mut AssignTable) {
318 for x in &self.statements {
319 x.eval_assign(context, assign_table, AssignContext::Final, &[]);
320 }
321 }
322}
323
324impl fmt::Display for FinalDeclaration {
325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 let mut ret = "final {\n".to_string();
327
328 for x in &self.statements {
329 let text = format!("{}\n", x);
330 ret.push_str(&indent_all_by(2, text));
331 }
332
333 ret.push('}');
334 ret.fmt(f)
335 }
336}