forked from riscv/sail-riscv
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathriscv_step.sail
139 lines (125 loc) · 4.5 KB
/
riscv_step.sail
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
/*=======================================================================================*/
/* 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 */
/*=======================================================================================*/
/* The emulator fetch-execute-interrupt dispatch loop. */
/* returns whether to increment the step count in the trace */
function step(step_no : int) -> bool = {
/* for step extensions */
ext_pre_step_hook();
/*
* This records whether or not minstret should be incremented when
* the instruction is retired. Since retirement occurs before CSR
* writes we initialise it based on mcountinhibit here, before
* mcountinhibit is potentially changed. We also mark minstret(h) as not
* having been explicitly written yet.
*/
minstret_increment = should_inc_minstret(cur_privilege);
minstret_write = None();
minstreth_write = None();
let (retired, stepped) : (Retired, bool) =
match dispatchInterrupt(cur_privilege) {
Some(intr, priv) => {
if get_config_print_instr()
then print_bits("Handling interrupt: ", interruptType_to_bits(intr));
handle_interrupt(intr, priv);
(RETIRE_FAIL, false)
},
None() => {
/* the extension hook interposes on the fetch result */
match ext_fetch_hook(fetch()) {
/* extension error */
F_Ext_Error(e) => {
ext_handle_fetch_check_error(e);
(RETIRE_FAIL, false)
},
/* standard error */
F_Error(e, addr) => {
handle_mem_exception(virtaddr(addr), e);
(RETIRE_FAIL, false)
},
/* non-error cases: */
F_RVC(h) => {
sail_instr_announce(h);
instbits = zero_extend(h);
let ast = ext_decode_compressed(h);
if get_config_print_instr()
then {
print_instr("[" ^ dec_str(step_no) ^ "] [" ^ to_str(cur_privilege) ^ "]: " ^ BitStr(PC) ^ " (" ^ BitStr(h) ^ ") " ^ to_str(ast));
};
/* check for RVC once here instead of every RVC execute clause. */
if extensionEnabled(Ext_Zca) then {
nextPC = PC + 2;
(execute(ast), true)
} else {
handle_illegal();
(RETIRE_FAIL, true)
}
},
F_Base(w) => {
sail_instr_announce(w);
instbits = zero_extend(w);
let ast = ext_decode(w);
if get_config_print_instr()
then {
print_instr("[" ^ dec_str(step_no) ^ "] [" ^ to_str(cur_privilege) ^ "]: " ^ BitStr(PC) ^ " (" ^ BitStr(w) ^ ") " ^ to_str(ast));
};
nextPC = PC + 4;
(execute(ast), true)
}
}
}
};
tick_pc();
// Only increment minstret if the instruction retired successfully.
if retired != RETIRE_SUCCESS then minstret_increment = false;
update_minstret();
/* for step extensions */
ext_post_step_hook();
stepped
}
function loop () : unit -> unit = {
let insns_per_tick = plat_insns_per_tick();
var i : int = 0;
var step_no : int = 0;
while not(htif_done) do {
let stepped = step(step_no);
if stepped then {
step_no = step_no + 1;
if get_config_print_instr() then {
print_step()
};
sail_end_cycle()
};
/* check htif exit */
if htif_done then {
let exit_val = unsigned(htif_exit_code);
if exit_val == 0 then print("SUCCESS")
else print_int("FAILURE: ", exit_val);
} else {
/* update time */
i = i + 1;
if i == insns_per_tick then {
tick_clock();
/* for now, we drive the platform i/o at every clock tick. */
tick_platform();
i = 0;
}
}
}
}
// Chip reset. This only does the minimum resets required by the RISC-V spec.
function reset() -> unit = {
reset_sys();
reset_vmem();
// To allow model extensions (code outside this repo) to perform additional reset.
ext_reset();
}
// Initialize model state. This is only called once; not for every chip reset.
function init_model() -> unit = {
init_platform();
reset();
}