aboutsummaryrefslogtreecommitdiff
path: root/riscv/csrs.h
blob: c924a5211386854e5a2afd78bec3477e20b5f704 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
// See LICENSE for license details.
#ifndef _RISCV_CSRS_H
#define _RISCV_CSRS_H

#include "common.h"
#include "encoding.h"
// For reg_t:
#include "decode.h"
// For std::unordered_map
#include <unordered_map>
// For std::shared_ptr
#include <memory>
// For std::optional
#include <optional>
// For access_type:
#include "memtracer.h"
#include <cassert>
// For std::optional
#include <optional>

class processor_t;
struct state_t;

enum struct elp_t {
  NO_LP_EXPECTED = 0,
  LP_EXPECTED = 1,
};

// Parent, abstract class for all CSRs
class csr_t {
 public:
  csr_t(processor_t* const proc, const reg_t addr);

  // Throw exception if read/write disallowed.
  virtual void verify_permissions(insn_t insn, bool write) const;

  // read() returns the architectural value of this CSR. No permission
  // checking needed or allowed. Side effects not allowed.
  virtual reg_t read() const noexcept = 0;

  // write() updates the architectural value of this CSR. No
  // permission checking needed or allowed.
  // Child classes must implement unlogged_write()
  void write(const reg_t val) noexcept;

  virtual ~csr_t();

 protected:
  // Return value indicates success; false means no write actually occurred
  virtual bool unlogged_write(const reg_t val) noexcept = 0;

  // Record this CSR update (which has already happened) in the commit log
  void log_write() const noexcept;

  // Record a write to an alternate CSR (e.g. minstreth instead of minstret)
  void log_special_write(const reg_t address, const reg_t val) const noexcept;

  // What value was written to this reg? Default implementation simply
  // calls read(), but a few CSRs are special.
  virtual reg_t written_value() const noexcept;

  processor_t* const proc;
  state_t* const state;
 public:
  const reg_t address;
 private:
  const unsigned csr_priv;
  const bool csr_read_only;

  // For access to written_value() and unlogged_write():
  friend class rv32_high_csr_t;
  friend class rv32_low_csr_t;
};

typedef std::shared_ptr<csr_t> csr_t_p;

// Basic CSRs, with XLEN bits fully readable and writable.
class basic_csr_t: public csr_t {
 public:
  basic_csr_t(processor_t* const proc, const reg_t addr, const reg_t init);

  virtual reg_t read() const noexcept override {
    return val;
  }

 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t val;
};

class pmpaddr_csr_t: public csr_t {
 public:
  pmpaddr_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  virtual reg_t read() const noexcept override;

  // Does a 4-byte access at the specified address match this PMP entry?
  bool match4(reg_t addr) const noexcept;

  // Does the specified range match only a proper subset of this page?
  bool subset_match(reg_t addr, reg_t len) const noexcept;

  // Is the specified access allowed given the pmpcfg privileges?
  bool access_ok(access_type type, reg_t mode, bool hlvx) const noexcept;

  // To check lock bit status from outside like mseccfg
  bool is_locked() const noexcept {
    return cfg & PMP_L;
  }

 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  // Assuming this is configured as TOR, return address for top of
  // range. Also forms bottom-of-range for next-highest pmpaddr
  // register if that one is TOR.
  reg_t tor_paddr() const noexcept;

  // Assuming this is configured as TOR, return address for bottom of
  // range. This is tor_paddr() from the previous pmpaddr register.
  reg_t tor_base_paddr() const noexcept;

  // Assuming this is configured as NAPOT or NA4, return mask for paddr.
  // E.g. for 4KiB region, returns 0xffffffff_fffff000.
  reg_t napot_mask() const noexcept;

  bool next_locked_and_tor() const noexcept;
  reg_t val;
  friend class pmpcfg_csr_t;  // so he can access cfg
  uint8_t cfg;
  const size_t pmpidx;
};

typedef std::shared_ptr<pmpaddr_csr_t> pmpaddr_csr_t_p;

