1use std::collections::HashMap;
34use std::error::Error;
35use std::fmt;
36
37use isla_lib::bitvector::BV;
38use isla_lib::config::ISAConfig;
39use isla_lib::ir::{Name, SharedState, Val};
40use isla_lib::smt::{EvPath, Event};
41
42pub type ThreadId = usize;
43
44pub struct Candidates<'ev, B> {
46 index: Vec<usize>,
47 max_index: Vec<usize>,
48 threads: &'ev [Vec<EvPath<B>>],
49 out_of_bounds: bool,
50}
51
52impl<'ev, B: BV> Candidates<'ev, B> {
53 pub fn new(threads: &'ev [Vec<EvPath<B>>]) -> Self {
56 Candidates {
57 index: vec![0; threads.len()],
58 max_index: threads.iter().map(|t| t.len()).collect(),
59 threads,
60 out_of_bounds: !threads.iter().all(|t| !t.is_empty()),
61 }
62 }
63
64 pub fn total(&self) -> usize {
65 if self.threads.is_empty() {
66 0
67 } else {
68 self.max_index.iter().product()
69 }
70 }
71}
72
73fn increment_index(index: &mut [usize], max_index: &[usize], carry: usize) -> bool {
74 if carry == index.len() {
75 return true;
76 }
77
78 index[carry] += 1;
79 if index[carry] == max_index[carry] {
80 index[carry] = 0;
81 increment_index(index, max_index, carry + 1)
82 } else {
83 false
84 }
85}
86
87impl<'ev, B: BV> Iterator for Candidates<'ev, B> {
88 type Item = Vec<&'ev [Event<B>]>;
89
90 fn next(&mut self) -> Option<Self::Item> {
91 if self.out_of_bounds {
92 None
93 } else {
94 let mut result = Vec::with_capacity(self.threads.len());
95 self.threads.iter().zip(self.index.iter()).for_each(|(thread, i)| result.push(thread[*i].as_ref()));
96 self.out_of_bounds = increment_index(&mut self.index, &self.max_index, 0);
97 Some(result)
98 }
99 }
100}
101
102pub struct Pairs<'a, A> {
103 index: (usize, usize),
104 slice: &'a [A],
105}
106
107impl<'a, A> Pairs<'a, A> {
108 pub fn from_slice(slice: &'a [A]) -> Self {
109 Pairs { index: (0, 0), slice }
110 }
111}
112
113impl<'a, A> Iterator for Pairs<'a, A> {
114 type Item = (&'a A, &'a A);
115
116 fn next(&mut self) -> Option<Self::Item> {
117 self.index.1 += 1;
118 if self.index.1 > self.slice.len() {
119 self.index.1 = 1;
120 self.index.0 += 1;
121 }
122 if self.index.0 >= self.slice.len() {
123 return None;
124 }
125 Some((&self.slice[self.index.0], &self.slice[self.index.1 - 1]))
126 }
127}
128
129#[derive(Debug)]
134pub struct AxEvent<'a, B> {
135 pub opcode: B,
137 pub po: usize,
139 pub intra_instruction_order: usize,
142 pub thread_id: ThreadId,
144 pub name: String,
146 pub base: &'a Event<B>,
148 pub is_ifetch: bool,
150}
151
152impl<'a, B: BV> AxEvent<'a, B> {
153 pub fn address(&self) -> Option<&'a Val<B>> {
154 match self.base {
155 Event::ReadMem { address, .. } | Event::WriteMem { address, .. } | Event::CacheOp { address, .. } => {
156 Some(address)
157 }
158 _ => None,
159 }
160 }
161
162 pub fn read_value(&self) -> Option<(&'a Val<B>, u32)> {
163 match self.base {
164 Event::ReadMem { value, bytes, .. } => Some((value, *bytes)),
165 _ => None,
166 }
167 }
168
169 pub fn write_data(&self) -> Option<(&'a Val<B>, u32)> {
170 match self.base {
171 Event::WriteMem { data, bytes, .. } => Some((data, *bytes)),
172 _ => None,
173 }
174 }
175}
176
177pub mod relations {
178 use std::collections::HashMap;
179
180 use isla_lib::bitvector::BV;
181 use isla_lib::smt::Event;
182
183 use super::AxEvent;
184 use crate::footprint_analysis::{addr_dep, ctrl_dep, data_dep, rmw_dep, Footprint};
185
186 pub fn is_write<B: BV>(ev: &AxEvent<B>) -> bool {
187 ev.base.is_memory_write()
188 }
189
190 pub fn is_s1_translate<B: BV>(ev: &AxEvent<B>) -> bool {
191 if let Event::ReadMem { kind, .. } = ev.base {
192 kind == &"stage 1"
193 } else {
194 false
195 }
196 }
197
198 pub fn is_s2_translate<B: BV>(ev: &AxEvent<B>) -> bool {
199 if let Event::ReadMem { kind, .. } = ev.base {
200 kind == &"stage 2"
201 } else {
202 false
203 }
204 }
205
206 pub fn is_translate<B: BV>(ev: &AxEvent<B>) -> bool {
207 is_s1_translate(ev) || is_s2_translate(ev)
208 }
209
210 pub fn is_read<B: BV>(ev: &AxEvent<B>) -> bool {
211 !is_translate(ev) && !ev.is_ifetch && ev.base.is_memory_read()
212 }
213
214 pub fn is_barrier<B: BV>(ev: &AxEvent<B>) -> bool {
215 ev.base.is_barrier()
216 }
217
218 pub fn is_ifetch<B: BV>(ev: &AxEvent<B>) -> bool {
219 ev.is_ifetch
220 }
221
222 pub fn is_cache_op<B: BV>(ev: &AxEvent<B>) -> bool {
223 ev.base.is_cache_op()
224 }
225
226 pub fn amo<B: BV>(_ev1: &AxEvent<B>, _ev2: &AxEvent<B>) -> bool {
228 false
229 }
230
231 pub fn univ<B: BV>(_: &AxEvent<B>, _: &AxEvent<B>) -> bool {
232 true
233 }
234
235 pub fn disjoint<B: BV>(ev1: &AxEvent<B>, ev2: &AxEvent<B>) -> bool {
236 ev1.po != ev2.po || ev1.thread_id != ev2.thread_id
237 }
238
239 pub fn po<B: BV>(ev1: &AxEvent<B>, ev2: &AxEvent<B>) -> bool {
240 ev1.po < ev2.po && ev1.thread_id == ev2.thread_id
241 }
242
243 pub fn intra_instruction_ordered<B: BV>(ev1: &AxEvent<B>, ev2: &AxEvent<B>) -> bool {
244 ev1.po == ev2.po && ev1.thread_id == ev2.thread_id && ev1.intra_instruction_order < ev2.intra_instruction_order
245 }
246
247 pub fn internal<B: BV>(ev1: &AxEvent<B>, ev2: &AxEvent<B>) -> bool {
248 ev1.po != ev2.po && ev1.thread_id == ev2.thread_id
249 }
250
251 pub fn external<B: BV>(ev1: &AxEvent<B>, ev2: &AxEvent<B>) -> bool {
252 ev1.po != ev2.po && ev1.thread_id != ev2.thread_id
253 }
254
255 pub type DepRel<B> = fn(&AxEvent<B>, &AxEvent<B>, &[Vec<B>], &HashMap<B, Footprint>) -> bool;
256
257 pub fn addr<B: BV>(
258 ev1: &AxEvent<B>,
259 ev2: &AxEvent<B>,
260 thread_opcodes: &[Vec<B>],
261 footprints: &HashMap<B, Footprint>,
262 ) -> bool {
263 !ev1.is_ifetch && po(ev1, ev2) && addr_dep(ev1.po, ev2.po, &thread_opcodes[ev1.thread_id], footprints)
264 }
265
266 pub fn data<B: BV>(
267 ev1: &AxEvent<B>,
268 ev2: &AxEvent<B>,
269 thread_opcodes: &[Vec<B>],
270 footprints: &HashMap<B, Footprint>,
271 ) -> bool {
272 po(ev1, ev2) && data_dep(ev1.po, ev2.po, &thread_opcodes[ev1.thread_id], footprints)
273 }
274
275 pub fn ctrl<B: BV>(
276 ev1: &AxEvent<B>,
277 ev2: &AxEvent<B>,
278 thread_opcodes: &[Vec<B>],
279 footprints: &HashMap<B, Footprint>,
280 ) -> bool {
281 !ev1.is_ifetch && po(ev1, ev2) && ctrl_dep(ev1.po, ev2.po, &thread_opcodes[ev1.thread_id], footprints)
282 }
283
284 pub fn rmw<B: BV>(
285 ev1: &AxEvent<B>,
286 ev2: &AxEvent<B>,
287 thread_opcodes: &[Vec<B>],
288 footprints: &HashMap<B, Footprint>,
289 ) -> bool {
290 (po(ev1, ev2) || intra_instruction_ordered(ev1, ev2))
291 && rmw_dep(ev1.po, ev2.po, &thread_opcodes[ev1.thread_id], footprints)
292 }
293
294 pub fn translation_walk_order<B: BV>(
295 ev1: &AxEvent<B>,
296 ev2: &AxEvent<B>,
297 ) -> bool {
298 intra_instruction_ordered(ev1, ev2) && is_translate(ev1) && is_translate(ev2)
299 }
300}
301
302pub struct ExecutionInfo<'ev, B> {
303 pub events: Vec<AxEvent<'ev, B>>,
305 pub thread_opcodes: Vec<Vec<B>>,
307 pub final_writes: HashMap<(Name, ThreadId), &'ev Val<B>>,
309}
310
311#[derive(Debug)]
312pub enum CandidateError<B> {
313 MultipleInstructionsInCycle { opcode1: B, opcode2: B },
314 NoInstructionsInCycle,
315}
316
317impl<B: BV> fmt::Display for CandidateError<B> {
318 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
319 use CandidateError::*;
320 match self {
321 MultipleInstructionsInCycle { opcode1, opcode2 } => write!(
322 f,
323 "A single fetch-execute-decode cycle in this candidate execution was associated with multiple instructions: {} and {}",
324 opcode1,
325 opcode2
326 ),
327 NoInstructionsInCycle => write!(
328 f,
329 "A fetch-execute-decode cycle was encountered that had no associated instructions"
330 ),
331 }
332 }
333}
334
335impl<B: BV> Error for CandidateError<B> {
336 fn source(&self) -> Option<&(dyn Error + 'static)> {
337 None
338 }
339}
340
341impl<'ev, B: BV> ExecutionInfo<'ev, B> {
342 pub fn from(
343 candidate: &'ev [&[Event<B>]],
344 shared_state: &SharedState<B>,
345 isa_config: &ISAConfig<B>,
346 ) -> Result<Self, CandidateError<B>> {
347 use CandidateError::*;
348 let mut exec = ExecutionInfo {
349 events: Vec::new(),
350 thread_opcodes: vec![Vec::new(); candidate.len()],
351 final_writes: HashMap::new(),
352 };
353
354 let rk_ifetch = shared_state.enum_member(isa_config.ifetch_read_kind).expect("Invalid ifetch read kind");
355
356 for (tid, thread) in candidate.iter().enumerate() {
357 for (po, cycle) in thread.split(|ev| ev.is_cycle()).skip(1).enumerate() {
358 let mut cycle_events: Vec<(usize, usize, String, &Event<B>, bool)> = Vec::new();
359 let mut cycle_instr: Option<B> = None;
360
361 for (eid, event) in cycle.iter().enumerate() {
362 match event {
363 Event::Instr(Val::Bits(bv)) => {
364 if let Some(opcode) = cycle_instr {
365 return Err(MultipleInstructionsInCycle { opcode1: *bv, opcode2: opcode });
366 } else {
367 exec.thread_opcodes[tid].push(*bv);
368 cycle_instr = Some(*bv)
369 }
370 }
371 Event::ReadMem { read_kind: Val::Enum(e), .. } => {
372 if e.member == rk_ifetch {
373 cycle_events.push((tid, eid, format!("R{}_{}_{}", po, eid, tid), event, true))
374 } else {
375 cycle_events.push((tid, eid, format!("R{}_{}_{}", po, eid, tid), event, false))
376 }
377 }
378 Event::ReadMem { .. } => panic!("ReadMem event with non-concrete enum read_kind"),
379 Event::WriteMem { .. } => {
380 cycle_events.push((tid, eid, format!("W{}_{}_{}", po, eid, tid), event, false))
381 }
382 Event::Barrier { .. } => {
383 cycle_events.push((tid, eid, format!("F{}_{}_{}", po, eid, tid), event, false))
384 }
385 Event::CacheOp { .. } => {
386 cycle_events.push((tid, eid, format!("C{}_{}_{}", po, eid, tid), event, false))
387 }
388 Event::WriteReg(reg, _, val) => {
389 exec.final_writes.insert((*reg, tid), val);
390 }
391 _ => (),
392 }
393 }
394
395 for (tid, eid, name, ev, is_ifetch) in cycle_events {
396 if let Some(opcode) = cycle_instr {
398 exec.events.push(AxEvent {
399 opcode,
400 po,
401 intra_instruction_order: eid,
402 thread_id: tid,
403 name,
404 base: ev,
405 is_ifetch,
406 })
407 } else if !ev.has_read_kind(rk_ifetch) {
408 return Err(NoInstructionsInCycle);
410 }
411 }
412 }
413 }
414
415 Ok(exec)
416 }
417}
418
419pub mod model {
422 use std::collections::HashMap;
423
424 use isla_lib::bitvector::BV;
425 use isla_lib::ir::Val;
426
427 use super::Pairs;
428 use crate::sexp::{DefineFun, InterpretEnv, InterpretError, SexpFn, SexpVal};
429 use crate::sexp_lexer::SexpLexer;
430 use crate::sexp_parser::SexpParser;
431
432 pub struct Model<'s, 'ev, B> {
439 env: InterpretEnv<'s, 'ev, B>,
440 functions: HashMap<&'s str, SexpFn<'s>>,
441 }
442
443 impl<'s, 'ev, B: BV> Model<'s, 'ev, B> {
444 pub fn parse(events: &[&'ev str], model: &'s str) -> Option<Self> {
446 let mut env = InterpretEnv::new();
447 for event in events {
448 env.add_event(event)
449 }
450
451 let lexer = SexpLexer::new(model);
452 match SexpParser::new().parse(lexer) {
453 Ok(sexp) => match sexp.dest_fn("model") {
454 Some(function_sexps) => {
455 let mut functions = HashMap::new();
456 for f in function_sexps {
457 if let Some(DefineFun { name, params, body, .. }) = f.dest_define_fun() {
458 let params = params.iter().map(|(a, _)| *a).collect();
459 functions.insert(name, SexpFn { params, body });
460 } else {
461 return None;
462 }
463 }
464 Some(Model { env, functions })
465 }
466 None => None,
467 },
468 Err(_) => None,
469 }
470 }
471
472 pub fn interpret(&mut self, f: &str, args: &[SexpVal<'ev, B>]) -> Result<SexpVal<'ev, B>, InterpretError> {
474 let function = self.functions.get(f).ok_or_else(|| InterpretError::UnknownFunction(f.to_string()))?;
475
476 self.env.add_args(&function.params, args)?;
477 let result = function.body.interpret(&mut self.env, &self.functions)?;
478 self.env.clear_args(&function.params);
479
480 Ok(result)
481 }
482
483 pub fn interpret_rel(
488 &mut self,
489 rel: &str,
490 events: &[&'ev str],
491 ) -> Result<Vec<(&'ev str, &'ev str)>, InterpretError> {
492 let mut pairs = Vec::new();
493
494 for (ev1, ev2) in Pairs::from_slice(events) {
495 match self.interpret(rel, &[SexpVal::Event(*ev1), SexpVal::Event(ev2)])? {
496 SexpVal::Bool(true) => pairs.push((*ev1, *ev2)),
497 SexpVal::Bool(false) => (),
498 _ => return Err(InterpretError::Type(rel.to_string())),
499 }
500 }
501
502 Ok(pairs)
503 }
504
505 pub fn interpret_bits(&mut self, val: &Val<B>) -> Result<B, InterpretError> {
508 match val {
509 Val::Symbolic(v) => {
510 let smt_name = format!("v{}", v);
511 let sexp = self.interpret(&smt_name, &[])?;
512 sexp.into_bits().ok_or_else(|| InterpretError::NotFound(smt_name))
513 }
514 Val::Bits(bv) => Ok(*bv),
515 _ => Err(InterpretError::Type("interpret_bv".to_string())),
516 }
517 }
518 }
519
520 #[cfg(test)]
521 mod tests {
522 use super::*;
523
524 use isla_lib::bitvector::b64::B64;
525
526 #[test]
527 fn test_parse() {
528 let smtlib = "(model (define-fun v12331 () (_ BitVec 32) #x00000001))";
529 Model::<B64>::parse(&[], smtlib).unwrap();
530 }
531
532 #[test]
533 fn test_interpret_1() {
534 let smtlib = "(model (define-fun dmb ((x!0 Event)) Bool false))";
535 let ev = "R0";
536 let mut model = Model::<B64>::parse(&[ev], smtlib).unwrap();
537 let result = model.interpret("dmb", &[SexpVal::Event(ev)]).unwrap();
538 assert_eq!(result, SexpVal::Bool(false));
539 }
540
541 #[test]
542 fn test_interpret_2() {
543 let smtlib = "(model (define-fun |0xdmb%| ((x!0 Event)) Bool false))";
544 let ev = "R0";
545 let mut model = Model::<B64>::parse(&[ev], smtlib).unwrap();
546 let result = model.interpret("0xdmb%", &[SexpVal::Event(ev)]).unwrap();
547 assert_eq!(result, SexpVal::Bool(false));
548 }
549
550 #[test]
551 fn test_interpret_3() {
552 let smtlib =
553 "(model (define-fun |foo| ((x!0 Event)) Bool (let ((a!0 true)) (let ((a!0 false)) (and a!0)))))";
554 let ev = "R0";
555 let mut model = Model::<B64>::parse(&[ev], smtlib).unwrap();
556 let result = model.interpret("foo", &[SexpVal::Event(ev)]).unwrap();
557 assert_eq!(result, SexpVal::Bool(false));
558 }
559
560 #[test]
561 fn test_interpret_4() {
562 let smtlib = "(model (define-fun |foo| ((x!0 Event)) Bool (ite false true (not (= x!0 R0)))))";
563 let ev = "R0";
564 let mut model = Model::<B64>::parse(&[ev], smtlib).unwrap();
565 let result = model.interpret("foo", &[SexpVal::Event(ev)]).unwrap();
566 assert_eq!(result, SexpVal::Bool(false));
567 }
568
569 #[test]
570 fn test_interpret_rel() {
571 let smtlib = "(model (define-fun obs ((x!0 Event) (x!1 Event)) Bool
572 (or (and (= x!0 W0) (= x!1 R1))
573 (and (= x!0 IW) (= x!1 W0))
574 (and (= x!0 W1) (= x!1 R0))
575 (and (= x!0 IW) (= x!1 W1)))))";
576 let evs = ["IW", "W0", "W1", "R0", "R1"];
577 let mut model = Model::<B64>::parse(&evs, smtlib).unwrap();
578 let result = model.interpret_rel("obs", &evs).unwrap();
579 assert!(result.contains(&("W0", "R1")));
580 assert!(result.contains(&("IW", "W0")));
581 assert!(result.contains(&("W1", "R0")));
582 assert!(result.contains(&("IW", "W1")));
583 assert!(result.len() == 4);
584 }
585 }
586}