1use super::rvc;
13
14pub const MISA: u64 = (2 << 62) | (1 << 0) | (1 << 2) | (1 << 8) | (1 << 12) | (1 << 20);
16
17pub const PMP_ENTRIES: usize = 8;
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
22pub enum Privilege {
23 User = 0,
24 Machine = 3,
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub struct Trap {
30 pub cause: u64,
31 pub tval: u64,
32}
33
34pub const CAUSE_FETCH_ACCESS: u64 = 1;
35pub const CAUSE_ILLEGAL_INSTRUCTION: u64 = 2;
36pub const CAUSE_BREAKPOINT: u64 = 3;
37pub const CAUSE_MISALIGNED_LOAD: u64 = 4;
38pub const CAUSE_LOAD_ACCESS: u64 = 5;
39pub const CAUSE_MISALIGNED_STORE: u64 = 6;
40pub const CAUSE_STORE_ACCESS: u64 = 7;
41pub const CAUSE_USER_ECALL: u64 = 8;
42pub const CAUSE_MACHINE_ECALL: u64 = 11;
43
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46pub struct BusError;
47
48pub trait Bus {
50 fn read(&mut self, addr: u64, size: u8) -> Result<u64, BusError>;
51 fn write(&mut self, addr: u64, size: u8, value: u64) -> Result<(), BusError>;
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
59pub struct Region {
60 pub base: u64,
61 pub size: u64,
62 pub read: bool,
63 pub write: bool,
64 pub execute: bool,
65 pub atomic: bool,
66 pub width: Option<u64>,
68}
69
70impl Region {
71 pub const fn memory(base: u64, size: u64) -> Self {
73 Region {
74 base,
75 size,
76 read: true,
77 write: true,
78 execute: true,
79 atomic: true,
80 width: None,
81 }
82 }
83
84 pub const fn data(base: u64, size: u64) -> Self {
86 Region {
87 base,
88 size,
89 read: true,
90 write: true,
91 execute: false,
92 atomic: true,
93 width: None,
94 }
95 }
96
97 pub const fn rom(base: u64, size: u64) -> Self {
99 Region {
100 base,
101 size,
102 read: true,
103 write: false,
104 execute: true,
105 atomic: false,
106 width: None,
107 }
108 }
109
110 pub const fn io(base: u64, size: u64) -> Self {
112 Region {
113 base,
114 size,
115 read: true,
116 write: true,
117 execute: false,
118 atomic: false,
119 width: Some(8),
120 }
121 }
122
123 fn holds(&self, addr: u64, size: u64) -> bool {
124 addr >= self.base && addr.wrapping_add(size) <= self.base.wrapping_add(self.size) && addr.wrapping_add(size) > addr
125 }
126}
127
128#[derive(Clone, Copy, Debug, PartialEq, Eq)]
130pub enum Step {
131 Retired,
133 Trapped(Trap),
135}
136
137#[derive(Clone, Copy, PartialEq, Eq)]
138enum Access {
139 Read,
140 Write,
141 Execute,
142 Atomic,
143}
144
145#[derive(Clone, Debug)]
147pub struct Hart {
148 pub pc: u64,
149 pub x: [u64; 32],
150 pub privilege: Privilege,
151 pub mie_bit: bool,
152 pub mpie: bool,
153 pub mpp: Privilege,
154 pub mprv: bool,
155 pub tw: bool,
156 pub mie: u64,
157 pub mtvec: u64,
158 pub mscratch: u64,
159 pub mepc: u64,
160 pub mcause: u64,
161 pub mtval: u64,
162 pub mcounteren: u64,
163 pub mcountinhibit: u64,
164 pub mcycle: u64,
165 pub minstret: u64,
166 pub pmpcfg: [u8; PMP_ENTRIES],
167 pub pmpaddr: [u64; PMP_ENTRIES],
168 pub reservation: Option<u64>,
170 pub pma: Vec<Region>,
172}
173
174const MSTATUS_UXL: u64 = 2 << 32;
176
177const PMP_R: u8 = 1;
178const PMP_W: u8 = 2;
179const PMP_X: u8 = 4;
180const PMP_A: u8 = 3 << 3;
181const PMP_L: u8 = 1 << 7;
182const PMP_TOR: u8 = 1 << 3;
183const PMP_NA4: u8 = 2 << 3;
184const PMP_NAPOT: u8 = 3 << 3;
185const PMPADDR_MASK: u64 = (1 << 54) - 1;
187
188fn sext32(v: u64) -> u64 {
189 v as u32 as i32 as i64 as u64
190}
191
192fn illegal(inst: u32) -> Trap {
193 Trap {
194 cause: CAUSE_ILLEGAL_INSTRUCTION,
195 tval: inst as u64,
196 }
197}
198
199impl Hart {
200 pub fn new(reset_pc: u64, pma: Vec<Region>) -> Self {
203 Hart {
204 pc: reset_pc,
205 x: [0; 32],
206 privilege: Privilege::Machine,
207 mie_bit: false,
208 mpie: false,
209 mpp: Privilege::User,
210 mprv: false,
211 tw: false,
212 mie: 0,
213 mtvec: 0,
214 mscratch: 0,
215 mepc: 0,
216 mcause: 0,
217 mtval: 0,
218 mcounteren: 0,
219 mcountinhibit: 0,
220 mcycle: 0,
221 minstret: 0,
222 pmpcfg: [0; PMP_ENTRIES],
223 pmpaddr: [0; PMP_ENTRIES],
224 reservation: None,
225 pma,
226 }
227 }
228
229 fn pma_allows(&self, addr: u64, size: u64, access: Access) -> bool {
231 self.pma.iter().any(|r| {
232 r.holds(addr, size)
233 && r.width.map_or(true, |w| w == size)
234 && match access {
235 Access::Read => r.read,
236 Access::Write => r.write,
237 Access::Execute => r.execute,
238 Access::Atomic => r.atomic,
239 }
240 })
241 }
242
243 pub fn mstatus(&self) -> u64 {
244 MSTATUS_UXL
245 | ((self.mie_bit as u64) << 3)
246 | ((self.mpie as u64) << 7)
247 | ((self.mpp as u64) << 11)
248 | ((self.mprv as u64) << 17)
249 | ((self.tw as u64) << 21)
250 }
251
252 fn write_mstatus(&mut self, v: u64) {
253 self.mie_bit = v & (1 << 3) != 0;
254 self.mpie = v & (1 << 7) != 0;
255 self.mpp = if (v >> 11) & 3 == 3 {
256 Privilege::Machine
257 } else {
258 Privilege::User
259 };
260 self.mprv = v & (1 << 17) != 0;
261 self.tw = v & (1 << 21) != 0;
262 }
263
264 fn data_privilege(&self) -> Privilege {
266 if self.mprv && self.privilege == Privilege::Machine {
267 self.mpp
268 } else {
269 self.privilege
270 }
271 }
272
273 fn pmp_range(&self, i: usize) -> Option<(u64, u64)> {
275 let a = self.pmpcfg[i] & PMP_A;
276 let addr = self.pmpaddr[i];
277 match a {
278 PMP_TOR => {
279 let lo = if i == 0 { 0 } else { self.pmpaddr[i - 1] << 2 };
280 Some((lo, addr << 2))
281 }
282 PMP_NA4 => Some((addr << 2, (addr << 2) + 4)),
283 PMP_NAPOT => {
284 let ones = (!addr).trailing_zeros().min(54) as u64;
285 let size_log2 = ones + 3;
286 let lo = (addr & !((1u64 << ones) - 1)) << 2;
287 Some((lo, lo.wrapping_add(1u64 << size_log2)))
288 }
289 _ => None,
290 }
291 }
292
293 fn pmp_allows(&self, addr: u64, size: u64, access: Access, privilege: Privilege) -> bool {
295 let end = addr.wrapping_add(size);
296 for i in 0..PMP_ENTRIES {
297 let Some((lo, hi)) = self.pmp_range(i) else { continue };
298 if lo >= hi {
299 continue;
300 }
301 let any = addr < hi && end > lo;
302 if !any {
303 continue;
304 }
305 let all = addr >= lo && end <= hi;
306 if !all {
307 return false;
308 }
309 let cfg = self.pmpcfg[i];
310 if privilege == Privilege::Machine && cfg & PMP_L == 0 {
311 return true;
312 }
313 return match access {
314 Access::Read => cfg & PMP_R != 0,
315 Access::Write => cfg & PMP_W != 0,
316 Access::Execute => cfg & PMP_X != 0,
317 Access::Atomic => cfg & PMP_R != 0 && cfg & PMP_W != 0,
318 };
319 }
320 privilege == Privilege::Machine
321 }
322
323 fn load(&mut self, bus: &mut impl Bus, addr: u64, size: u8) -> Result<u64, Trap> {
324 if addr % size as u64 != 0 {
325 return Err(Trap {
326 cause: CAUSE_MISALIGNED_LOAD,
327 tval: addr,
328 });
329 }
330 let fault = Trap {
331 cause: CAUSE_LOAD_ACCESS,
332 tval: addr,
333 };
334 if !self.pmp_allows(addr, size as u64, Access::Read, self.data_privilege())
335 || !self.pma_allows(addr, size as u64, Access::Read)
336 {
337 return Err(fault);
338 }
339 bus.read(addr, size).map_err(|_| fault)
340 }
341
342 fn store(&mut self, bus: &mut impl Bus, addr: u64, size: u8, value: u64) -> Result<(), Trap> {
343 if addr % size as u64 != 0 {
344 return Err(Trap {
345 cause: CAUSE_MISALIGNED_STORE,
346 tval: addr,
347 });
348 }
349 let fault = Trap {
350 cause: CAUSE_STORE_ACCESS,
351 tval: addr,
352 };
353 if !self.pmp_allows(addr, size as u64, Access::Write, self.data_privilege())
354 || !self.pma_allows(addr, size as u64, Access::Write)
355 {
356 return Err(fault);
357 }
358 bus.write(addr, size, value).map_err(|_| fault)
359 }
360
361 fn amo_load(&mut self, bus: &mut impl Bus, addr: u64, size: u8) -> Result<u64, Trap> {
363 let fault = Trap {
364 cause: CAUSE_STORE_ACCESS,
365 tval: addr,
366 };
367 if addr % size as u64 != 0 {
368 return Err(Trap {
369 cause: CAUSE_MISALIGNED_STORE,
370 tval: addr,
371 });
372 }
373 if !self.pmp_allows(addr, size as u64, Access::Atomic, self.data_privilege())
374 || !self.pma_allows(addr, size as u64, Access::Atomic)
375 {
376 return Err(fault);
377 }
378 bus.read(addr, size).map_err(|_| fault)
379 }
380
381 fn fetch_half(&mut self, bus: &mut impl Bus, addr: u64) -> Result<u16, Trap> {
382 let fault = Trap {
383 cause: CAUSE_FETCH_ACCESS,
384 tval: addr,
385 };
386 if !self.pmp_allows(addr, 2, Access::Execute, self.privilege) || !self.pma_allows(addr, 2, Access::Execute) {
387 return Err(fault);
388 }
389 bus.read(addr, 2).map(|v| v as u16).map_err(|_| fault)
390 }
391
392 fn fetch(&mut self, bus: &mut impl Bus) -> Result<(u32, u64, u32), Trap> {
394 let lo = self.fetch_half(bus, self.pc)?;
395 if rvc::is_compressed(lo) {
396 return match rvc::expand(lo) {
397 Some(inst) => Ok((inst, 2, lo as u32)),
398 None => Err(illegal(lo as u32)),
399 };
400 }
401 let hi = self.fetch_half(bus, self.pc.wrapping_add(2))?;
402 let inst = (lo as u32) | ((hi as u32) << 16);
403 Ok((inst, 4, inst))
404 }
405
406 fn take_trap(&mut self, trap: Trap) {
407 self.mepc = self.pc;
408 self.mcause = trap.cause;
409 self.mtval = trap.tval;
410 self.mpie = self.mie_bit;
411 self.mie_bit = false;
412 self.mpp = self.privilege;
413 self.privilege = Privilege::Machine;
414 self.pc = self.mtvec & !3;
415 self.reservation = None;
416 }
417
418 pub fn step(&mut self, bus: &mut impl Bus) -> Step {
422 let result = self.execute(bus);
423 let counting_cycles = self.mcountinhibit & 1 == 0;
424 match result {
425 Ok(outcome) => {
426 if counting_cycles && !outcome.wrote_mcycle {
427 self.mcycle = self.mcycle.wrapping_add(1);
428 }
429 if self.mcountinhibit & 4 == 0 && !outcome.wrote_minstret {
430 self.minstret = self.minstret.wrapping_add(1);
431 }
432 self.pc = outcome.next_pc;
433 self.x[0] = 0;
434 Step::Retired
435 }
436 Err(trap) => {
437 if counting_cycles {
438 self.mcycle = self.mcycle.wrapping_add(1);
439 }
440 self.take_trap(trap);
441 Step::Trapped(trap)
442 }
443 }
444 }
445
446 fn execute(&mut self, bus: &mut impl Bus) -> Result<Outcome, Trap> {
447 let (inst, len, raw) = self.fetch(bus)?;
448 let mut out = Outcome {
449 next_pc: self.pc.wrapping_add(len),
450 wrote_mcycle: false,
451 wrote_minstret: false,
452 };
453 let opcode = inst & 0x7f;
454 let rd = ((inst >> 7) & 31) as usize;
455 let funct3 = (inst >> 12) & 7;
456 let rs1 = ((inst >> 15) & 31) as usize;
457 let rs2 = ((inst >> 20) & 31) as usize;
458 let funct7 = inst >> 25;
459 let a = self.x[rs1];
460 let b = self.x[rs2];
461 let imm_i = ((inst as i32) >> 20) as i64 as u64;
462 let imm_s = ((((inst as i32) >> 25) << 5) as i64 as u64) | ((inst >> 7) & 31) as u64;
463 let imm_b = ((((inst as i32) >> 31) << 12) as i64 as u64)
464 | (((inst >> 7) & 1) << 11) as u64
465 | (((inst >> 25) & 0x3f) << 5) as u64
466 | (((inst >> 8) & 0xf) << 1) as u64;
467 let imm_u = (inst & 0xffff_f000) as i32 as i64 as u64;
468 let imm_j = ((((inst as i32) >> 31) << 20) as i64 as u64)
469 | (inst & 0x000f_f000) as u64
470 | (((inst >> 20) & 1) << 11) as u64
471 | (((inst >> 21) & 0x3ff) << 1) as u64;
472 let bad = || illegal(raw);
473 match opcode {
474 0x37 => self.x[rd] = imm_u,
475 0x17 => self.x[rd] = self.pc.wrapping_add(imm_u),
476 0x6f => {
477 self.x[rd] = self.pc.wrapping_add(len);
478 out.next_pc = self.pc.wrapping_add(imm_j);
479 }
480 0x67 => {
481 if funct3 != 0 {
482 return Err(bad());
483 }
484 let target = a.wrapping_add(imm_i) & !1;
485 self.x[rd] = self.pc.wrapping_add(len);
486 out.next_pc = target;
487 }
488 0x63 => {
489 let taken = match funct3 {
490 0 => a == b,
491 1 => a != b,
492 4 => (a as i64) < (b as i64),
493 5 => (a as i64) >= (b as i64),
494 6 => a < b,
495 7 => a >= b,
496 _ => return Err(bad()),
497 };
498 if taken {
499 out.next_pc = self.pc.wrapping_add(imm_b);
500 }
501 }
502 0x03 => {
503 let addr = a.wrapping_add(imm_i);
504 let v = match funct3 {
505 0 => self.load(bus, addr, 1)? as u8 as i8 as i64 as u64,
506 1 => self.load(bus, addr, 2)? as u16 as i16 as i64 as u64,
507 2 => sext32(self.load(bus, addr, 4)?),
508 3 => self.load(bus, addr, 8)?,
509 4 => self.load(bus, addr, 1)? as u8 as u64,
510 5 => self.load(bus, addr, 2)? as u16 as u64,
511 6 => self.load(bus, addr, 4)? as u32 as u64,
512 _ => return Err(bad()),
513 };
514 self.x[rd] = v;
515 }
516 0x23 => {
517 let addr = a.wrapping_add(imm_s);
518 match funct3 {
519 0 => self.store(bus, addr, 1, b & 0xff)?,
520 1 => self.store(bus, addr, 2, b & 0xffff)?,
521 2 => self.store(bus, addr, 4, b & 0xffff_ffff)?,
522 3 => self.store(bus, addr, 8, b)?,
523 _ => return Err(bad()),
524 }
525 }
526 0x13 => {
527 let shamt = (inst >> 20) & 0x3f;
528 self.x[rd] = match funct3 {
529 0 => a.wrapping_add(imm_i),
530 2 => ((a as i64) < (imm_i as i64)) as u64,
531 3 => (a < imm_i) as u64,
532 4 => a ^ imm_i,
533 6 => a | imm_i,
534 7 => a & imm_i,
535 1 if inst >> 26 == 0 => a << shamt,
536 5 if inst >> 26 == 0 => a >> shamt,
537 5 if inst >> 26 == 0x10 => ((a as i64) >> shamt) as u64,
538 _ => return Err(bad()),
539 };
540 }
541 0x1b => {
542 let shamt = (inst >> 20) & 0x1f;
543 self.x[rd] = match (funct3, funct7) {
544 (0, _) => sext32(a.wrapping_add(imm_i)),
545 (1, 0) => sext32(((a as u32) << shamt) as u64),
546 (5, 0) => sext32(((a as u32) >> shamt) as u64),
547 (5, 0x20) => ((a as i32) >> shamt) as i64 as u64,
548 _ => return Err(bad()),
549 };
550 }
551 0x33 => {
552 self.x[rd] = match (funct7, funct3) {
553 (0, 0) => a.wrapping_add(b),
554 (0x20, 0) => a.wrapping_sub(b),
555 (0, 1) => a << (b & 63),
556 (0, 2) => ((a as i64) < (b as i64)) as u64,
557 (0, 3) => (a < b) as u64,
558 (0, 4) => a ^ b,
559 (0, 5) => a >> (b & 63),
560 (0x20, 5) => ((a as i64) >> (b & 63)) as u64,
561 (0, 6) => a | b,
562 (0, 7) => a & b,
563 (1, 0) => a.wrapping_mul(b),
564 (1, 1) => (((a as i64 as i128) * (b as i64 as i128)) >> 64) as u64,
565 (1, 2) => (((a as i64 as i128) * (b as u128 as i128)) >> 64) as u64,
566 (1, 3) => (((a as u128) * (b as u128)) >> 64) as u64,
567 (1, 4) => {
568 let (x, y) = (a as i64, b as i64);
569 if y == 0 {
570 u64::MAX
571 } else {
572 x.wrapping_div(y) as u64
573 }
574 }
575 (1, 5) => a.checked_div(b).unwrap_or(u64::MAX),
576 (1, 6) => {
577 let (x, y) = (a as i64, b as i64);
578 if y == 0 {
579 a
580 } else {
581 x.wrapping_rem(y) as u64
582 }
583 }
584 (1, 7) => a.checked_rem(b).unwrap_or(a),
585 _ => return Err(bad()),
586 };
587 }
588 0x3b => {
589 let (x, y) = (a as u32, b as u32);
590 self.x[rd] = match (funct7, funct3) {
591 (0, 0) => sext32(x.wrapping_add(y) as u64),
592 (0x20, 0) => sext32(x.wrapping_sub(y) as u64),
593 (0, 1) => sext32((x << (y & 31)) as u64),
594 (0, 5) => sext32((x >> (y & 31)) as u64),
595 (0x20, 5) => ((x as i32) >> (y & 31)) as i64 as u64,
596 (1, 0) => sext32(x.wrapping_mul(y) as u64),
597 (1, 4) => {
598 let (p, q) = (x as i32, y as i32);
599 if q == 0 {
600 u64::MAX
601 } else {
602 p.wrapping_div(q) as i64 as u64
603 }
604 }
605 (1, 5) => {
606 if y == 0 {
607 u64::MAX
608 } else {
609 sext32((x / y) as u64)
610 }
611 }
612 (1, 6) => {
613 let (p, q) = (x as i32, y as i32);
614 if q == 0 {
615 p as i64 as u64
616 } else {
617 p.wrapping_rem(q) as i64 as u64
618 }
619 }
620 (1, 7) => {
621 if y == 0 {
622 sext32(x as u64)
623 } else {
624 sext32((x % y) as u64)
625 }
626 }
627 _ => return Err(bad()),
628 };
629 }
630 0x2f => self.atomic(bus, inst, rd, a, b, raw)?,
631 0x0f => match funct3 {
632 0 | 1 => {}
633 _ => return Err(bad()),
634 },
635 0x73 => self.system(inst, raw, rd, rs1, funct3, &mut out)?,
636 _ => return Err(bad()),
637 }
638 Ok(out)
639 }
640
641 fn atomic(&mut self, bus: &mut impl Bus, inst: u32, rd: usize, a: u64, b: u64, raw: u32) -> Result<(), Trap> {
642 let funct3 = (inst >> 12) & 7;
643 let funct5 = inst >> 27;
644 let size: u8 = match funct3 {
645 2 => 4,
646 3 => 8,
647 _ => return Err(illegal(raw)),
648 };
649 let widen = |v: u64| if size == 4 { sext32(v) } else { v };
650 match funct5 {
651 0x02 => {
652 if (inst >> 20) & 31 != 0 {
653 return Err(illegal(raw));
654 }
655 if a % size as u64 != 0 {
656 return Err(Trap {
657 cause: CAUSE_MISALIGNED_LOAD,
658 tval: a,
659 });
660 }
661 if !self.pma_allows(a, size as u64, Access::Atomic) {
662 return Err(Trap {
663 cause: CAUSE_LOAD_ACCESS,
664 tval: a,
665 });
666 }
667 let v = self.load(bus, a, size)?;
668 self.reservation = Some(a);
669 self.x[rd] = widen(v);
670 }
671 0x03 => {
672 if a % size as u64 != 0 {
673 return Err(Trap {
674 cause: CAUSE_MISALIGNED_STORE,
675 tval: a,
676 });
677 }
678 if self.reservation == Some(a) {
679 if !self.pma_allows(a, size as u64, Access::Atomic) {
680 return Err(Trap {
681 cause: CAUSE_STORE_ACCESS,
682 tval: a,
683 });
684 }
685 let value = if size == 4 { b & 0xffff_ffff } else { b };
686 self.store(bus, a, size, value)?;
687 self.x[rd] = 0;
688 } else {
689 self.x[rd] = 1;
690 }
691 self.reservation = None;
692 }
693 _ => {
694 let old = self.amo_load(bus, a, size)?;
695 let (x, y) = if size == 4 { (sext32(old), sext32(b)) } else { (old, b) };
696 let new = match funct5 {
697 0x01 => y,
698 0x00 => x.wrapping_add(y),
699 0x04 => x ^ y,
700 0x0c => x & y,
701 0x08 => x | y,
702 0x10 => {
703 if (x as i64) < (y as i64) {
704 x
705 } else {
706 y
707 }
708 }
709 0x14 => {
710 if (x as i64) > (y as i64) {
711 x
712 } else {
713 y
714 }
715 }
716 0x18 => x.min(y),
718 0x1c => x.max(y),
719 _ => return Err(illegal(raw)),
720 };
721 let mask = if size == 4 { 0xffff_ffff } else { u64::MAX };
722 self.store(bus, a, size, new & mask)
723 .map_err(|t| Trap {
724 cause: CAUSE_STORE_ACCESS,
725 tval: t.tval,
726 })?;
727 self.x[rd] = widen(old);
728 }
729 }
730 Ok(())
731 }
732
733 fn system(
734 &mut self,
735 inst: u32,
736 raw: u32,
737 rd: usize,
738 rs1: usize,
739 funct3: u32,
740 out: &mut Outcome,
741 ) -> Result<(), Trap> {
742 if funct3 == 0 {
743 return match inst {
744 0x0000_0073 => Err(Trap {
745 cause: if self.privilege == Privilege::Machine {
746 CAUSE_MACHINE_ECALL
747 } else {
748 CAUSE_USER_ECALL
749 },
750 tval: 0,
751 }),
752 0x0010_0073 => Err(Trap {
753 cause: CAUSE_BREAKPOINT,
754 tval: self.pc,
755 }),
756 0x3020_0073 if self.privilege == Privilege::Machine => {
757 self.privilege = self.mpp;
758 self.mie_bit = self.mpie;
759 self.mpie = true;
760 if self.mpp != Privilege::Machine {
761 self.mprv = false;
762 }
763 self.mpp = Privilege::User;
764 self.reservation = None;
765 out.next_pc = self.mepc;
766 Ok(())
767 }
768 0x1050_0073 if self.privilege == Privilege::Machine || !self.tw => Ok(()),
769 _ => Err(illegal(raw)),
770 };
771 }
772 if funct3 == 4 {
773 return Err(illegal(raw));
774 }
775 let csr = inst >> 20;
776 let operand = if funct3 & 4 != 0 { rs1 as u64 } else { self.x[rs1] };
777 let writes = match funct3 & 3 {
778 1 => true,
779 _ => rs1 != 0,
780 };
781 let old = self.read_csr(csr, raw)?;
782 if writes {
783 if (csr >> 10) & 3 == 3 {
784 return Err(illegal(raw));
785 }
786 let new = match funct3 & 3 {
787 1 => operand,
788 2 => old | operand,
789 _ => old & !operand,
790 };
791 self.write_csr(csr, new, out);
792 }
793 self.x[rd] = old;
794 Ok(())
795 }
796
797 fn counter_permitted(&self, bit: u32) -> bool {
798 self.privilege == Privilege::Machine || self.mcounteren & (1 << bit) != 0
799 }
800
801 fn read_csr(&self, csr: u32, raw: u32) -> Result<u64, Trap> {
802 if (csr >> 8) & 3 > self.privilege as u32 {
803 return Err(illegal(raw));
804 }
805 Ok(match csr {
806 0x300 => self.mstatus(),
807 0x301 => MISA,
808 0x304 => self.mie,
809 0x305 => self.mtvec,
810 0x306 => self.mcounteren,
811 0x30a => 0,
812 0x320 => self.mcountinhibit,
813 0x323..=0x33f => 0,
814 0x340 => self.mscratch,
815 0x341 => self.mepc,
816 0x342 => self.mcause,
817 0x343 => self.mtval,
818 0x344 => 0,
819 0x3a0 => self.pmpcfg.iter().enumerate().map(|(i, &c)| (c as u64) << (8 * i)).sum(),
820 0x3a2 => 0,
821 0x3b0..=0x3bf => {
822 let i = (csr - 0x3b0) as usize;
823 if i < PMP_ENTRIES {
824 self.pmpaddr[i]
825 } else {
826 0
827 }
828 }
829 0xb00 => self.mcycle,
830 0xb02 => self.minstret,
831 0xb03..=0xb1f => 0,
832 0xc00 if self.counter_permitted(0) => self.mcycle,
833 0xc01 if self.counter_permitted(1) => self.mcycle,
834 0xc02 if self.counter_permitted(2) => self.minstret,
835 0xc03..=0xc1f if self.counter_permitted(csr - 0xc00) => 0,
836 0xf11..=0xf15 => 0,
837 _ => return Err(illegal(raw)),
838 })
839 }
840
841 fn write_csr(&mut self, csr: u32, v: u64, out: &mut Outcome) {
842 match csr {
843 0x300 => self.write_mstatus(v),
844 0x304 => self.mie = v & ((1 << 3) | (1 << 7) | (1 << 11)),
845 0x305 => self.mtvec = v & !3,
846 0x306 => self.mcounteren = v & 7,
847 0x320 => self.mcountinhibit = v & 5,
848 0x340 => self.mscratch = v,
849 0x341 => self.mepc = v & !1,
850 0x342 => self.mcause = v,
851 0x343 => self.mtval = v,
852 0x3a0 => {
853 for i in 0..PMP_ENTRIES {
854 if self.pmpcfg[i] & PMP_L != 0 {
855 continue;
856 }
857 let mut cfg = (v >> (8 * i)) as u8 & (PMP_R | PMP_W | PMP_X | PMP_A | PMP_L);
858 if cfg & PMP_W != 0 && cfg & PMP_R == 0 {
859 cfg &= !PMP_W;
860 }
861 self.pmpcfg[i] = cfg;
862 }
863 }
864 0x3b0..=0x3bf => {
865 let i = (csr - 0x3b0) as usize;
866 if i < PMP_ENTRIES && !self.pmpaddr_locked(i) {
867 self.pmpaddr[i] = v & PMPADDR_MASK;
868 }
869 }
870 0xb00 => {
871 self.mcycle = v;
872 out.wrote_mcycle = true;
873 }
874 0xb02 => {
875 self.minstret = v;
876 out.wrote_minstret = true;
877 }
878 _ => {}
879 }
880 }
881
882 fn pmpaddr_locked(&self, i: usize) -> bool {
885 self.pmpcfg[i] & PMP_L != 0
886 || (i + 1 < PMP_ENTRIES
887 && self.pmpcfg[i + 1] & PMP_L != 0
888 && self.pmpcfg[i + 1] & PMP_A == PMP_TOR)
889 }
890}
891
892struct Outcome {
893 next_pc: u64,
894 wrote_mcycle: bool,
895 wrote_minstret: bool,
896}