class pmpcfg_csr_t: public csr_t {
 public:
  pmpcfg_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class mseccfg_csr_t: public basic_csr_t {
 public:
  mseccfg_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  bool get_mml() const noexcept;
  bool get_mmwp() const noexcept;
  bool get_rlb() const noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

typedef std::shared_ptr<mseccfg_csr_t> mseccfg_csr_t_p;

// For CSRs that have a virtualized copy under another name. Each
// instance of virtualized_csr_t will read/write one of two CSRs,
// based on state.v. E.g. sscratch, stval, etc.
//
// Example: sscratch and vsscratch are both instances of basic_csr_t.
// The csrmap will contain a virtualized_csr_t under sscratch's
// address, plus the vsscratch basic_csr_t under its address.

class virtualized_csr_t: public csr_t {
 public:
  virtualized_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt);

  virtual reg_t read() const noexcept override;
  // Instead of using state.v, explicitly request original or virtual:
  reg_t readvirt(bool virt) const noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
  csr_t_p orig_csr;
  csr_t_p virt_csr;
};

typedef std::shared_ptr<virtualized_csr_t> virtualized_csr_t_p;

// For mepc, sepc, and vsepc
class epc_csr_t: public csr_t {
 public:
  epc_csr_t(processor_t* const proc, const reg_t addr);

  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t val;
};

// For mtvec, stvec, and vstvec
class tvec_csr_t: public csr_t {
 public:
  tvec_csr_t(processor_t* const proc, const reg_t addr);

  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t val;
};

// For mcause, scause, and vscause
class cause_csr_t: public basic_csr_t {
 public:
  cause_csr_t(processor_t* const proc, const reg_t addr);

  virtual reg_t read() const noexcept override;
};

// For *status family of CSRs
class base_status_csr_t: public csr_t {
 public:
  base_status_csr_t(processor_t* const proc, const reg_t addr);

  bool field_exists(const reg_t which) {
    return (sstatus_write_mask & which) != 0;
  }

 protected:
  reg_t adjust_sd(const reg_t val) const noexcept;
  void maybe_flush_tlb(const reg_t newval) noexcept;
  const bool has_page;
  const reg_t sstatus_write_mask;
  const reg_t sstatus_read_mask;
 private:
  reg_t compute_sstatus_write_mask() const noexcept;
};

typedef std::shared_ptr<base_status_csr_t> base_status_csr_t_p;

// For vsstatus, which is its own separate architectural register
// (unlike sstatus)
class vsstatus_csr_t final: public base_status_csr_t {
 public:
  vsstatus_csr_t(processor_t* const proc, const reg_t addr);

  reg_t read() const noexcept override {
    return val;
  }

 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t val;
};

typedef std::shared_ptr<vsstatus_csr_t> vsstatus_csr_t_p;

class mstatus_csr_t final: public base_status_csr_t {
 public:
  mstatus_csr_t(processor_t* const proc, const reg_t addr);

  reg_t read() const noexcept override {
    return val;
  }

 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t compute_mstatus_initial_value() const noexcept;
  reg_t val;
};

typedef std::shared_ptr<mstatus_csr_t> mstatus_csr_t_p;

class mnstatus_csr_t final: public basic_csr_t {
 public:
  mnstatus_csr_t(processor_t* const proc, const reg_t addr);
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

// For RV32 CSRs that are split into two, e.g. mstatus/mstatush
// CSRW should only modify the lower half
class rv32_low_csr_t: public csr_t {
 public:
  rv32_low_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig);
  virtual reg_t read() const noexcept override;
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
  virtual reg_t written_value() const noexcept override;
 private:
  csr_t_p orig;
};

class rv32_high_csr_t: public csr_t {
 public:
  rv32_high_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig);
  virtual reg_t read() const noexcept override;
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
  virtual reg_t written_value() const noexcept override;
 private:
  csr_t_p orig;
};

class sstatus_proxy_csr_t final: public base_status_csr_t {
 public:
  sstatus_proxy_csr_t(processor_t* const proc, const reg_t addr, mstatus_csr_t_p mstatus);

  reg_t read() const noexcept override {
    return mstatus->read() & sstatus_read_mask;
  }

 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  mstatus_csr_t_p mstatus;
};

typedef std::shared_ptr<sstatus_proxy_csr_t> sstatus_proxy_csr_t_p;

class sstatus_csr_t: public virtualized_csr_t {
 public:
  sstatus_csr_t(processor_t* const proc, sstatus_proxy_csr_t_p orig, vsstatus_csr_t_p virt);

  // Set FS, VS, or XS bits to dirty
  void dirty(const reg_t dirties);
  // Return true if the specified bits are not 00 (Off)
  bool enabled(const reg_t which);
 private:
  sstatus_proxy_csr_t_p orig_sstatus;
  vsstatus_csr_t_p virt_sstatus;
};

typedef std::shared_ptr<sstatus_csr_t> sstatus_csr_t_p;

class misa_csr_t final: public basic_csr_t {
 public:
  misa_csr_t(processor_t* const proc, const reg_t addr, const reg_t max_isa);

  bool extension_enabled(unsigned char ext) const noexcept {
    assert(ext >= 'A' && ext <= 'Z');
    return (read() >> (ext - 'A')) & 1;
  }

