-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtiny-arm.sail
174 lines (143 loc) · 5.17 KB
/
tiny-arm.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
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
union ast = {
LoadRegister : (reg_index, reg_index, reg_index),
StoreRegister : (reg_index, reg_index, reg_index),
ExclusiveOr : (reg_index, reg_index, reg_index),
DataMemoryBarrier : unit,
CompareAndBranch : (reg_index, bits(64)),
}
val decode : bits(32) -> option(ast)
scattered function decode
val execute : ast -> unit
scattered function execute
/* LoadStoreRegister: LDR and STR */
val decodeLoadStoreRegister : (bits(2), bits(5), bits(3), bit, bits(5), bits(5)) -> option(ast)
function clause decode (0b11@0b111@0b0@0b00@(opc:bits(2))@0b1@(Rm:bits(5))@(option_v:bits(3))@[S]@0b10@(Rn:bits(5))@(Rt:bits(5))) = {
decodeLoadStoreRegister(opc, Rm, option_v, S, Rn, Rt)
}
function decodeLoadStoreRegister (opc, Rm, option_v, S, Rn, Rt) = {
let t : reg_index = unsigned(Rt);
let n : reg_index = unsigned(Rn);
let m : reg_index = unsigned(Rm);
/* option_v == 0b011 and S == 1 means that the offset in Rm is used as is and not shifted or extended */
if option_v != 0b011 | S == bitone then None ()
else if opc == 0b00
then Some(LoadRegister((t,n,m)))
else if opc == 0b01
then Some(StoreRegister((t,n,m)))
else None ();
}
/* LDR Xt, [Xn, Xm] */
function clause execute LoadRegister(t, n, m) = {
_PC = _PC + 4;
/* Ask for the value of register Xn and record it in the local
* variable base_addr */
let base_addr = X(n);
/* Ask for the value of register Xm and record it in the local
* variable offset */
let offset = X(m);
/* Compute the address */
let addr = base_addr + offset;
/* Ask for the eight-byte value in memory starting from location
addr and record it in the local variable data */
let data = rMem(addr);
/* Ask for the value of data to be written to register Xt */
X(t) = data;
}
/* STR Xt, [Xn, Xm] */
function clause execute StoreRegister(t, n, m) = {
_PC = _PC + 4;
/* Ask for the value of register Xn and record it in the local
* variable base_addr */
let base_addr = X(n);
/* Ask for the value of register Xm and record it in the local
* variable offset */
let offset = X(m);
/* Compute the address */
let addr = base_addr + offset;
/* Announce that a store into the eight bytes of memory starting
* from location addr will be performed later */
wMem_Addr(addr);
/* Ask for the value of register Xt and record it in the local
* variable data */
let data = X(t);
/* Ask for the value of data to be stored into the eight bytes of
* memory starting from location addr */
wMem(addr, data);
}
/* Exclusive OR: EOR */
val decodeExclusiveOr : (bit, bits(2), bit, bits(5), bits(6), bits(5), bits(5)) -> option(ast)
function clause decode ([sf]@0b10@0b01010@(shift:bits(2))@[N]@(Rm:bits(5))@(imm6:bits(6))@(Rn:bits(5))@(Rd:bits(5))) = {
decodeExclusiveOr(sf, shift, N, Rm, imm6, Rn, Rd)
}
function decodeExclusiveOr (sf, shift, N, Rm, imm6, Rn, Rd) = {
let d : reg_index = unsigned(Rd);
let n : reg_index = unsigned(Rn);
let m : reg_index = unsigned(Rm);
if sf == bitzero & imm6[5] == bitone then None ()
else if imm6 != 0b000000 then None ()
else Some(ExclusiveOr((d,n,m)));
}
/* EOR Xd, Xn, Xm */
function clause execute ExclusiveOr(d, n, m) = {
/* Ask for the value of register Xn and record it in the local
* variable operand1 */
let operand1 = X(n);
/* Ask for the value of register Xm and record it in the local
* variable operand2 */
let operand2 = X(m);
/* Compute the bitwise exclusive OR, and ask for the value of
* the result to be written to register Xd */
X(d) = operand1 ^ operand2;
}
/* DMB */
val decodeDataMemoryBarrier : bits(4) -> option(ast)
function clause decode (0b1101010100@0b0@0b00@0b011@0b0011@(CRm : bits(4))@0b1@0b01@0b11111) = {
decodeDataMemoryBarrier(CRm)
}
function decodeDataMemoryBarrier(CRm) = {
if CRm != 0b1111 then None ()
else Some(DataMemoryBarrier());
}
function clause execute DataMemoryBarrier() = {
dataMemoryBarrier();
}
/* CompareAndBranch: CBZ */
val decodeCompareAndBranch : (bits(19), bits(5)) -> option(ast)
function clause decode (0b1@0b011010@0b0@(imm19:bits(19))@(Rt:bits(5))) = {
decodeCompareAndBranch(imm19, Rt)
}
function decodeCompareAndBranch(imm19, Rt) = {
let t : reg_index = unsigned(Rt);
let offset : bits(64) = sail_sign_extend(imm19@0b00,64);
Some(CompareAndBranch(t,offset));
}
/* CBZ Xt, <offset> */
function clause execute CompareAndBranch(t, offset) = {
/* Ask for the value of register Xt and record it in the local
* variable operand */
let operand = X(t);
/* Check if operand is 0 */
if operand == 0x0000000000000000 then {
/* Ask for the value of the program counter register and record it
* in the local variable base */
let base = PC();
/* Compute the address */
let addr = base + offset;
/* Ask for the value of result to be written to the program counter
* register */
PC() = addr;
}
else _PC = _PC + 4;
}
// This needs to be the last clause
function clause decode(_) = { None() }
// Simple top level fetch and execute loop.
val fetch_and_execute : unit -> unit
function fetch_and_execute () = {
let machineCode = iFetch(_PC);
let instr = decode(machineCode);
match instr {
Some (instr) => execute(instr),
None () => assert (false, "Unsupported Encoding")
}
}