-
Notifications
You must be signed in to change notification settings - Fork 61
/
mmu.js
204 lines (185 loc) · 7.16 KB
/
mmu.js
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
// simulated memory management unit,
// needs to intercept all memory loading calls
// CONSTANTS HERE
var PTE_V = 0x1;
var PTE_T = 0x2;
var PTE_G = new Long(0x4, 0x0);
var PTE_UR = 0x8;
var PTE_UW = 0x10;
var PTE_UX = 0x20;
var PTE_SR = 0x40;
var PTE_SW = 0x80;
var PTE_SX = 0x100;
// [todo] - simple TLB (try just a dictionary)
var TLBSIZE = 524288;
var TLB = new Uint32Array(TLBSIZE);
var ITLBSIZE = 4;
var ITLB = new Uint32Array(ITLBSIZE);
var ITLBstuff = new Uint32Array(ITLBSIZE);
//var TLBON = true;
//var TLBcount = 0;
//var NONcount = 0;
//var Totcount = 0;
function insttranslate(addrlo, access_type) {
var origaddrVPN = addrlo >>> 13;
var pte;
var paddr;
var pgoff;
var pgbase;
var addr;
if (ITLBstuff[origaddrVPN & 0x3] == origaddrVPN) {
// UNSAFE - although TLB contains only valid translations, not checking S bit
return (ITLB[origaddrVPN & 0x3] & 0xFFFFE000) | (addrlo & 0x1FFF);
} else {
addr = new Long(addrlo, addrlo >> 31)
pte = walk(addr).getLowBitsUnsigned();
}
paddr = (pte & 0xFFFFE000) | (addrlo & 0x1FFF);
var mode = RISCV.priv_reg[0x50A];
// permissions check
if (mode & 0x1) {
// we are in supervisor mode
if (access_type == CONSTS.EXEC && (pte & PTE_SX)) {
// "short" the fastest path (valid instruction)
// only valid translations in the TLB
ITLB[origaddrVPN & 0x3] = pte;
ITLBstuff[origaddrVPN & 0x3] = origaddrVPN;
return paddr;
} else {
addr = new Long(addrlo, addrlo >> 31);
if (access_type == CONSTS.EXEC && !(pte & PTE_SX)) {
RISCV.excpTrigg = new RISCVTrap("Instruction Access Fault", addr);
} else if (access_type == CONSTS.READ && !(pte & PTE_SR)) {
RISCV.excpTrigg = new RISCVTrap("Load Access Fault", addr);
} else if (access_type == CONSTS.WRITE && !(pte & PTE_SW)) {
RISCV.excpTrigg = new RISCVTrap("Store Access Fault", addr);
}
}
} else {
if (access_type == CONSTS.EXEC && (pte & PTE_UX)) {
// "short" the fastest path (valid instruction)
// only valid translations in the TLB
ITLB[origaddrVPN & 0x3] = pte;
ITLBstuff[origaddrVPN & 0x3] = origaddrVPN;
return paddr;
} else {
addr = new Long(addrlo, addrlo >> 31);
if (access_type == CONSTS.EXEC && !(pte & PTE_UX)) {
RISCV.excpTrigg = new RISCVTrap("Instruction Access Fault", addr);
} else if (access_type == CONSTS.READ && !(pte & PTE_UR)) {
RISCV.excpTrigg = new RISCVTrap("Load Access Fault", addr);
} else if (access_type == CONSTS.WRITE && !(pte & PTE_UW)) {
RISCV.excpTrigg = new RISCVTrap("Store Access Fault", addr);
}
}
}
return paddr;
}
// performs address translation
// addr MUST BE A LONG
function translate(addr, access_type) {
//Totcount += 1;
var origaddr = addr.getLowBitsUnsigned();
// if ((origaddr & 0xFF000000) == 0x55000000) {
// addr = new Long(origaddr, 0x155);
// }
var origaddrVPN = origaddr >>> 13;
var pte;
var paddr;
var pgoff;
var pgbase;
pte = TLB[origaddrVPN];
if (!pte) {
//NONcount += 1;
pte = walk(addr).getLowBitsUnsigned();
TLB[origaddrVPN] = pte;
}
paddr = (pte & 0xFFFFE000) | (origaddr & 0x1FFF);
var mode = RISCV.priv_reg[0x50A];
// permissions check
if (mode & 0x1) {
// we are in supervisor mode
if (access_type == CONSTS.EXEC && (pte & PTE_SX)) {
// "short" the fastest path (valid instruction)
return paddr;
}
if (access_type == CONSTS.EXEC && !(pte & PTE_SX)) {
RISCV.excpTrigg = new RISCVTrap("Instruction Access Fault", addr);
} else if (access_type == CONSTS.READ && !(pte & PTE_SR)) {
RISCV.excpTrigg = new RISCVTrap("Load Access Fault", addr);
} else if (access_type == CONSTS.WRITE && !(pte & PTE_SW)) {
RISCV.excpTrigg = new RISCVTrap("Store Access Fault", addr);
}
} else {
if (access_type == CONSTS.EXEC && (pte & PTE_UX)) {
// "short" the fastest path (valid instruction)
return paddr;
}
if (access_type == CONSTS.EXEC && !(pte & PTE_UX)) {
RISCV.excpTrigg = new RISCVTrap("Instruction Access Fault", addr);
} else if (access_type == CONSTS.READ && !(pte & PTE_UR)) {
RISCV.excpTrigg = new RISCVTrap("Load Access Fault", addr);
} else if (access_type == CONSTS.WRITE && !(pte & PTE_UW)) {
RISCV.excpTrigg = new RISCVTrap("Store Access Fault", addr);
}
}
return paddr;
}
var LONG3FF = new Long(0x3FF, 0x0);
// does the page table walk only - no permission checks here
// vaddr is Long
function walk(vaddr) {
// [todo] - add additional checking from the top of mmu.cc's walk here later
// var pte = new Long(0x0, 0x0);
var ptbr = RISCV.priv_reg[PCR["CSR_PTBR"]["num"]]; // this is a Long
// main walk for loop
var idx = (vaddr.shiftRightUnsigned((33))).and(LONG3FF);
var pte_addr = ptbr.add(idx.shiftLeft(3));
var pt_data = RISCV.load_double_from_mem_raw(pte_addr);
var pt_data_low = pt_data.getLowBitsUnsigned();
if (pt_data_low & PTE_V == 0) {
// INVALID MAPPING
return Long.ZERO;
} else if ((pt_data_low & PTE_T) != 0) {
// Next level of page table
ptbr = (pt_data.shiftRightUnsigned(0xD)).shiftLeft(0xD);
} else {
// The actual pte
var vpn = vaddr.shiftRightUnsigned(0xD);
pt_data = pt_data.or((vpn.and(((Long.ONE).shiftLeft(20)).subtract(Long.ONE))).shiftLeft(0xD));
//supposed to be a mem bounds fault check here but ignore for now:
return pt_data;
}
var idx = (vaddr.shiftRightUnsigned((23))).and(LONG3FF);
var pte_addr = ptbr.add(idx.shiftLeft(3));
var pt_data = RISCV.load_double_from_mem_raw(pte_addr);
var pt_data_low = pt_data.getLowBitsUnsigned();
if (pt_data_low & PTE_V == 0) {
// INVALID MAPPING
return Long.ZERO;
} else if ((pt_data_low & PTE_T) != 0) {
// Next level of page table
ptbr = (pt_data.shiftRightUnsigned(0xD)).shiftLeft(0xD);
} else {
// The actual pte
var vpn = vaddr.shiftRightUnsigned(0xD);
pt_data = pt_data.or((vpn.and(((Long.ONE).shiftLeft(10)).subtract(Long.ONE))).shiftLeft(0xD));
//supposed to be a mem bounds fault check here but ignore for now:
return pt_data;
}
var idx = (vaddr.shiftRightUnsigned(13)).and(LONG3FF);
var pte_addr = ptbr.add(idx.shiftLeft(3));
var pt_data = RISCV.load_double_from_mem_raw(pte_addr);
var pt_data_low = pt_data.getLowBitsUnsigned();
if (pt_data_low & PTE_V == 0) {
// INVALID MAPPING
return Long.ZERO;
} else if ((pt_data_low & PTE_T) != 0) {
// Next level of page table
ptbr = (pt_data.shiftRightUnsigned(0xD)).shiftLeft(0xD);
} else {
// The actual pte
//supposed to be a mem bounds fault check here but ignore for now:
return pt_data;
}
}