  bool extension_enabled_const(unsigned char ext) const noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  const reg_t max_isa;
  const reg_t write_mask;
  reg_t dependency(const reg_t val, const char feature, const char depends_on) const noexcept;
};

typedef std::shared_ptr<misa_csr_t> misa_csr_t_p;

class mip_or_mie_csr_t: public csr_t {
 public:
  mip_or_mie_csr_t(processor_t* const proc, const reg_t addr);
  virtual reg_t read() const noexcept override;

  void write_with_mask(const reg_t mask, const reg_t val) noexcept;

 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override final;
  reg_t val;
 private:
  virtual reg_t write_mask() const noexcept = 0;
};

// mip is special because some of the bits are driven by hardware pins
class mip_csr_t: public mip_or_mie_csr_t {
 public:
  mip_csr_t(processor_t* const proc, const reg_t addr);
  virtual reg_t read() const noexcept override final;

  // Does not log. Used by external things (clint) that wiggle bits in mip.
  void backdoor_write_with_mask(const reg_t mask, const reg_t val) noexcept;
 private:
  virtual reg_t write_mask() const noexcept override;
};

typedef std::shared_ptr<mip_csr_t> mip_csr_t_p;

class mie_csr_t: public mip_or_mie_csr_t {
 public:
  mie_csr_t(processor_t* const proc, const reg_t addr);
 private:
  virtual reg_t write_mask() const noexcept override;
};

typedef std::shared_ptr<mie_csr_t> mie_csr_t_p;

// For sip, hip, hvip, vsip, sie, hie, vsie which are all just (masked
// & shifted) views into mip or mie. Each pair will have one of these
// objects describing the view, e.g. one for sip+sie, one for hip+hie,
// etc.
class generic_int_accessor_t {
 public:
  enum mask_mode_t { NONE, MIDELEG, HIDELEG };

  generic_int_accessor_t(state_t* const state,
                         const reg_t read_mask,
                         const reg_t ip_write_mask,
                         const reg_t ie_write_mask,
                         const mask_mode_t mask_mode,
                         const int shiftamt);
  reg_t ip_read() const noexcept;
  void ip_write(const reg_t val) noexcept;
  reg_t ie_read() const noexcept;
  void ie_write(const reg_t val) noexcept;
 private:
  state_t* const state;
  const reg_t read_mask;
  const reg_t ip_write_mask;
  const reg_t ie_write_mask;
  const bool mask_mideleg;
  const bool mask_hideleg;
  const int shiftamt;
  reg_t deleg_mask() const;
};

typedef std::shared_ptr<generic_int_accessor_t> generic_int_accessor_t_p;

// For all CSRs that are simply (masked & shifted) views into mip
class mip_proxy_csr_t: public csr_t {
 public:
  mip_proxy_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr);
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  generic_int_accessor_t_p accr;
};

// For all CSRs that are simply (masked & shifted) views into mie
class mie_proxy_csr_t: public csr_t {
 public:
  mie_proxy_csr_t(processor_t* const proc, const reg_t addr, generic_int_accessor_t_p accr);
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  generic_int_accessor_t_p accr;
};

class mideleg_csr_t: public basic_csr_t {
 public:
  mideleg_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class medeleg_csr_t: public basic_csr_t {
 public:
  medeleg_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  const reg_t hypervisor_exceptions;
};

// For CSRs with certain bits hardwired
class masked_csr_t: public basic_csr_t {
 public:
  masked_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  const reg_t mask;
};

class envcfg_csr_t: public masked_csr_t {
 public:
  envcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

// henvcfg.pbmte is read_only 0 when menvcfg.pbmte = 0
// henvcfg.stce is read_only 0 when menvcfg.stce = 0
// henvcfg.hade is read_only 0 when menvcfg.hade = 0
class henvcfg_csr_t final: public envcfg_csr_t {
 public:
  henvcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init, csr_t_p menvcfg);

  reg_t read() const noexcept override {
    return (menvcfg->read() | ~(MENVCFG_PBMTE | MENVCFG_STCE | MENVCFG_ADUE)) & masked_csr_t::read();
  }

  virtual void verify_permissions(insn_t insn, bool write) const override;

 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;

