Skip to content

Commit aa67c42

Browse files
committed
Fix #15: Implement a proper CSR file
Dummy implementation of all known but unsupported CSRs
1 parent 91ff4a9 commit aa67c42

File tree

4 files changed

+145
-81
lines changed

4 files changed

+145
-81
lines changed

TODO.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44

55
- Fix boot with the newest kernels (it hangs, unknown why)
66

7-
- CSR handling is still a bit suspect
8-
The access checks looks broken and we shouldn't have a CSR array but instead
9-
individually implement CSR registers we support and trap access to everything else.
10-
need to cross check the read/write CSR behavior against Dromajo
7+
- CSR handling is still a bit suspect; the access checks looks
8+
broken. Need to cross check the read/write CSR behavior against
9+
Dromajo
1110

1211
- Go though all explicit usage of cpu.f[] and look for mistakes
1312

1413
- Pass all of riscv-test (status: debug, svnapot, and lots of FP.
15-
Might punt on debug and svnapot)
14+
Might punt on debug and svnapot for now)
1615

1716
- Pass all of riscof
1817

src/cpu.rs

Lines changed: 83 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ pub struct Cpu {
173173

174174
// Supervisor and CSR
175175
pub cycle: u64,
176-
csr: Box<[u64]>, // XXX this should be replaced with individual registers
176+
csr: csr::CsrFile,
177177
reservation: Option<u64>,
178178

179179
// Wait-For-Interrupt; relax and await further instruction
@@ -237,15 +237,11 @@ impl Cpu {
237237
cycle: 0,
238238
wfi: false,
239239
pc: 0,
240-
csr: vec![0; 4096].into_boxed_slice(), // XXX MUST GO AWAY SOON
240+
csr: CsrFile::new(),
241241
mmu,
242242
reservation: None,
243243
flush_icache: false,
244244
};
245-
cpu.csr[Csr::Misa as usize] = 1 << 63; // RV64
246-
for c in "SUIMAFDC".bytes() {
247-
cpu.csr[Csr::Misa as usize] |= 1 << (c as usize - 65);
248-
}
249245
cpu.mmu.mstatus = 2 << MSTATUS_UXL_SHIFT | 2 << MSTATUS_SXL_SHIFT | 3 << MSTATUS_MPP_SHIFT;
250246
cpu.write_x(x(11), 0x1020); // start of DTB (XXX could put that elsewhere);
251247
cpu
@@ -334,7 +330,7 @@ impl Cpu {
334330
fn step_cpu(&mut self, uop_cache: &mut IntMap<u64, Uop>) -> Result<(), Exception> {
335331
self.cycle = self.cycle.wrapping_add(1);
336332
if self.wfi {
337-
if self.mmu.mip & self.read_csr_raw(Csr::Mie) != 0 {
333+
if self.mmu.mip & self.csr.mie != 0 {
338334
self.wfi = false;
339335
}
340336
return Ok(());
@@ -400,7 +396,7 @@ impl Cpu {
400396
use self::Trap::SupervisorExternalInterrupt;
401397
use self::Trap::SupervisorSoftwareInterrupt;
402398
use self::Trap::SupervisorTimerInterrupt;
403-
let minterrupt = self.mmu.mip & self.read_csr_raw(Csr::Mie);
399+
let minterrupt = self.mmu.mip & self.csr.mie;
404400
if minterrupt == 0 {
405401
return;
406402
}
@@ -442,16 +438,16 @@ impl Cpu {
442438
// First, determine which privilege mode should handle the trap.
443439
// @TODO: Check if this logic is correct
444440
let mdeleg = if is_interrupt {
445-
self.read_csr_raw(Csr::Mideleg)
441+
self.csr.mideleg
446442
} else {
447-
self.read_csr_raw(Csr::Medeleg)
443+
self.csr.medeleg
448444
};
449445
let sdeleg = if is_interrupt {
450-
self.read_csr_raw(Csr::Sideleg)
446+
self.csr.sideleg
451447
} else {
452-
self.read_csr_raw(Csr::Sedeleg)
448+
self.csr.sedeleg
453449
};
454-
let pos = cause & 0xffff;
450+
let pos = cause & 63;
455451

456452
let new_priv_mode = if (mdeleg >> pos) & 1 == 0 {
457453
PrivMode::M
@@ -468,11 +464,11 @@ impl Cpu {
468464
let current_status = match self.mmu.prv {
469465
PrivMode::M => self.read_csr_raw(Csr::Mstatus),
470466
PrivMode::S => self.read_csr_raw(Csr::Sstatus),
471-
PrivMode::U => self.read_csr_raw(Csr::Ustatus),
467+
PrivMode::U => self.csr.ustatus,
472468
};
473469

474470
let ie = match new_priv_mode {
475-
PrivMode::M => self.read_csr_raw(Csr::Mie),
471+
PrivMode::M => self.csr.mie,
476472
PrivMode::S => self.read_csr_raw(Csr::Sie),
477473
PrivMode::U => self.read_csr_raw(Csr::Uie),
478474
};
@@ -582,16 +578,15 @@ impl Cpu {
582578
PrivMode::S => Csr::Stval,
583579
PrivMode::U => Csr::Utval,
584580
};
585-
let csr_tvec_address = match self.mmu.prv {
586-
PrivMode::M => Csr::Mtvec,
587-
PrivMode::S => Csr::Stvec,
588-
PrivMode::U => Csr::Utvec,
581+
self.pc = match self.mmu.prv {
582+
PrivMode::M => self.read_csr_raw(Csr::Mtvec),
583+
PrivMode::S => self.read_csr_raw(Csr::Stvec),
584+
PrivMode::U => self.read_csr_raw(Csr::Utvec),
589585
};
590586

591587
self.write_csr_raw(csr_epc_address, insn_addr);
592588
self.write_csr_raw(csr_cause_address, cause);
593589
self.write_csr_raw(csr_tval_address, exc.tval);
594-
self.pc = self.read_csr_raw(csr_tvec_address);
595590

596591
// Add 4 * cause if tvec has vector type address
597592
if self.pc & 3 != 0 {
@@ -663,6 +658,7 @@ impl Cpu {
663658
if self.mmu.prv == S && self.mmu.mstatus & MSTATUS_TVM != 0 {
664659
return illegal;
665660
}
661+
return Ok(self.mmu.satp);
666662
}
667663
_ => {}
668664
}
@@ -671,7 +667,6 @@ impl Cpu {
671667

672668
#[allow(clippy::cast_sign_loss)]
673669
fn write_csr(&mut self, csrno: u16, value: u64) -> Result<(), Exception> {
674-
let mut value = value;
675670
let illegal = Err(Exception {
676671
trap: Trap::IllegalInstruction,
677672
tval: 0,
@@ -687,10 +682,6 @@ impl Cpu {
687682
}
688683

689684
match csr {
690-
Csr::Mstatus => {
691-
let mask = MSTATUS_MASK & !(MSTATUS_VS | MSTATUS_UXL_MASK | MSTATUS_SXL_MASK);
692-
value = value & mask | self.mmu.mstatus & !mask;
693-
}
694685
Csr::Fflags | Csr::Frm | Csr::Fcsr => self.check_float_access_and_dirty(0)?,
695686
Csr::Cycle => {
696687
log::info!("** deny cycle writing");
@@ -708,6 +699,10 @@ impl Cpu {
708699
log::warn!("wrote illegal value {value:x} to satp");
709700
return illegal;
710701
}
702+
703+
self.mmu.satp = value;
704+
self.mmu.clear_page_cache();
705+
return Ok(());
711706
}
712707
_ => {}
713708
}
@@ -720,82 +715,96 @@ impl Cpu {
720715
#[allow(clippy::cast_sign_loss)]
721716
fn read_csr_raw(&self, csr: Csr) -> u64 {
722717
match csr {
718+
Csr::Cycle | Csr::Mcycle | Csr::Minstret => self.cycle,
719+
Csr::Fcsr => self.read_fcsr(),
723720
Csr::Fflags => u64::from(self.read_fflags()),
724721
Csr::Frm => self.read_frm() as u64,
725-
Csr::Fcsr => self.read_fcsr(),
726-
Csr::Sstatus => {
727-
let mut sstatus = self.mmu.mstatus;
728-
sstatus &= !MSTATUS_FS;
729-
sstatus |= u64::from(self.fs) << MSTATUS_FS_SHIFT;
730-
sstatus &= 0x8000_0003_000d_e162;
722+
Csr::Mcause => self.csr.mcause,
723+
Csr::Medeleg => self.csr.medeleg,
724+
Csr::Mepc => self.csr.mepc,
725+
Csr::Mhartid => self.csr.mhartid,
726+
Csr::Mideleg => self.csr.mideleg,
727+
Csr::Mie => self.csr.mie,
728+
Csr::Mip => self.mmu.mip,
729+
Csr::Misa => self.csr.misa,
730+
Csr::Mscratch => self.csr.mscratch,
731+
Csr::Mstatus => {
732+
let mut mstatus = self.mmu.mstatus;
733+
mstatus &= !MSTATUS_FS;
734+
mstatus |= u64::from(self.fs) << MSTATUS_FS_SHIFT;
731735
if self.fs == 3 {
732-
sstatus |= 1 << 63;
736+
mstatus |= 1 << 63;
733737
}
734-
sstatus
738+
mstatus
735739
}
736-
Csr::Mstatus => {
740+
Csr::Mtval => self.csr.mtval,
741+
Csr::Mtvec => self.csr.mtvec,
742+
Csr::Satp => self.mmu.satp,
743+
Csr::Scause => self.csr.scause,
744+
Csr::Sedeleg => self.csr.sedeleg,
745+
Csr::Sepc => self.csr.sepc,
746+
Csr::Sideleg => self.csr.sideleg,
747+
Csr::Sie => self.csr.mie & self.csr.mideleg,
748+
Csr::Sip => self.mmu.mip & self.csr.mideleg,
749+
Csr::Sscratch => self.csr.sscratch,
750+
Csr::Sstatus => {
737751
let mut mstatus = self.mmu.mstatus;
738752
mstatus &= !MSTATUS_FS;
739753
mstatus |= u64::from(self.fs) << MSTATUS_FS_SHIFT;
754+
mstatus &= 0x8000_0003_000d_e162;
740755
if self.fs == 3 {
741756
mstatus |= 1 << 63;
742757
}
743758
mstatus
744759
}
745-
Csr::Sie => self.csr[Csr::Mie as usize] & self.csr[Csr::Mideleg as usize],
746-
Csr::Sip => self.mmu.mip & self.csr[Csr::Mideleg as usize],
747-
Csr::Mip => self.mmu.mip,
760+
Csr::Stval => self.csr.stval,
761+
Csr::Stvec => self.csr.stvec,
748762
Csr::Time => self.mmu.get_clint().read_mtime(),
749-
Csr::Cycle | Csr::Mcycle | Csr::Minstret => self.cycle,
750-
Csr::Satp => self.mmu.satp,
751-
_ => self.csr[csr as usize],
763+
Csr::Ustatus => self.csr.ustatus,
764+
_ => 0,
752765
}
753766
}
754767

755768
fn write_csr_raw(&mut self, csr: Csr, value: u64) {
756769
match csr {
757-
Csr::Misa => {} // Not writable
770+
Csr::Mcycle => self.cycle = value,
771+
Csr::Fcsr => self.write_fcsr(value),
758772
Csr::Fflags => self.write_fflags((value & 31) as u8),
759773
Csr::Frm => self.write_frm(
760774
FromPrimitive::from_u64(value & 7).unwrap_or(RoundingMode::RoundNearestEven),
761775
),
762-
Csr::Fcsr => self.write_fcsr(value),
776+
Csr::Mcause => self.csr.mcause = value,
777+
Csr::Medeleg => self.csr.medeleg = value,
778+
Csr::Mepc => self.csr.mepc = value,
779+
Csr::Mhartid => self.csr.mhartid = value,
780+
Csr::Mideleg => self.csr.mideleg = value & 0x222,
781+
Csr::Mie => self.csr.mie = value,
782+
Csr::Mip => self.mmu.mip = value,
783+
Csr::Mscratch => self.csr.mscratch = value,
784+
Csr::Mstatus => {
785+
let mask = MSTATUS_MASK & !(MSTATUS_VS | MSTATUS_UXL_MASK | MSTATUS_SXL_MASK);
786+
self.mmu.mstatus = value & mask | self.mmu.mstatus & !mask;
787+
self.fs = ((value >> MSTATUS_FS_SHIFT) & 3) as u8;
788+
}
789+
Csr::Mtval => self.csr.mtval = value,
790+
Csr::Mtvec => self.csr.mtvec = value,
791+
Csr::Scause => self.csr.scause = value,
792+
Csr::Sedeleg => self.csr.sedeleg = value,
793+
Csr::Sepc => self.csr.sepc = value,
794+
Csr::Sideleg => self.csr.sideleg = value,
795+
Csr::Sie => self.csr.mie = self.csr.mie & !0x222 | value & 0x222,
796+
Csr::Sip => self.mmu.mip = value & 0x222 | self.mmu.mip & !0x222,
797+
Csr::Sscratch => self.csr.sscratch = value,
763798
Csr::Sstatus => {
764799
self.mmu.mstatus &= !0x8000_0003_000d_e162;
765800
self.mmu.mstatus |= value & 0x8000_0003_000d_e162;
766801
self.fs = ((value >> MSTATUS_FS_SHIFT) & 3) as u8;
767802
}
768-
Csr::Sie => {
769-
self.csr[Csr::Mie as usize] &= !0x222;
770-
self.csr[Csr::Mie as usize] |= value & 0x222;
771-
}
772-
Csr::Sip => {
773-
let mask = 0x222;
774-
self.mmu.mip = value & mask | self.mmu.mip & !mask;
775-
}
776-
Csr::Mip => {
777-
let mask = !0; // XXX 0x555 was too restrictive?? Stopped Ubuntu booting
778-
self.mmu.mip = value & mask | self.mmu.mip & !mask;
779-
}
780-
Csr::Mideleg => {
781-
self.csr[Csr::Mideleg as usize] = value & 0x222;
782-
}
783-
Csr::Mstatus => {
784-
self.mmu.mstatus = value;
785-
self.fs = ((value >> MSTATUS_FS_SHIFT) & 3) as u8;
786-
}
787-
Csr::Time => {
788-
// XXX This should trap actually
789-
self.mmu.get_mut_clint().write_mtime(value);
790-
}
791-
Csr::Satp => {
792-
self.mmu.satp = value;
793-
self.mmu.clear_page_cache();
794-
}
795-
/* Csr::Cycle | */ Csr::Mcycle => self.cycle = value,
796-
_ => {
797-
self.csr[csr as usize] = value;
798-
}
803+
Csr::Stval => self.csr.stval = value,
804+
Csr::Stvec => self.csr.stvec = value,
805+
Csr::Time => self.mmu.get_mut_clint().write_mtime(value), // XXX SHOULD trap
806+
Csr::Ustatus => self.csr.ustatus = value,
807+
_ => log::warn!("We are ignoring writes to {csr:?}"),
799808
}
800809
}
801810

@@ -1974,7 +1983,7 @@ mod test_cpu {
19741983
cpu.update_pc(MEMORY_BASE);
19751984

19761985
// Machine timer interrupt but mie in mstatus is not enabled yet
1977-
cpu.write_csr_raw(Csr::Mie, MIP_MTIP);
1986+
cpu.csr.mie = MIP_MTIP;
19781987
cpu.mmu.mip |= MIP_MTIP;
19791988
cpu.write_csr_raw(Csr::Mtvec, handler_vector);
19801989

src/csr.rs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ pub enum Csr {
3434
Mideleg = 0x303,
3535
Mie = 0x304,
3636
Mtvec = 0x305,
37-
Csr306 = 0x306,
37+
Mcounteren = 0x306,
3838
Menvcfg = 0x30a, // Unsupported Mostly Just Configure S Access To Timecmp
3939
Mscratch = 0x340,
4040
Mepc = 0x341,
@@ -148,6 +148,7 @@ pub const fn legal(csr: Csr) -> bool {
148148
| Csr::Instret
149149
| Csr::Marchid
150150
| Csr::Mcause
151+
| Csr::Mcounteren
151152
| Csr::Mcycle
152153
| Csr::Minstret
153154
| Csr::Medeleg
@@ -184,6 +185,61 @@ pub const fn legal(csr: Csr) -> bool {
184185
| Csr::Ustatus
185186
| Csr::Utval
186187
| Csr::Utvec
187-
| Csr::Csr306
188188
)
189189
}
190+
191+
pub struct CsrFile {
192+
pub mcause: u64,
193+
pub medeleg: u64,
194+
pub mepc: u64,
195+
pub mhartid: u64,
196+
pub mideleg: u64,
197+
pub mie: u64,
198+
pub misa: u64,
199+
pub mscratch: u64,
200+
pub mtval: u64,
201+
pub mtvec: u64,
202+
pub scause: u64,
203+
pub sedeleg: u64,
204+
pub sepc: u64,
205+
pub sideleg: u64,
206+
pub sscratch: u64,
207+
pub stval: u64,
208+
pub stvec: u64,
209+
pub ustatus: u64,
210+
}
211+
212+
impl Default for CsrFile {
213+
fn default() -> Self { Self::new() }
214+
}
215+
216+
impl CsrFile {
217+
#[must_use]
218+
pub fn new() -> Self {
219+
let mut misa = 1 << 63; // RV64
220+
for c in "SUIMAFDC".bytes() {
221+
misa |= 1 << (c as usize - 65);
222+
}
223+
224+
Self {
225+
mcause: 0,
226+
medeleg: 0,
227+
mepc: 0,
228+
mhartid: 0,
229+
mideleg: 0,
230+
mie: 0,
231+
misa,
232+
mscratch: 0,
233+
mtval: 0,
234+
mtvec: 0,
235+
scause: 0,
236+
sedeleg: 0,
237+
sepc: 0,
238+
sideleg: 0,
239+
sscratch: 0,
240+
stval: 0,
241+
stvec: 0,
242+
ustatus: 0,
243+
}
244+
}
245+
}

wasm/web/simmerv_wasm_bg.wasm

-14 KB
Binary file not shown.

0 commit comments

Comments
 (0)