aboutsummaryrefslogtreecommitdiff
path: root/model/postlude/fetch.sail
blob: 0b1bfd87ef07918c1d3faf58c7ac0523ba9db768 (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
// =======================================================================================
// This Sail RISC-V architecture model, comprising all files and
// directories except where otherwise noted is subject the BSD
// two-clause license in the LICENSE file.
//
// SPDX-License-Identifier: BSD-2-Clause
// =======================================================================================

// Current fetch hooks for RISC-V extensions call extensions
// to check PC validity *before* standard fetch processing checks.

private function isRVC(h : half) -> bool = not(h[1 .. 0] == 0b11)

private function fetch() -> FetchResult = {
  // fetch PC check for extensions: extensions return a transformed PC to fetch,
  // but any exceptions use the untransformed PC.
  // TODO: Add a parameter to try_step() to allow forcing the fetch result and use that instead.

  if get_config_rvfi()
  then return rvfi_fetch();

  match ext_fetch_check_pc(PC, PC) {
    Some(e) => return F_Ext_Error(e),
    None()  => (),
  };

  if   (PC[0] != 0b0 | (PC[1] != 0b0 & not(currentlyEnabled(Ext_Zca))))
  then return F_Error(E_Fetch_Addr_Align(), PC);

  match translateAddr(Virtaddr(PC), InstructionFetch()) {
    Err(e, _)    => F_Error(e, PC),
    Ok(ppclo, _) => {
      // split instruction fetch into 16-bit granules to handle RVC, as
      // well as to generate precise fault addresses in any fetch
      // exceptions.
      match mem_read(InstructionFetch(), ppclo, 2, false, false, false) {
        Err(e)  => F_Error(e, PC),
        Ok(ilo) =>
          if   isRVC(ilo)
          then F_RVC(ilo)
          else {
            // fetch PC check for the next instruction granule
            let PC_hi = PC + 2;
            match ext_fetch_check_pc(PC, PC_hi) {
              Some(e) => return F_Ext_Error(e),
              None()  => (),
            };

            match translateAddr(Virtaddr(PC_hi), InstructionFetch()) {
              Err(e, _)    => F_Error(e, PC_hi),
              Ok(ppchi, _) =>
                match mem_read(InstructionFetch(), ppchi, 2, false, false, false) {
                  Err(e)  => F_Error(e, PC_hi),
                  Ok(ihi) => F_Base(append(ihi, ilo))
                }
            }
          }
      }
    }
  }
}