-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSimulator.py
242 lines (202 loc) · 9.53 KB
/
Simulator.py
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
import sys
input_file="./s_test2.txt"
output_file="./s2_output.txt"
a=open(output_file,"w")
a.close()
class RISC_V_Simulator:
def __init__(self):
self.registers = [0] * 32
self.registers[2]=256
self.memory= [0] * 32
self.pc= 0
def int_to_bin(self,num,width=32): #returns with 0b remove if needed using slicing
num=int(num)
width=width-1
if num<0:
num=(2**(width))+num
output="0b1"+format(num,f'0{width}b')
return output
output="0b0"+format(num,f'0{width}b')
return output
def sext(self,bin,width):
nw=width-len(bin)
return (bin[0]*nw)+bin
def bin_to_int(self,bin,signed):
bin=str(bin)
if signed==1:
if bin[0]=='1':
width=len(bin)-1
num=(2**width)-int(bin[1:],2)
return -num
return int(bin[1:],2)
elif signed==0:
return int(bin,2)
def register_output(self):
output=self.int_to_bin(4*(self.pc),32)
for i in self.registers:
output=output+ " " + self.int_to_bin(i,32)
output=output+"\n"
with open(output_file,"a") as file:
file.write(output)
def memory_output(self):
output=""
for i,j in enumerate(self.memory):
output=output+"0x"+format(4*i+65536,"08x")+":"+self.int_to_bin(j,32)+"\n"
with open(output_file,"a") as file:
file.write(output)
def rtype(self, ins, ):
rd = ins[::-1][7:12][::-1]
rs1 = ins[::-1][15:20][::-1]
rs2 = ins[::-1][20:25][::-1]
funct3 = ins[::-1][12:15][::-1]
funct7 = ins[::-1][25:32][::-1]
if funct3 == '000' and funct7 == '0000000': # ADD
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] + self.registers[self.bin_to_int(rs2, 0)]
elif funct3 == '000' and funct7 == '0100000': # SUB
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] - self.registers[self.bin_to_int(rs2, 0)]
elif funct3 == '111' and funct7 == '0000000': # AND
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] & self.registers[self.bin_to_int(rs2, 0)]
elif funct3 == '110' and funct7 == '0000000': # OR
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] | self.registers[self.bin_to_int(rs2, 0)]
elif funct3 == '100' and funct7 == '0000000': # XOR
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] ^ self.registers[self.bin_to_int(rs2, 0)]
elif funct3 == '001'and funct7== '0000000': #SLL
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] << self.bin_to_int(self.int_to_bin( self.registers[self.bin_to_int(rs2, 0)] )[2:][-5:],0)
elif funct3 == '010' and funct7=='0000000': # SLT
self.registers[self.bin_to_int(rd, 0)] = 1 if self.registers[self.bin_to_int(rs1, 0)] < self.registers[self.bin_to_int(rs2, 0)] else 0
elif funct3 == '011' and funct7=='0000000': # SLTU
self.registers[self.bin_to_int(rd, 0)] = 1 if self.bin_to_int(self.int_to_bin(self.registers[self.bin_to_int(rs1, 0)])[2:], 0) < self.bin_to_int(self.int_to_bin(self.registers[self.bin_to_int(rs2, 0)])[2:], 0) else 0
elif funct3 == '101' and funct7 == '0000000': # SRL
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] >> self.bin_to_int(self.int_to_bin( self.registers[self.bin_to_int(rs2, 0)] )[2:][-5:],0)
self.pc+=1
def i_type(self, instruction):
opcode = instruction[-7:]
imm = instruction[::-1][20:32][::-1]
imm_value = self.bin_to_int(imm, 1)
rd = instruction[::-1][7:12][::-1]
rs1 = instruction[::-1][15:20][::-1]
funct3 = instruction[::-1][12:15][::-1]
match opcode:
case '1100111': # jalr
rd = instruction[::-1][7:12][::-1]
rs1 = instruction[::-1][15:20][::-1]
imm = instruction[::-1][20:32][::-1]
imm_value = self.bin_to_int(imm, 1)
target_addr = self.registers[self.bin_to_int(rs1, 0)] + imm_value
self.registers[self.bin_to_int(rd, 0)] = 4 * (self.pc + 1)
self.pc = target_addr // 4
self.pc += 1
case '0010011': # sltiu
if funct3 == '011':
self.registers[self.bin_to_int(rd, 0)] = 1 if self.bin_to_int(self.int_to_bin(self.registers[self.bin_to_int(rs1, 0)])[2:], 0) < self.bin_to_int(imm, 0) else 0
if funct3 == '000':
self.registers[self.bin_to_int(rd, 0)] = self.registers[self.bin_to_int(rs1, 0)] + imm_value
self.pc += 1
case "0000011":
if funct3 == '010':
self.registers[self.bin_to_int(rd, 0)] = self.memory[(self.registers[self.bin_to_int(rs1, 0)] + imm_value - 16 ** 4) // 4]
self.pc += 1
def stype(self,ins):
imm=ins[::-1][25:32][::-1]+ins[::-1][7:12][::-1]
immval=self.bin_to_int(imm,1)
rs1=ins[::-1][15:20][::-1]
rs2=ins[::-1][20:25][::-1]
funct3=ins[::-1][12:15][::-1]
memadr=immval+self.registers[self.bin_to_int(rs1,0)] -16**4
self.memory[memadr//4]=self.registers[self.bin_to_int(rs2,0)]
self.pc+=1
def btype(self, instruction):
opcode = instruction[-7:]
imm = instruction[-32]+instruction[-8]+instruction[-31:-25] + instruction[-12:-7] + '0'
rs1 = self.bin_to_int(instruction[::-1][15:20][::-1], 0)
rs2 = self.bin_to_int(instruction[::-1][20:25][::-1], 0)
funct3=instruction[::-1][12:15][::-1]
imm_value = self.bin_to_int(imm, 1)
rs1_value = self.registers[rs1]
rs2_value = self.registers[rs2]
# def sign_extend(value, bits):
# if value >> (bits - 1) & 1: # Check if the sign bit is set
# return value | ((1 << (32 - bits)) - 1) << bits
# return value
def signed_to_unsigned(value):
return self.bin_to_int(self.int_to_bin(value)[2:],0)
done=False
match funct3:
case '000': # beq
if rs1_value == rs2_value:
self.pc = self.pc + imm_value//4
done=True
case '001': # bne
if rs1_value != rs2_value:
self.pc = self.pc + imm_value//4
done=True
case '101': # bge
if rs1_value >= rs2_value:
self.pc = self.pc + imm_value//4
done=True
case '111': # bgeu
if signed_to_unsigned(rs1_value) >= signed_to_unsigned(rs2_value):
self.pc = self.pc + imm_value//4
done=True
case '110': # bltu
if signed_to_unsigned(rs1_value) < signed_to_unsigned(rs2_value):
self.pc = self.pc + imm_value//4
done=True
case '100': # blt
if rs1_value < rs2_value:
self.pc = self.pc + imm_value//4
done=True
if not done:
self.pc+=1
def utype(self,ins):
opcode=ins[-7:]
rd=ins[::-1][7:12][::-1]
rdint=self.bin_to_int(rd,0)
imm=ins[::-1][12:32][::-1]
if opcode == "0110111": #lui
self.registers[rdint]=self.bin_to_int(imm+"0"*12,1)
if opcode == "0010111": #auipc
self.registers[rdint]=self.bin_to_int(imm+"0"*12,1)+4*self.pc
self.pc+=1
def j_type(self, instruction):
# opcode=instruction[-7:]
rd=instruction[-12:-7]
imm=instruction[-32]+instruction[-20:-12]+instruction[-21]+instruction[-31:-21]+'0'
# imm[-21]=instruction[-32]
# imm[-11:-1]=instruction[-31:-21]
# imm[-12]=instruction[-21]
# imm[-20:-12]=instruction[-20:-12]
self.registers[self.bin_to_int(rd,0)]=4*self.pc+4
self.pc+=self.bin_to_int(self.sext(imm, 32), 1)//4 #imm 0 bit is 0
def execute(self, input_file):
read = open(input_file, 'r')
program = [line.strip() for line in read.read().splitlines() if line]
while self.pc < len(program):
print(self.pc)
if program[self.pc] == '00000000000000000000000001100011':
self.register_output()
break
opcode = program[self.pc][-7:]
# use match case to match opcodes and run your functions
match opcode:
case '0110011': # r_type
self.rtype(program[self.pc])
case '0000011' | '0010011' | '1100111': # i_type
self.i_type(program[self.pc])
case '0100011': # s_type
self.stype(program[self.pc])
case '1100011': # b_type
self.btype(program[self.pc])
case '0110111' | '0010111':
self.utype(program[self.pc])
case '1101111':
self.j_type(program[self.pc])
# check if the current instruction is the last one in the program
if self.pc == len(program) - 1:
break
self.register_output()
self.memory_output()
sim = RISC_V_Simulator()
sim.execute(input_file)
# with open(output_file, 'r') as f:
# print(f.read())