 private:
  csr_t_p menvcfg;
};

// For satp and vsatp
// These are three classes in order to handle the [V]TVM bits permission checks
class base_atp_csr_t: public basic_csr_t {
 public:
  base_atp_csr_t(processor_t* const proc, const reg_t addr);
  bool satp_valid(reg_t val) const noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t compute_new_satp(reg_t val) const noexcept;
};

class satp_csr_t: public base_atp_csr_t {
 public:
  satp_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

typedef std::shared_ptr<satp_csr_t> satp_csr_t_p;

class virtualized_satp_csr_t: public virtualized_csr_t {
 public:
  virtualized_satp_csr_t(processor_t* const proc, satp_csr_t_p orig, csr_t_p virt);
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  satp_csr_t_p orig_satp;
};

// Forward declaration
class smcntrpmf_csr_t;
typedef std::shared_ptr<smcntrpmf_csr_t> smcntrpmf_csr_t_p;

// For minstret and mcycle, which are always 64 bits, but in RV32 are
// split into high and low halves. The first class always holds the
// full 64-bit value.
class wide_counter_csr_t: public csr_t {
 public:
  wide_counter_csr_t(processor_t* const proc, const reg_t addr, smcntrpmf_csr_t_p config_csr);
  // Always returns full 64-bit value
  virtual reg_t read() const noexcept override;
  void bump(const reg_t howmuch) noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
  virtual reg_t written_value() const noexcept override;
 private:
  bool is_counting_enabled() const noexcept;
  reg_t val;
  smcntrpmf_csr_t_p config_csr;
};

typedef std::shared_ptr<wide_counter_csr_t> wide_counter_csr_t_p;

class time_counter_csr_t: public csr_t {
 public:
  time_counter_csr_t(processor_t* const proc, const reg_t addr);
  virtual reg_t read() const noexcept override;

  void sync(const reg_t val) noexcept;

