1mod arch_prelude;
15pub mod config;
16pub mod registers;
17
18#[rustfmt::skip]
27pub mod raw;
28
29pub use raw::{Core, ExceptionType, ExecutionResult, Privilege, ast};
30use raw::{cregidx, regidx};
31use registers::GeneralRegister;
32use registers::*;
33pub use softcore_prelude as prelude;
34use softcore_prelude::{BitVector, bv};
35
36const DEFAULT_PMP_CFG: raw::Pmpcfg_ent = raw::Pmpcfg_ent { bits: bv(0) };
39const DEFAULT_HPM_EVENT: raw::HpmEvent = raw::HpmEvent { bits: bv(0) };
40const DEFAULT_TLB_ENTRY: Option<raw::TLB_Entry> = None;
41const ZEROES: BitVector<64> = bv(0);
42
43#[derive(Debug, Clone, Copy)]
47pub enum Trap {
48 Some(u64),
50 None,
52}
53
54impl Trap {
55 pub fn trapped(self) -> bool {
56 match self {
57 Trap::Some(_) => true,
58 Trap::None => false,
59 }
60 }
61}
62
63impl Core {
66 pub fn reset(&mut self) {
74 raw::_reset_all_registers(self);
75 raw::reset_sys(self, ());
76 }
77
78 pub fn execute(&mut self, instr: ast) -> Trap {
80 let exec_res = raw::execute(self, instr);
81 self.process_execution_result(exec_res, instr)
82 }
83
84 fn process_execution_result(&mut self, exec_res: ExecutionResult, instr: ast) -> Trap {
87 match exec_res {
88 ExecutionResult::Retire_Success(_) => Trap::None,
89 ExecutionResult::Wait_For_Interrupt(_) => Trap::None,
90 ExecutionResult::Illegal_Instruction(_) => {
91 let instr_bits = raw::encdec_forwards(self, instr);
92 raw::handle_illegal(self, instr_bits);
93 Trap::Some(self.nextPC.bits())
94 }
95 ExecutionResult::Trap((privilege, ctl, pc)) => {
96 let pc = raw::exception_handler(self, privilege, ctl, pc);
97 raw::set_next_pc(self, pc);
98 Trap::Some(self.nextPC.bits())
99 }
100 ExecutionResult::Memory_Exception(_) => todo!("handle Memory_Exception"),
101 ExecutionResult::Ext_CSR_Check_Failure(_) => todo!("handle Ext_CSR_Check_Failure"),
102 ExecutionResult::Ext_ControlAddr_Check_Failure(_) => {
103 todo!("handle Ext_ControlAddr_Check_Failure")
104 }
105 ExecutionResult::Ext_DataAddr_Check_Failure(_) => {
106 todo!("handle Ext_DataAddr_Check_Failure")
107 }
108 ExecutionResult::Ext_XRET_Priv_Failure(_) => todo!("handle Ext_XRET_Priv_Failure"),
109 }
110 }
111
112 pub fn get(&mut self, reg: GeneralRegister) -> u64 {
114 let reg = match reg {
115 raw::regidx::Regidx(reg) => reg.bits() as i128,
116 };
117 raw::rX(self, raw::regno::Regno(reg)).bits()
118 }
119
120 pub fn set(&mut self, reg: GeneralRegister, value: u64) {
122 let reg = match reg {
123 raw::regidx::Regidx(reg) => reg.bits() as i128,
124 };
125 raw::wX(self, raw::regno::Regno(reg), bv(value));
126 }
127
128 pub fn get_csr(&mut self, csr: u64) -> Option<u64> {
133 let csr = bv(csr);
134 if raw::check_CSR(self, csr, self.cur_privilege, false) {
135 Some(raw::read_CSR(self, csr).bits())
136 } else {
137 None
138 }
139 }
140
141 pub fn set_csr(&mut self, csr: u64, value: u64) -> Option<u64> {
147 let csr = bv(csr);
148 if raw::check_CSR(self, csr, self.cur_privilege, true) {
149 Some(raw::write_CSR(self, csr, bv(value)).bits())
150 } else {
151 None
152 }
153 }
154
155 pub fn csrrw(
160 &mut self,
161 rd: GeneralRegister,
162 csr: u64,
163 rs1: GeneralRegister,
164 ) -> Result<(), raw::ExecutionResult> {
165 let val = self.get(rs1);
166 self.do_csr(val, csr, rd, raw::csrop::CSRRW, true)
167 }
168
169 pub fn csrrs(
174 &mut self,
175 rd: GeneralRegister,
176 csr: u64,
177 rs1: GeneralRegister,
178 ) -> Result<(), raw::ExecutionResult> {
179 let val = self.get(rs1);
180 self.do_csr(val, csr, rd, raw::csrop::CSRRS, rs1 != X0)
181 }
182
183 pub fn csrrc(
188 &mut self,
189 rd: GeneralRegister,
190 csr: u64,
191 rs1: GeneralRegister,
192 ) -> Result<(), raw::ExecutionResult> {
193 let val = self.get(rs1);
194 self.do_csr(val, csr, rd, raw::csrop::CSRRC, rs1 != X0)
195 }
196
197 pub fn csrrwi(
202 &mut self,
203 rd: GeneralRegister,
204 csr: u64,
205 uimm: u64,
206 ) -> Result<(), raw::ExecutionResult> {
207 let uimm = uimm & 0b11111; self.do_csr(uimm, csr, rd, raw::csrop::CSRRW, true)
209 }
210
211 pub fn csrrsi(
216 &mut self,
217 rd: GeneralRegister,
218 csr: u64,
219 uimm: u64,
220 ) -> Result<(), raw::ExecutionResult> {
221 let uimm = uimm & 0b11111; self.do_csr(uimm, csr, rd, raw::csrop::CSRRS, uimm != 0)
223 }
224
225 pub fn csrrci(
230 &mut self,
231 rd: GeneralRegister,
232 csr: u64,
233 uimm: u64,
234 ) -> Result<(), raw::ExecutionResult> {
235 let uimm = uimm & 0b11111; self.do_csr(uimm, csr, rd, raw::csrop::CSRRC, uimm != 0)
237 }
238
239 fn do_csr(
243 &mut self,
244 val: u64,
245 csr: u64,
246 rd: GeneralRegister,
247 op: raw::csrop,
248 is_write: bool,
249 ) -> Result<(), raw::ExecutionResult> {
250 let csr = bv(csr);
251 let val = bv(val);
252 let res = raw::doCSR(self, csr, val, rd, op, is_write);
253 match res {
254 raw::ExecutionResult::Retire_Success(()) => Ok(()),
255 _ => Err(res),
256 }
257 }
258
259 pub fn mode(&self) -> Privilege {
261 self.cur_privilege
262 }
263
264 pub fn set_mode(&mut self, mode: Privilege) {
266 self.cur_privilege = mode
267 }
268
269 pub fn decode_instr(&mut self, instr: u32) -> ast {
271 raw::encdec_backwards(self, bv(instr as u64))
272 }
273
274 pub fn encode_instr(&mut self, instr: ast) -> u32 {
276 raw::encdec_forwards(self, instr).bits() as u32
277 }
278
279 pub fn is_csr_defined(&mut self, csr_id: usize) -> bool {
281 raw::is_CSR_defined(self, bv(csr_id as u64))
282 }
283
284 pub fn dispatch_interrupt(&mut self) {
289 if let Some((int, target_priv)) = raw::dispatchInterrupt(self, self.cur_privilege) {
290 raw::handle_interrupt(self, int, target_priv);
291 }
292 }
293
294 pub fn inject_exception(&mut self, exception: ExceptionType, tval: u64) {
301 let current_level = self.cur_privilege;
302 let target_level = raw::exception_delegatee(self, exception, current_level);
303 raw::trap_handler(
304 self,
305 target_level,
306 false,
307 raw::exceptionType_to_bits(exception),
308 self.PC,
309 Some(bv(tval)),
310 None,
311 );
312 }
313
314 pub fn get_pmpaddr(&self, index: usize) -> u64 {
316 self.pmpaddr_n[index].bits()
317 }
318
319 pub fn set_pmpaddr(&mut self, index: usize, val: u64) {
321 raw::pmpWriteAddrReg(self, index as i128, bv(val));
322 }
323
324 pub fn set_pmpcfg(&mut self, index: usize, val: u64) {
326 raw::pmpWriteCfgReg(self, index as i128, bv(val));
327 }
328
329 pub fn pmp_check(
333 &mut self,
334 addr: u64,
335 access_kind: raw::AccessType<()>,
336 ) -> Option<raw::ExceptionType> {
337 let addr = raw::physaddr::Physaddr(bv(addr));
338 let width = 8;
339 raw::pmpCheck(self, addr, width, access_kind, self.cur_privilege)
340 }
341}
342
343pub const fn new_core(config: raw::Config) -> Core {
348 Core {
349 PC: bv(0),
350 nextPC: bv(0),
351 x1: bv(0),
352 x2: bv(0),
353 x3: bv(0),
354 x4: bv(0),
355 x5: bv(0),
356 x6: bv(0),
357 x7: bv(0),
358 x8: bv(0),
359 x9: bv(0),
360 x10: bv(0),
361 x11: bv(0),
362 x12: bv(0),
363 x13: bv(0),
364 x14: bv(0),
365 x15: bv(0),
366 x16: bv(0),
367 x17: bv(0),
368 x18: bv(0),
369 x19: bv(0),
370 x20: bv(0),
371 x21: bv(0),
372 x22: bv(0),
373 x23: bv(0),
374 x24: bv(0),
375 x25: bv(0),
376 x26: bv(0),
377 x27: bv(0),
378 x28: bv(0),
379 x29: bv(0),
380 x30: bv(0),
381 x31: bv(0),
382 cur_privilege: raw::Privilege::Machine,
383 cur_inst: bv(0),
384 misa: raw::Misa { bits: bv(0) },
385 mstatus: raw::Mstatus { bits: bv(0) },
386 menvcfg: raw::MEnvcfg { bits: bv(0) },
387 senvcfg: raw::SEnvcfg { bits: bv(0) },
388 mie: raw::Minterrupts { bits: bv(0) },
389 mip: raw::Minterrupts { bits: bv(0) },
390 medeleg: raw::Medeleg { bits: bv(0) },
391 mideleg: raw::Minterrupts { bits: bv(0) },
392 mtvec: raw::Mtvec { bits: bv(0) },
393 mcause: raw::Mcause { bits: bv(0) },
394 mepc: bv(0),
395 mtval: bv(0),
396 mscratch: bv(0),
397 scounteren: raw::Counteren { bits: bv(0) },
398 mcounteren: raw::Counteren { bits: bv(0) },
399 mcountinhibit: raw::Counterin { bits: bv(0) },
400 mcycle: bv(0),
401 mtime: bv(0),
402 minstret: bv(0),
403 minstret_increment: false,
404 mvendorid: bv(0),
405 mimpid: bv(0),
406 marchid: bv(0),
407 mhartid: bv(0),
408 mconfigptr: bv(0),
409 stvec: raw::Mtvec { bits: bv(0) },
410 sscratch: bv(0),
411 sepc: bv(0),
412 scause: raw::Mcause { bits: bv(0) },
413 stval: bv(0),
414 tselect: bv(0),
415 vstart: bv(0),
416 vl: bv(0),
417 vtype: raw::Vtype { bits: bv(0) },
418 pmpcfg_n: [DEFAULT_PMP_CFG; 64],
419 pmpaddr_n: [ZEROES; 64],
420 vr0: bv(0),
421 vr1: bv(0),
422 vr2: bv(0),
423 vr3: bv(0),
424 vr4: bv(0),
425 vr5: bv(0),
426 vr6: bv(0),
427 vr7: bv(0),
428 vr8: bv(0),
429 vr9: bv(0),
430 vr10: bv(0),
431 vr11: bv(0),
432 vr12: bv(0),
433 vr13: bv(0),
434 vr14: bv(0),
435 vr15: bv(0),
436 vr16: bv(0),
437 vr17: bv(0),
438 vr18: bv(0),
439 vr19: bv(0),
440 vr20: bv(0),
441 vr21: bv(0),
442 vr22: bv(0),
443 vr23: bv(0),
444 vr24: bv(0),
445 vr25: bv(0),
446 vr26: bv(0),
447 vr27: bv(0),
448 vr28: bv(0),
449 vr29: bv(0),
450 vr30: bv(0),
451 vr31: bv(0),
452 vcsr: raw::Vcsr { bits: bv(0) },
453 mhpmevent: [DEFAULT_HPM_EVENT; 32],
454 mhpmcounter: [ZEROES; 32],
455 float_result: bv(0),
456 float_fflags: bv(0),
457 f0: bv(0),
458 f1: bv(0),
459 f2: bv(0),
460 f3: bv(0),
461 f4: bv(0),
462 f5: bv(0),
463 f6: bv(0),
464 f7: bv(0),
465 f8: bv(0),
466 f9: bv(0),
467 f10: bv(0),
468 f11: bv(0),
469 f12: bv(0),
470 f13: bv(0),
471 f14: bv(0),
472 f15: bv(0),
473 f16: bv(0),
474 f17: bv(0),
475 f18: bv(0),
476 f19: bv(0),
477 f20: bv(0),
478 f21: bv(0),
479 f22: bv(0),
480 f23: bv(0),
481 f24: bv(0),
482 f25: bv(0),
483 f26: bv(0),
484 f27: bv(0),
485 f28: bv(0),
486 f29: bv(0),
487 f30: bv(0),
488 f31: bv(0),
489 fcsr: raw::Fcsr { bits: bv(0) },
490 mcyclecfg: raw::CountSmcntrpmf { bits: bv(0) },
491 minstretcfg: raw::CountSmcntrpmf { bits: bv(0) },
492 mtimecmp: bv(0),
493 stimecmp: bv(0),
494 htif_tohost: bv(0),
495 htif_done: false,
496 htif_exit_code: bv(0),
497 htif_cmd_write: false,
498 htif_payload_writes: bv(0),
499 tlb: [DEFAULT_TLB_ENTRY; raw::num_tlb_entries as usize],
500 satp: bv(0),
501 hart_state: raw::HartState::HART_ACTIVE(()),
502 config,
503 }
504}
505
506impl regidx {
509 pub fn new(reg: u8) -> regidx {
511 regidx::Regidx(bv(reg as u64))
512 }
513
514 pub fn bits(self) -> u8 {
516 let regidx::Regidx(bits) = self;
517 bits.bits() as u8
518 }
519}
520
521impl cregidx {
522 pub fn bits(self) -> u8 {
526 let cregidx::Cregidx(bits) = self;
527 bits.bits() as u8
528 }
529
530 pub fn to_regidx(self) -> regidx {
532 raw::creg2reg_idx(self)
533 }
534}
535
536#[cfg(test)]
539mod tests {
540 use super::*;
541 use crate::raw::*;
542
543 #[test]
544 fn pmp_check() {
545 let mut core = new_core(config::U74);
546 let addr = 0x8000_0000;
547 let access = AccessType::Read(());
548
549 assert!(
551 core.pmp_check(addr, access).is_none(),
552 "M-mode can access all memory by default"
553 );
554
555 core.set_mode(Privilege::User);
556 assert_eq!(
557 core.pmp_check(addr, access),
558 Some(ExceptionType::E_Load_Access_Fault(())),
559 "U-mode has no access by default"
560 );
561
562 let pmp_addr = addr >> 2; core.set_pmpaddr(0, pmp_addr);
565 core.set_pmpaddr(1, 2 * pmp_addr);
566 core.set_pmpcfg(0, 0b0000_1001 << 8); assert!(
568 core.pmp_check(addr, access).is_none(),
569 "PMP allow read access"
570 );
571 }
572
573 #[test]
574 fn decoder() {
575 let mut ctx = new_core(config::U74);
576 let uimm0 = bv(0);
577
578 assert_eq!(
581 ctx.decode_instr(0xff87b703),
582 ast::LOAD((
583 bv(0xFFF - 7), X15,
585 X14,
586 false,
587 word_width::DOUBLE,
588 false,
589 false
590 ))
591 );
592
593 assert_eq!(
597 ctx.decode_instr(0x30001073),
598 ast::CSRReg((bv(0x300), X0, X0, csrop::CSRRW))
599 );
600 assert_eq!(
602 ctx.decode_instr(0x30002073),
603 ast::CSRReg((bv(0x300), X0, X0, csrop::CSRRS))
604 );
605 assert_eq!(
607 ctx.decode_instr(0x30003073),
608 ast::CSRReg((bv(0x300), X0, X0, csrop::CSRRC))
609 );
610 assert_eq!(
612 ctx.decode_instr(0x30005073),
613 ast::CSRImm((bv(0x300), uimm0, X0, csrop::CSRRW))
614 );
615 assert_eq!(
617 ctx.decode_instr(0x30006073),
618 ast::CSRImm((bv(0x300), uimm0, X0, csrop::CSRRS))
619 );
620 assert_eq!(
622 ctx.decode_instr(0x30007073),
623 ast::CSRImm((bv(0x300), uimm0, X0, csrop::CSRRC))
624 );
625
626 assert_eq!(ctx.decode_instr(0x30001072), ast::ILLEGAL(bv(0x30001072)));
628 }
629
630 #[test]
631 fn general_purpose_registers() {
632 let mut ctx = new_core(config::U74);
633
634 assert_eq!(ctx.get(X0), 0, "X0 should be hardwired to 0");
636 assert_eq!(ctx.get(ZERO), 0, "ZERO should be hardwired to 0");
637
638 ctx.set(X0, 0xDEADBEEF);
640 assert_eq!(ctx.get(X0), 0, "X0 should remain 0 after write attempt");
641
642 ctx.set(RA, 0x12345678);
644 assert_eq!(ctx.get(RA), 0x12345678, "RA register should store value");
645 assert_eq!(ctx.get(X1), 0x12345678, "X1 and RA should be the same");
646
647 ctx.set(SP, 0x87654321);
648 assert_eq!(ctx.get(SP), 0x87654321, "SP register should store value");
649 assert_eq!(ctx.get(X2), 0x87654321, "X2 and SP should be the same");
650
651 ctx.set(A0, 0xAAAAAAAA);
653 ctx.set(A1, 0xBBBBBBBB);
654 assert_eq!(ctx.get(A0), 0xAAAAAAAA, "A0 register should store value");
655 assert_eq!(ctx.get(A1), 0xBBBBBBBB, "A1 register should store value");
656 assert_eq!(ctx.get(X10), 0xAAAAAAAA, "X10 and A0 should be the same");
657 assert_eq!(ctx.get(X11), 0xBBBBBBBB, "X11 and A1 should be the same");
658
659 ctx.set(S0, 0xCCCCCCCC);
661 ctx.set(S1, 0xDDDDDDDD);
662 assert_eq!(ctx.get(S0), 0xCCCCCCCC, "S0 register should store value");
663 assert_eq!(ctx.get(S1), 0xDDDDDDDD, "S1 register should store value");
664 assert_eq!(ctx.get(FP), 0xCCCCCCCC, "FP and S0 should be the same");
665 assert_eq!(ctx.get(X8), 0xCCCCCCCC, "X8 and S0 should be the same");
666 assert_eq!(ctx.get(X9), 0xDDDDDDDD, "X9 and S1 should be the same");
667
668 ctx.set(T0, 0xEEEEEEEE);
670 ctx.set(T6, 0xFFFFFFFF);
671 assert_eq!(ctx.get(T0), 0xEEEEEEEE, "T0 register should store value");
672 assert_eq!(ctx.get(T6), 0xFFFFFFFF, "T6 register should store value");
673 assert_eq!(ctx.get(X5), 0xEEEEEEEE, "X5 and T0 should be the same");
674 assert_eq!(ctx.get(X31), 0xFFFFFFFF, "X31 and T6 should be the same");
675
676 assert_eq!(
678 ctx.get(X0),
679 0,
680 "X0 should still be 0 after other register operations"
681 );
682 }
683
684 #[test]
685 fn csr_defined() {
686 let mut core = new_core(config::U74);
687
688 assert!(core.is_csr_defined(0x300), "mstatus should be defined");
690 assert!(core.is_csr_defined(0x301), "misa should be defined");
691 assert!(core.is_csr_defined(0x304), "mie should be defined");
692 assert!(core.is_csr_defined(0x305), "mtvec should be defined");
693 assert!(core.is_csr_defined(0x341), "mepc should be defined");
694 assert!(core.is_csr_defined(0x342), "mcause should be defined");
695 assert!(core.is_csr_defined(0x343), "mtval should be defined");
696 assert!(core.is_csr_defined(0x344), "mip should be defined");
697
698 assert!(core.is_csr_defined(0x3A0), "pmpcfg0 should be defined");
701 assert!(core.is_csr_defined(0x3A2), "pmpcfg2 should be defined");
702 assert!(!core.is_csr_defined(0x3A4), "pmpcfg4 should not be defined");
703 assert!(!core.is_csr_defined(0x3A6), "pmpcfg6 should not be defined");
704
705 assert!(
707 !core.is_csr_defined(0x3A1),
708 "pmpcfg1 should not be defined on RV64"
709 );
710 assert!(
711 !core.is_csr_defined(0x3A3),
712 "pmpcfg3 should not be defined on RV64"
713 );
714 assert!(
715 !core.is_csr_defined(0x3A5),
716 "pmpcfg5 should not be defined on RV64"
717 );
718
719 assert!(core.is_csr_defined(0x3B0), "pmpaddr0 should be defined");
722 assert!(core.is_csr_defined(0x3B5), "pmpaddr5 should be defined");
723 assert!(core.is_csr_defined(0x3BF), "pmpaddr15 should be defined");
724
725 assert!(
727 !core.is_csr_defined(0x3C0),
728 "pmpaddr16 should not be defined on U74"
729 );
730 assert!(
731 !core.is_csr_defined(0x3C8),
732 "pmpaddr24 should not be defined on U74"
733 );
734 assert!(
735 !core.is_csr_defined(0x3CF),
736 "pmpaddr31 should not be defined on U74"
737 );
738
739 assert!(
741 !core.is_csr_defined(0x000),
742 "CSR 0x000 should not be defined"
743 );
744 assert!(
745 !core.is_csr_defined(0xFFF),
746 "CSR 0xFFF should not be defined"
747 );
748 assert!(
749 !core.is_csr_defined(0x200),
750 "CSR 0x200 should not be defined"
751 );
752 }
753
754 #[test]
755 fn inject_exception() {
756 let mut core = new_core(config::U74);
757
758 core.set_mode(Privilege::User);
760 core.PC = bv(0x1000);
761 let initial_pc = core.PC.bits();
762
763 assert_eq!(core.mode(), Privilege::User, "Initial mode should be User");
764
765 let fault_addr = 0x8000_0000;
767 core.inject_exception(ExceptionType::E_Load_Access_Fault(()), fault_addr);
768
769 assert_eq!(
771 core.mode(),
772 Privilege::Machine,
773 "Mode should be Machine after exception"
774 );
775
776 assert_eq!(
778 core.mepc.bits(),
779 initial_pc,
780 "mepc should contain the PC when exception occurred"
781 );
782
783 assert_eq!(
785 core.mtval.bits(),
786 fault_addr,
787 "mtval should contain the fault address"
788 );
789 }
790
791 #[test]
792 fn csr_read_operations() {
793 let mut core = new_core(config::U74);
794
795 let _mstatus = core.get_csr(0x300);
797 let _misa = core.get_csr(0x301);
798 let _mie = core.get_csr(0x304);
799 let _mtvec = core.get_csr(0x305);
800 let _mepc = core.get_csr(0x341);
801 let _mcause = core.get_csr(0x342);
802 let _mtval = core.get_csr(0x343);
803 let _mip = core.get_csr(0x344);
804
805 let initial_value = core.get_csr(0x340);
807 assert_eq!(initial_value, Some(0), "mscratch should be 0 initially");
808 }
809
810 #[test]
811 fn csr_write_operations() {
812 let mut core = new_core(config::U74);
813
814 let initial_value = 0x12345678;
816 core.set(X1, initial_value);
817
818 let result = core.csrrw(X2, 0x340, X1);
820 assert!(result.is_ok(), "csrrw should succeed for mscratch");
821
822 let read_value = core.get_csr(0x340);
824 assert_eq!(
825 read_value,
826 Some(initial_value),
827 "mscratch should contain written value"
828 );
829
830 assert_eq!(core.get(X2), 0, "rd should contain old CSR value");
832
833 let new_value = 0x87654321;
835 core.set(X3, new_value);
836 let result = core.csrrw(X0, 0x340, X3);
837 assert!(result.is_ok(), "csrrw with X0 as rd should succeed");
838
839 assert_eq!(core.get(X0), 0, "X0 should remain 0");
841
842 let read_value = core.get_csr(0x340);
844 assert_eq!(
845 read_value,
846 Some(new_value),
847 "mscratch should contain new value"
848 );
849 }
850
851 #[test]
852 fn csr_set_operations() {
853 let mut core = new_core(config::U74);
854
855 core.set(X1, 0xFF00FF00);
857 let _ = core.csrrw(X0, 0x340, X1);
858
859 let set_bits = 0x00FF00FF;
861 core.set(X2, set_bits);
862
863 let result = core.csrrs(X3, 0x340, X2);
864 assert!(result.is_ok(), "csrrs should succeed for mscratch");
865
866 assert_eq!(core.get(X3), 0xFF00FF00, "rd should contain old CSR value");
868
869 let read_value = core.get_csr(0x340);
871 assert_eq!(
872 read_value,
873 Some(0xFFFFFFFF),
874 "mscratch should have bits set"
875 );
876
877 let result = core.csrrs(X4, 0x340, X0);
879 assert!(result.is_ok(), "csrrs with X0 as rs1 should succeed");
880
881 assert_eq!(
883 core.get(X4),
884 0xFFFFFFFF,
885 "rd should contain current CSR value"
886 );
887
888 let read_value = core.get_csr(0x340);
890 assert_eq!(read_value, Some(0xFFFFFFFF), "mscratch should be unchanged");
891 }
892
893 #[test]
894 fn csr_clear_operations() {
895 let mut core = new_core(config::U74);
896
897 core.set(X1, 0xFFFFFFFF);
899 let _ = core.csrrw(X0, 0x340, X1);
900
901 let clear_bits = 0x0F0F0F0F;
903 core.set(X2, clear_bits);
904
905 let result = core.csrrc(X3, 0x340, X2);
906 assert!(result.is_ok(), "csrrc should succeed for mscratch");
907
908 assert_eq!(core.get(X3), 0xFFFFFFFF, "rd should contain old CSR value");
910
911 let read_value = core.get_csr(0x340);
913 assert_eq!(
914 read_value,
915 Some(0xF0F0F0F0),
916 "mscratch should have bits cleared"
917 );
918
919 let result = core.csrrc(X4, 0x340, X0);
921 assert!(result.is_ok(), "csrrc with X0 as rs1 should succeed");
922
923 assert_eq!(
925 core.get(X4),
926 0xF0F0F0F0,
927 "rd should contain current CSR value"
928 );
929
930 let read_value = core.get_csr(0x340);
932 assert_eq!(read_value, Some(0xF0F0F0F0), "mscratch should be unchanged");
933 }
934
935 #[test]
936 fn csr_immediate_operations() {
937 let mut core = new_core(config::U74);
938
939 let result = core.csrrwi(X1, 0x340, 0x15);
941 assert!(result.is_ok(), "csrrwi should succeed for mscratch");
942
943 assert_eq!(core.get(X1), 0, "rd should contain old CSR value");
945
946 let read_value = core.get_csr(0x340);
948 assert_eq!(
949 read_value,
950 Some(0x15),
951 "mscratch should contain immediate value"
952 );
953
954 let result = core.csrrsi(X2, 0x340, 0x0A);
956 assert!(result.is_ok(), "csrrsi should succeed for mscratch");
957
958 assert_eq!(core.get(X2), 0x15, "rd should contain old CSR value");
960
961 let read_value = core.get_csr(0x340);
963 assert_eq!(read_value, Some(0x1F), "mscratch should have bits set");
964
965 let result = core.csrrci(X3, 0x340, 0x05);
967 assert!(result.is_ok(), "csrrci should succeed for mscratch");
968
969 assert_eq!(core.get(X3), 0x1F, "rd should contain old CSR value");
971
972 let read_value = core.get_csr(0x340);
974 assert_eq!(read_value, Some(0x1A), "mscratch should have bits cleared");
975
976 let result = core.csrrwi(X4, 0x340, 0xFF);
978 assert!(result.is_ok(), "csrrwi with large immediate should succeed");
979
980 let read_value = core.get_csr(0x340);
982 assert_eq!(
983 read_value,
984 Some(0x1F),
985 "immediate should be masked to 5 bits"
986 );
987
988 core.set(X5, 0x12345678);
990 let _ = core.csrrw(X0, 0x340, X5);
991
992 let result = core.csrrsi(X6, 0x340, 0);
993 assert!(result.is_ok(), "csrrsi with zero immediate should succeed");
994 assert_eq!(core.get(X6), 0x12345678, "rd should contain current value");
995
996 let read_value = core.get_csr(0x340);
997 assert_eq!(
998 read_value,
999 Some(0x12345678),
1000 "CSR should be unchanged with zero immediate"
1001 );
1002
1003 let result = core.csrrci(X7, 0x340, 0);
1004 assert!(result.is_ok(), "csrrci with zero immediate should succeed");
1005 assert_eq!(core.get(X7), 0x12345678, "rd should contain current value");
1006
1007 let read_value = core.get_csr(0x340);
1008 assert_eq!(
1009 read_value,
1010 Some(0x12345678),
1011 "CSR should be unchanged with zero immediate"
1012 );
1013 }
1014
1015 #[test]
1016 fn execute_addi() {
1017 let mut core = new_core(config::U74);
1018
1019 assert_eq!(core.get(A1), 0, "A1 should start at 0");
1021 let result = core.execute(ast::ITYPE((bv(0x42), X0, A1, iop::ADDI)));
1022 assert!(matches!(result, Trap::None));
1023 assert_eq!(core.get(A1), 0x42, "A1 should contain immediate value");
1024
1025 let result = core.execute(ast::ITYPE((bv(0x20), A1, A1, iop::ADDI)));
1027 assert!(matches!(result, Trap::None));
1028 assert_eq!(
1029 core.get(A1),
1030 0x62,
1031 "A1 should contain sum of previous value and immediate"
1032 );
1033
1034 core.set(T0, 100);
1036 let result = core.execute(ast::ITYPE((bv((-10i64) as u64), T0, T1, iop::ADDI)));
1037 assert!(matches!(result, Trap::None));
1038 assert_eq!(
1039 core.get(T1),
1040 90,
1041 "T1 should contain result of adding negative immediate"
1042 );
1043
1044 let result = core.execute(ast::ITYPE((bv(0xFF), T0, X0, iop::ADDI)));
1046 assert!(matches!(result, Trap::None));
1047 assert_eq!(core.get(X0), 0, "X0 should remain hardwired to 0");
1048
1049 core.set(T2, u64::MAX);
1051 let result = core.execute(ast::ITYPE((bv(1), T2, T3, iop::ADDI)));
1052 assert!(matches!(result, Trap::None));
1053 assert_eq!(core.get(T3), 0, "Addition should wrap around on overflow");
1054 }
1055
1056 #[test]
1057 fn execute_jalr() {
1058 let mut core = new_core(config::U74);
1059
1060 core.PC = bv(0x1000);
1062 core.nextPC = bv(0x1004);
1063 core.set(T0, 0x3000); let initial_pc = core.PC.bits();
1066
1067 let result = core.execute(ast::JALR((bv(8), T0, RA)));
1070
1071 assert!(matches!(result, Trap::None));
1072
1073 assert_eq!(
1075 core.get(RA),
1076 initial_pc + 4,
1077 "Return address should be old PC + 4"
1078 );
1079
1080 let expected_target = (0x3000 + 8) & !1; assert_eq!(
1083 core.nextPC.bits(),
1084 expected_target,
1085 "nextPC should be updated to target address"
1086 );
1087 }
1088
1089 #[test]
1090 fn execute_mul() {
1091 let mut core = new_core(config::U74);
1092
1093 core.set(T1, 123);
1095 core.set(T2, 456);
1096
1097 let mul_op = raw::mul_op {
1098 high: false,
1099 signed_rs1: true,
1100 signed_rs2: true,
1101 };
1102 let result = core.execute(ast::MUL((T2, T1, T0, mul_op)));
1103
1104 assert!(matches!(result, Trap::None));
1105
1106 let expected = 123u64.wrapping_mul(456u64);
1108 assert_eq!(core.get(T0), expected, "MUL result should be correct");
1109
1110 core.set(T1, (-5i64) as u64); core.set(T2, 3);
1113
1114 let result = core.execute(ast::MUL((T2, T1, T0, mul_op)));
1115 assert!(matches!(result, Trap::None));
1116
1117 let expected = ((-5i64).wrapping_mul(3i64)) as u64;
1118 assert_eq!(
1119 core.get(T0),
1120 expected,
1121 "MUL with negative numbers should work"
1122 );
1123 }
1124
1125 #[test]
1126 fn execute_div() {
1127 let mut core = new_core(config::U74);
1128
1129 core.set(T1, 100);
1131 core.set(T2, 7);
1132
1133 let result = core.execute(ast::DIV((T2, T1, T0, true))); assert!(matches!(result, Trap::None));
1136
1137 let expected = (100i64 / 7i64) as u64;
1139 assert_eq!(core.get(T0), expected, "DIV result should be correct");
1140
1141 core.set(T1, 42);
1143 core.set(T2, 0);
1144
1145 let result = core.execute(ast::DIV((T2, T1, T0, true)));
1146 assert!(matches!(result, Trap::None));
1147
1148 assert_eq!(
1149 core.get(T0),
1150 (-1i64) as u64,
1151 "Division by zero should return -1"
1152 );
1153
1154 core.set(T1, (-20i64) as u64);
1156 core.set(T2, 3);
1157
1158 let result = core.execute(ast::DIV((T2, T1, T0, true)));
1159 assert!(matches!(result, Trap::None));
1160
1161 let expected = ((-20i64) / 3i64) as u64;
1162 assert_eq!(
1163 core.get(T0),
1164 expected,
1165 "Signed division should work correctly"
1166 );
1167
1168 core.set(T1, 100);
1170 core.set(T2, 7);
1171
1172 let result = core.execute(ast::DIV((T2, T1, T0, false))); assert!(matches!(result, Trap::None));
1174
1175 let expected = 100u64 / 7u64;
1176 assert_eq!(
1177 core.get(T0),
1178 expected,
1179 "Unsigned division should work correctly"
1180 );
1181 }
1182}