1use crate::conv::Context;
2use crate::ir::assign_table::{AssignContext, AssignTable};
3use crate::ir::ff_table::FfTable;
4use crate::ir::{
5 AssignDestination, Comptime, Expression, IrResult, Shape, Type, TypeKind, ValueVariant,
6 VarPathSelect,
7};
8use crate::value::Value;
9use crate::{AnalyzerError, BigUint, ir_error};
10use std::fmt;
11use veryl_parser::resource_table::StrId;
12use veryl_parser::token_range::TokenRange;
13
14#[derive(Clone, Debug)]
15pub struct Input(pub Expression);
16
17impl fmt::Display for Input {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 self.0.fmt(f)
20 }
21}
22
23#[derive(Clone, Debug)]
24pub struct Output(pub Vec<AssignDestination>);
25
26impl fmt::Display for Output {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 let mut ret = String::new();
29
30 if self.0.len() == 1 {
31 ret.push_str(&format!("{}", self.0[0]));
32 } else if !self.0.is_empty() {
33 ret.push_str(&format!("{{{}", self.0[0]));
34 for d in &self.0[1..] {
35 ret.push_str(&format!(", {}", d));
36 }
37 ret.push_str("}}");
38 }
39
40 ret.fmt(f)
41 }
42}
43
44#[derive(Clone, Debug)]
45pub struct SystemFunctionCall {
46 pub kind: SystemFunctionKind,
47 pub comptime: Comptime,
48}
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq)]
51pub enum AssertKind {
52 Fatal,
53 Continue,
54}
55
56impl AssertKind {
57 pub fn as_str(&self) -> &'static str {
58 match self {
59 AssertKind::Fatal => "$assert",
60 AssertKind::Continue => "$assert_continue",
61 }
62 }
63}
64
65#[derive(Clone, Debug)]
66pub enum SystemFunctionKind {
67 Bits(Input),
68 Size(Input),
69 Clog2(Input),
70 Onehot(Input),
71 Readmemh(Input, Output),
72 Display(Vec<Input>),
73 Write(Vec<Input>),
74 Assert {
75 kind: AssertKind,
76 cond: Input,
77 args: Vec<Input>,
78 },
79 Finish,
80 Signed(Input),
81 Unsigned(Input),
82}
83
84fn create_input(
85 context: &mut Context,
86 name: StrId,
87 r#type: Option<Type>,
88 arg: (Expression, Vec<VarPathSelect>, TokenRange),
89) -> Input {
90 let (mut expr, _, token) = arg;
91
92 let comptime = expr.eval_comptime(context, None);
94 if let Some(r#type) = r#type
95 && !r#type.compatible(comptime)
96 {
97 context.insert_error(AnalyzerError::mismatch_function_arg(
98 &name.to_string(),
99 &comptime.r#type.to_string(),
100 &token,
101 ));
102 }
103
104 Input(expr)
105}
106
107fn create_output(
108 context: &mut Context,
109 name: StrId,
110 r#type: Option<Type>,
111 arg: (Expression, Vec<VarPathSelect>, TokenRange),
112) -> Output {
113 let (mut expr, dst, token) = arg;
114
115 let dst = dst
116 .into_iter()
117 .filter_map(|x| x.to_assign_destination(context, false))
118 .collect();
119
120 if let Some(r#type) = r#type {
121 let comptime = expr.eval_comptime(context, None);
122 if !r#type.compatible(comptime) {
123 context.insert_error(AnalyzerError::mismatch_function_arg(
124 &name.to_string(),
125 &comptime.r#type.to_string(),
126 &token,
127 ));
128 }
129 }
130
131 Output(dst)
132}
133
134impl SystemFunctionCall {
135 pub fn new(
136 context: &mut Context,
137 name: StrId,
138 mut args: Vec<(Expression, Vec<VarPathSelect>, TokenRange)>,
139 token: TokenRange,
140 ) -> IrResult<Self> {
141 let mut comptime = Comptime::create_unknown(token);
142 comptime.is_const = true;
143
144 match name.to_string().as_str() {
145 "$bits" => {
146 if args.len() != 1 {
147 context.insert_error(AnalyzerError::mismatch_function_arity(
148 "$bits",
149 1,
150 args.len(),
151 &token,
152 ));
153 return Err(ir_error!(token));
154 }
155 let arg0 = create_input(context, name, None, args.remove(0));
156 Ok(SystemFunctionCall {
157 kind: SystemFunctionKind::Bits(arg0),
158 comptime,
159 })
160 }
161 "$size" => {
162 if args.len() != 1 {
163 context.insert_error(AnalyzerError::mismatch_function_arity(
164 "$size",
165 1,
166 args.len(),
167 &token,
168 ));
169 return Err(ir_error!(token));
170 }
171 let arg0 = create_input(context, name, None, args.remove(0));
172 Ok(SystemFunctionCall {
173 kind: SystemFunctionKind::Size(arg0),
174 comptime,
175 })
176 }
177 "$clog2" => {
178 if args.len() != 1 {
179 context.insert_error(AnalyzerError::mismatch_function_arity(
180 "$clog2",
181 1,
182 args.len(),
183 &token,
184 ));
185 return Err(ir_error!(token));
186 }
187 let arg0_type = {
188 let mut t = Type::new(TypeKind::Logic);
189 t.set_concrete_width(Shape::new(vec![Some(32)]));
190 t
191 };
192 let arg0 = create_input(context, name, Some(arg0_type), args.remove(0));
193 Ok(SystemFunctionCall {
194 kind: SystemFunctionKind::Clog2(arg0),
195 comptime,
196 })
197 }
198 "$onehot" => {
199 if args.len() != 1 {
200 context.insert_error(AnalyzerError::mismatch_function_arity(
201 "$onehot",
202 1,
203 args.len(),
204 &token,
205 ));
206 return Err(ir_error!(token));
207 }
208 let arg0_type = {
209 let mut t = Type::new(TypeKind::Logic);
210 t.set_concrete_width(Shape::new(vec![Some(32)]));
211 t
212 };
213 let arg0 = create_input(context, name, Some(arg0_type), args.remove(0));
214 Ok(SystemFunctionCall {
215 kind: SystemFunctionKind::Onehot(arg0),
216 comptime,
217 })
218 }
219 "$readmemh" => {
220 if args.len() != 2 {
221 context.insert_error(AnalyzerError::mismatch_function_arity(
222 "$readmemh",
223 2,
224 args.len(),
225 &token,
226 ));
227 return Err(ir_error!(token));
228 }
229 let arg0 = create_input(context, name, None, args.remove(0));
230 let arg1 = create_output(context, name, None, args.remove(0));
231 Ok(SystemFunctionCall {
232 kind: SystemFunctionKind::Readmemh(arg0, arg1),
233 comptime,
234 })
235 }
236 "$display" => {
237 let inputs: Vec<Input> = args
238 .into_iter()
239 .map(|arg| create_input(context, name, None, arg))
240 .collect();
241 Ok(SystemFunctionCall {
242 kind: SystemFunctionKind::Display(inputs),
243 comptime,
244 })
245 }
246 "$write" => {
247 let inputs: Vec<Input> = args
248 .into_iter()
249 .map(|arg| create_input(context, name, None, arg))
250 .collect();
251 Ok(SystemFunctionCall {
252 kind: SystemFunctionKind::Write(inputs),
253 comptime,
254 })
255 }
256 "$assert" | "$assert_continue" => {
257 if args.is_empty() {
258 context.insert_error(AnalyzerError::mismatch_function_arity(
259 &name.to_string(),
260 1,
261 0,
262 &token,
263 ));
264 return Err(ir_error!(token));
265 }
266 let kind = if name.to_string() == "$assert_continue" {
267 AssertKind::Continue
268 } else {
269 AssertKind::Fatal
270 };
271 let cond = create_input(context, name, None, args.remove(0));
272 let args: Vec<Input> = args
273 .into_iter()
274 .map(|arg| create_input(context, name, None, arg))
275 .collect();
276 Ok(SystemFunctionCall {
277 kind: SystemFunctionKind::Assert { kind, cond, args },
278 comptime,
279 })
280 }
281 "$finish" => {
282 if !args.is_empty() {
283 return Err(ir_error!(token));
284 }
285 Ok(SystemFunctionCall {
286 kind: SystemFunctionKind::Finish,
287 comptime,
288 })
289 }
290 "$signed" => {
291 if args.len() != 1 {
292 return Err(ir_error!(token));
293 }
294
295 let mut arg = args.remove(0);
296 arg.0.eval_comptime(context, None);
297
298 let arg0 = create_input(context, name, None, arg);
299 comptime.expr_context.signed = true;
300
301 Ok(SystemFunctionCall {
302 kind: SystemFunctionKind::Signed(arg0),
303 comptime,
304 })
305 }
306 "$unsigned" => {
307 if args.len() != 1 {
308 return Err(ir_error!(token));
309 }
310
311 let mut arg = args.remove(0);
312 arg.0.eval_comptime(context, None);
313
314 let arg0 = create_input(context, name, None, arg);
315 comptime.expr_context.signed = false;
316
317 Ok(SystemFunctionCall {
318 kind: SystemFunctionKind::Unsigned(arg0),
319 comptime,
320 })
321 }
322 _ => Err(ir_error!(token)),
323 }
324 }
325
326 pub fn eval_value(&self, context: &mut Context) -> Option<Value> {
327 match &self.kind {
328 SystemFunctionKind::Bits(x) => {
329 let mut expr = x.0.clone();
330 let comptime = expr.eval_comptime(context, None);
331 let value = match &comptime.value {
332 ValueVariant::Numeric(_) => comptime.r#type.total_width(),
333 ValueVariant::Type(x) => x.total_width(),
334 _ => None,
335 };
336 value.map(|x| Value::new(x as u64, 32, false))
337 }
338 SystemFunctionKind::Size(x) => {
339 let mut expr = x.0.clone();
340 let comptime = expr.eval_comptime(context, None);
341 let value = match &comptime.value {
342 ValueVariant::Numeric(_) => comptime.r#type.total_width(),
343 ValueVariant::Type(x) => x.total_width(),
344 _ => None,
345 };
346 value.map(|x| Value::new(x as u64, 32, false))
347 }
348 SystemFunctionKind::Clog2(x) => {
349 let value = x.0.eval_value(context)?;
350 let value = value.payload();
351 let ret = if value.as_ref() == &BigUint::from(0u32) {
352 BigUint::from(0u32)
353 } else {
354 value.as_ref() - BigUint::from(1u32)
355 };
356 Some(Value::new(ret.bits(), 32, false))
357 }
358 SystemFunctionKind::Onehot(x) => {
359 let value = x.0.eval_value(context)?;
360 let ret = value.payload().count_ones() == 1;
361 Some(Value::new(ret.into(), 1, false))
362 }
363 SystemFunctionKind::Readmemh(_, _) => None,
364 SystemFunctionKind::Display(_) => None,
365 SystemFunctionKind::Write(_) => None,
366 SystemFunctionKind::Assert { .. } => None,
367 SystemFunctionKind::Finish => None,
368 SystemFunctionKind::Signed(x) | SystemFunctionKind::Unsigned(x) => {
369 x.0.eval_value(context)
370 }
371 }
372 }
373
374 pub fn eval_comptime(&self, context: &mut Context) -> Comptime {
375 let value = self.eval_value(context);
376 match &self.kind {
377 SystemFunctionKind::Bits(_)
378 | SystemFunctionKind::Size(_)
379 | SystemFunctionKind::Clog2(_)
380 | SystemFunctionKind::Onehot(_) => {
381 let mut ret = self.comptime.clone();
382 if let Some(x) = value {
383 ret.value = ValueVariant::Numeric(x);
384 }
385 ret
386 }
387 SystemFunctionKind::Readmemh(_, _) => self.comptime.clone(),
388 SystemFunctionKind::Display(_) => self.comptime.clone(),
389 SystemFunctionKind::Write(_) => self.comptime.clone(),
390 SystemFunctionKind::Assert { .. } => self.comptime.clone(),
391 SystemFunctionKind::Finish => self.comptime.clone(),
392 SystemFunctionKind::Signed(_) | SystemFunctionKind::Unsigned(_) => {
393 let mut ret = self.comptime.clone();
394 if let Some(x) = value {
395 ret.value = ValueVariant::Numeric(x);
396 }
397 ret
398 }
399 }
400 }
401
402 pub fn eval_assign(
403 &self,
404 context: &mut Context,
405 assign_table: &mut AssignTable,
406 assign_context: AssignContext,
407 ) {
408 if let SystemFunctionKind::Readmemh(_, x) = &self.kind {
409 for x in &x.0 {
410 x.eval_assign(context, assign_table, assign_context);
411 }
412 }
413 }
414}
415
416impl fmt::Display for SystemFunctionCall {
417 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418 match &self.kind {
419 SystemFunctionKind::Bits(x) => format!("$bits({x})").fmt(f),
420 SystemFunctionKind::Size(x) => format!("$size({x})").fmt(f),
421 SystemFunctionKind::Clog2(x) => format!("$clog2({x})").fmt(f),
422 SystemFunctionKind::Onehot(x) => format!("$onehot({x})").fmt(f),
423 SystemFunctionKind::Readmemh(x, y) => format!("$readmemh({x}, {y})").fmt(f),
424 SystemFunctionKind::Display(args) => {
425 let args_str: Vec<_> = args.iter().map(|a| format!("{a}")).collect();
426 format!("$display({})", args_str.join(", ")).fmt(f)
427 }
428 SystemFunctionKind::Write(args) => {
429 let args_str: Vec<_> = args.iter().map(|a| format!("{a}")).collect();
430 format!("$write({})", args_str.join(", ")).fmt(f)
431 }
432 SystemFunctionKind::Assert { kind, cond, args } => {
433 let name = kind.as_str();
434 if args.is_empty() {
435 format!("{name}({cond})").fmt(f)
436 } else {
437 let args_str: Vec<_> = args.iter().map(|a| format!("{a}")).collect();
438 format!("{name}({cond}, {})", args_str.join(", ")).fmt(f)
439 }
440 }
441 SystemFunctionKind::Finish => "$finish()".fmt(f),
442 SystemFunctionKind::Signed(x) => format!("$signed({x})").fmt(f),
443 SystemFunctionKind::Unsigned(x) => format!("$unsigned({x})").fmt(f),
444 }
445 }
446}
447
448impl SystemFunctionCall {
449 pub fn gather_ff(
450 &self,
451 context: &mut Context,
452 table: &mut FfTable,
453 decl: usize,
454 from_ff: bool,
455 ) {
456 let process_input = |input: &Input, context: &mut Context, table: &mut FfTable| {
457 input.0.gather_ff(context, table, decl, None, from_ff);
458 };
459 match &self.kind {
460 SystemFunctionKind::Bits(x)
461 | SystemFunctionKind::Size(x)
462 | SystemFunctionKind::Clog2(x)
463 | SystemFunctionKind::Onehot(x)
464 | SystemFunctionKind::Signed(x)
465 | SystemFunctionKind::Unsigned(x) => {
466 process_input(x, context, table);
467 }
468 SystemFunctionKind::Readmemh(_, _) => {
469 }
472 SystemFunctionKind::Display(args) | SystemFunctionKind::Write(args) => {
473 for arg in args {
474 process_input(arg, context, table);
475 }
476 }
477 SystemFunctionKind::Assert { cond, args, .. } => {
478 process_input(cond, context, table);
479 for arg in args {
480 process_input(arg, context, table);
481 }
482 }
483 SystemFunctionKind::Finish => {}
484 }
485 }
486}