 protected:
  virtual bool unlogged_write(const reg_t UNUSED val) noexcept override { return false; };
 private:
  reg_t shadow_val;
};

typedef std::shared_ptr<time_counter_csr_t> time_counter_csr_t_p;

// For a CSR that is an alias of another
class proxy_csr_t: public csr_t {
 public:
  proxy_csr_t(processor_t* const proc, const reg_t addr, csr_t_p delegate);
  virtual reg_t read() const noexcept override;
 protected:
  bool unlogged_write(const reg_t val) noexcept override;
 private:
  csr_t_p delegate;
};

// For a CSR with a fixed, unchanging value
class const_csr_t: public csr_t {
 public:
  const_csr_t(processor_t* const proc, const reg_t addr, reg_t val);
  virtual reg_t read() const noexcept override;
 protected:
  bool unlogged_write(const reg_t val) noexcept override;
 private:
  const reg_t val;
};

// For a CSR that is an unprivileged accessor of a privileged counter
class counter_proxy_csr_t: public proxy_csr_t {
 public:
  counter_proxy_csr_t(processor_t* const proc, const reg_t addr, csr_t_p delegate);
  virtual void verify_permissions(insn_t insn, bool write) const override;
 private:
  bool myenable(csr_t_p counteren) const noexcept;
};

class mevent_csr_t: public basic_csr_t {
 public:
  mevent_csr_t(processor_t* const proc, const reg_t addr);
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

// For machine-level CSRs that only exist with Hypervisor
class hypervisor_csr_t: public basic_csr_t {
 public:
  hypervisor_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

class hideleg_csr_t: public masked_csr_t {
 public:
  hideleg_csr_t(processor_t* const proc, const reg_t addr, csr_t_p mideleg);
  virtual reg_t read() const noexcept override;
 private:
  csr_t_p mideleg;
};

class hgatp_csr_t: public basic_csr_t {
 public:
  hgatp_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class tselect_csr_t: public basic_csr_t {
 public:
  tselect_csr_t(processor_t* const proc, const reg_t addr);
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class tdata1_csr_t: public csr_t {
 public:
  tdata1_csr_t(processor_t* const proc, const reg_t addr);
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class tdata2_csr_t: public csr_t {
 public:
  tdata2_csr_t(processor_t* const proc, const reg_t addr);
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class tdata3_csr_t: public csr_t {
 public:
  tdata3_csr_t(processor_t* const proc, const reg_t addr);
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class tinfo_csr_t: public csr_t {
 public:
  tinfo_csr_t(processor_t* const proc, const reg_t addr);
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t UNUSED val) noexcept override { return false; };
};

// For CSRs that are only writable from debug mode
class debug_mode_csr_t: public basic_csr_t {
 public:
  debug_mode_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

class dpc_csr_t: public epc_csr_t {
 public:
  dpc_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

class dcsr_csr_t: public csr_t {
 public:
  dcsr_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  virtual reg_t read() const noexcept override;
  void update_fields(const uint8_t cause, const reg_t prv,
                     const bool v, const elp_t pelp) noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 public:
  uint8_t prv;
  bool step;
  bool ebreakm;
  bool ebreaks;
  bool ebreaku;
  bool ebreakvs;
  bool ebreakvu;
  bool halt;
  bool v;
  uint8_t cause;
  elp_t pelp;
};

typedef std::shared_ptr<dcsr_csr_t> dcsr_csr_t_p;

class float_csr_t final: public masked_csr_t {
 public:
  float_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

typedef std::shared_ptr<float_csr_t> float_csr_t_p;

// For a CSR like FCSR, that is actually a view into multiple
// underlying registers.
class composite_csr_t: public csr_t {
 public:
  // We assume the lower_csr maps to bit 0.
  composite_csr_t(processor_t* const proc, const reg_t addr, csr_t_p upper_csr, csr_t_p lower_csr, const unsigned upper_lsb);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  csr_t_p upper_csr;
  csr_t_p lower_csr;
  const unsigned upper_lsb;
};

class seed_csr_t: public csr_t {
 public:
  seed_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class vector_csr_t: public basic_csr_t {
 public:
  vector_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init=0);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  // Write without regard to mask, and without touching mstatus.VS
  void write_raw(const reg_t val) noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t mask;
};

typedef std::shared_ptr<vector_csr_t> vector_csr_t_p;

// For CSRs shared between Vector and P extensions (vxsat)
class vxsat_csr_t: public masked_csr_t {
 public:
  vxsat_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class hstateen_csr_t: public masked_csr_t {
 public:
  hstateen_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init, uint8_t index);
  virtual reg_t read() const noexcept override;
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
protected:
  uint8_t index;
};

class sstateen_csr_t: public hstateen_csr_t {
 public:
  sstateen_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init, uint8_t index);
  virtual reg_t read() const noexcept override;
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class senvcfg_csr_t final: public envcfg_csr_t {
 public:
  senvcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

class stimecmp_csr_t: public basic_csr_t {
 public:
  stimecmp_csr_t(processor_t* const proc, const reg_t addr, const reg_t imask);
  virtual void verify_permissions(insn_t insn, bool write) const override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  reg_t intr_mask;
};

class virtualized_stimecmp_csr_t: public virtualized_csr_t {
 public:
  virtualized_stimecmp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

class scountovf_csr_t: public csr_t {
 public:
  scountovf_csr_t(processor_t* const proc, const reg_t addr);
  virtual void verify_permissions(insn_t insn, bool write) const override;
  virtual reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

class jvt_csr_t: public basic_csr_t {
 public:
  jvt_csr_t(processor_t* const proc, const reg_t addr, const reg_t init);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

// Sscsrind registers needs permissions checked
// (the original virtualized_csr_t does not call verify_permission of the underlying CSRs)
class virtualized_indirect_csr_t: public virtualized_csr_t {
 public:
  virtualized_indirect_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

class sscsrind_reg_csr_t : public csr_t {
 public:
  typedef std::shared_ptr<sscsrind_reg_csr_t> sscsrind_reg_csr_t_p;
  sscsrind_reg_csr_t(processor_t* const proc, const reg_t addr, csr_t_p iselect);
  reg_t read() const noexcept override;
  virtual void verify_permissions(insn_t insn, bool write) const override;
  void add_ireg_proxy(const reg_t iselect_val, csr_t_p proxy_csr);
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  csr_t_p iselect;
  std::unordered_map<reg_t, csr_t_p> ireg_proxy;
  csr_t_p get_reg() const noexcept;
};

// smcntrpmf_csr_t caches the previous state of the CSR in case a CSRW instruction
// modifies the state that should not be immediately visible to bump()
class smcntrpmf_csr_t : public masked_csr_t {
 public:
  smcntrpmf_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
  reg_t read_prev() const noexcept;
  void reset_prev() noexcept;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
 private:
  std::optional<reg_t> prev_val;
};

// srmcfg CSR provided by Ssqosid extension
class srmcfg_csr_t: public masked_csr_t {
 public:
  srmcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};

class hvip_csr_t : public basic_csr_t {
 public:
  hvip_csr_t(processor_t* const proc, const reg_t addr, const reg_t init);
  reg_t read() const noexcept override;
 protected:
  virtual bool unlogged_write(const reg_t val) noexcept override;
};

typedef std::shared_ptr<hvip_csr_t> hvip_csr_t_p;

// ssp CSR provided by CFI Zicfiss extension
class ssp_csr_t final : public masked_csr_t {
 public:
  ssp_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init);
  virtual void verify_permissions(insn_t insn, bool write) const override;
};
#endif