> sa
242 |
243 | elif func == 0x06:
244 | # Srlv
245 | reg[r3] = reg[r2] >> min(reg[r1], 32)
246 |
247 | elif func == 0x22:
248 | # Sub
249 | reg[r3] = (reg[r1] - reg[r2]) & 0xFFFFFFFF
250 | if (reg[r1]>>31) == (reg[r2]>>31) and (reg[r1]>>31) != (reg[r3]>>31):
251 | program_end = True
252 | raise SimulationException('PC = %d: An overflow occurs when performing the sub operation.' % (pc))
253 |
254 | elif func == 0x23:
255 | # Subu
256 | reg[r3] = (reg[r1] - reg[r2]) & 0xFFFFFFFF
257 |
258 | elif func == 0x0C:
259 | # Syscall
260 | if reg[2] == 1:
261 | # Print integer
262 | output_data += str(get_signed(reg[4]))
263 |
264 | elif reg[2] == 4:
265 | # Print string
266 | output_data += read_string(reg[4])
267 |
268 | elif reg[2] == 5:
269 | # Read integer
270 | if len(input_data) > 0:
271 | try:
272 | reg[2] = int(input_data[0]) & 0xFFFFFFFF
273 | input_data = input_data[1:]
274 | except:
275 | pass
276 | else:
277 | raise SimulationInfoException('PC = %d: Waiting for integer input. Simulation paused.' % (pc))
278 |
279 | elif reg[2] == 8:
280 | # Read string
281 | if len(input_data) > 0:
282 | write_string(input_data[0], reg[4], reg[5])
283 | input_data = input_data[1:]
284 | else:
285 | raise SimulationInfoException('PC = %d: Waiting for string input. Simulation paused.' % (pc))
286 |
287 | elif reg[2] == 10:
288 | # Exit
289 | program_end = True
290 | return
291 |
292 | elif reg[2] == 11:
293 | # Print char
294 | output_data += chr(reg[4] & 0xFF)
295 |
296 | elif reg[2] == 12:
297 | # Read char
298 | if len(input_data) > 0:
299 | reg[4] = ord(input_data[0][0])
300 | input_data = input_data[1:]
301 | else:
302 | raise SimulationInfoException('PC = %d: Waiting for char input. Simulation paused.' % (pc))
303 |
304 | elif reg[2] == 30:
305 | # System time
306 | millis = int(round(time.time() * 1000))
307 | reg[4] = millis & 0xFFFFFFFF
308 | reg[5] = (millis>>32) & 0xFFFFFFFF
309 |
310 | elif reg[2] == 41:
311 | # Random int
312 | reg[4] = random.randint(0, 0xFFFFFFFF)
313 |
314 | elif reg[2] == 42:
315 | # Random int with range
316 | reg[4] = random.randint(0, reg[5]-1)
317 |
318 | else:
319 | raise SimulationException('PC = %d: Unsupported syscall operation %d.' % (pc, reg[2]))
320 |
321 | elif func == 0x26:
322 | # Xor
323 | reg[r3] = reg[r1] ^ reg[r2]
324 |
325 | elif op == 0x08:
326 | # Addi
327 | t = get_signed(imm, 16) & 0xFFFFFFFF
328 | reg[r2] = (reg[r1] + t) & 0xFFFFFFFF
329 | if (reg[r1]>>31) == (t>>31) and (reg[r1]>>31) != (reg[r2]>>31):
330 | program_end = True
331 | raise SimulationException('PC = %d: An overflow occurs when performing the addi operation.' % (pc))
332 |
333 | elif op == 0x09:
334 | # Addiu
335 | reg[r2] = (reg[r1] + get_signed(imm, 16)) & 0xFFFFFFFF
336 |
337 | elif op == 0x0C:
338 | # Andi
339 | reg[r2] = reg[r1] & imm
340 |
341 | elif op == 0x04:
342 | # Beq
343 | if reg[r1] == reg[r2]:
344 | pc += get_signed(imm, 16) << 2
345 |
346 | elif op == 0x01 and r2 == 1:
347 | # Bgez
348 | if get_signed(reg[r1]) >= 0:
349 | pc += get_signed(imm, 16) << 2
350 |
351 | elif op == 0x01 and r2 == 17:
352 | # Bgezal
353 | if get_signed(reg[r1]) >= 0:
354 | reg[31] = pc+4
355 | pc += get_signed(imm, 16) << 2
356 |
357 | elif op == 0x07 and r2 == 0:
358 | # Bgtz
359 | if get_signed(reg[r1]) > 0:
360 | pc += get_signed(imm, 16) << 2
361 |
362 | elif op == 0x06 and r2 == 0:
363 | # Blez
364 | if get_signed(reg[r1]) <= 0:
365 | pc += get_signed(imm, 16) << 2
366 |
367 | elif op == 0x01 and r2 == 0:
368 | # Bltz
369 | if get_signed(reg[r1]) < 0:
370 | pc += get_signed(imm, 16) << 2
371 |
372 | elif op == 0x01 and r2 == 16:
373 | # Bltzal
374 | if get_signed(reg[r1]) < 0:
375 | reg[31] = pc+4
376 | pc += get_signed(imm, 16) << 2
377 |
378 | elif op == 0x05:
379 | # Bne
380 | if reg[r1] != reg[r2]:
381 | pc += get_signed(imm, 16) << 2
382 |
383 | elif op == 0x02:
384 | # J
385 | pc = (pc&0xF0000000) | (lbl<<2)
386 | return
387 |
388 | elif op == 0x03:
389 | # Jal
390 | reg[31] = pc+4
391 | pc = (pc&0xF0000000) | (lbl<<2)
392 | return
393 |
394 | elif op == 0x20:
395 | # Lb
396 | addr = reg[r1] + get_signed(imm, 16)
397 | if addr < config.DATA_ADDR_LOWER or addr > config.DATA_ADDR_UPPER:
398 | program_end = True
399 | raise SimulationException('PC = %d: Trying to load signed byte out of data segment.' % (pc))
400 | reg[r2] = int(mem[addr])
401 |
402 | if (reg[r2]>>7) == 1:
403 | reg[r2] |= 0xFFFFFF00
404 |
405 | elif op == 0x24:
406 | # Lbu
407 | addr = reg[r1] + get_signed(imm, 16)
408 | if addr < config.DATA_ADDR_LOWER or addr > config.DATA_ADDR_UPPER:
409 | program_end = True
410 | raise SimulationException('PC = %d: Trying to load unsigned byte out of data segment.' % (pc))
411 | reg[r2] = int(mem[addr])
412 |
413 | elif op == 0x21:
414 | # Lh
415 | addr = reg[r1] + get_signed(imm, 16)
416 | if addr < config.DATA_ADDR_LOWER or addr+1 > config.DATA_ADDR_UPPER:
417 | program_end = True
418 | raise SimulationException('PC = %d: Trying to load signed half word out of data segment.' % (pc))
419 | reg[r2] = (int(mem[addr])<<8) | int(mem[addr+1])
420 |
421 | if (reg[r2]>>15) == 1:
422 | reg[r2] |= 0xFFFF0000
423 |
424 | elif op == 0x25:
425 | # Lhu
426 | addr = reg[r1] + get_signed(imm, 16)
427 | if addr < config.DATA_ADDR_LOWER or addr+1 > config.DATA_ADDR_UPPER:
428 | program_end = True
429 | raise SimulationException('PC = %d: Trying to load unsigned half word out of data segment.' % (pc))
430 | reg[r2] = (int(mem[addr])<<8) | int(mem[addr+1])
431 |
432 | elif op == 0x0F:
433 | # Lui
434 | reg[r2] = imm << 16
435 |
436 | elif op == 0x23:
437 | # Lw
438 | addr = reg[r1] + get_signed(imm, 16)
439 | if addr < config.DATA_ADDR_LOWER or addr+3 > config.DATA_ADDR_UPPER:
440 | program_end = True
441 | raise SimulationException('PC = %d: Trying to load word out of data segment.' % (pc))
442 | reg[r2] = (int(mem[addr])<<24) | (int(mem[addr+1])<<16) | (int(mem[addr+2])<<8) | int(mem[addr+3])
443 |
444 | elif op == 0x0D:
445 | # Ori
446 | reg[r2] = reg[r1] | imm
447 |
448 | elif op == 0x28:
449 | # Sb
450 | addr = reg[r1] + get_signed(imm, 16)
451 | if addr < config.DATA_ADDR_LOWER or addr > config.DATA_ADDR_UPPER:
452 | program_end = True
453 | raise SimulationException('PC = %d: Trying to store byte out of data segment.' % (pc))
454 | mem[addr] = reg[r2] & 0xFF
455 |
456 | elif op == 0x0A:
457 | # Slti
458 | if get_signed(reg[r1]) < get_signed(imm, 16):
459 | reg[r2] = 1
460 | else:
461 | reg[r2] = 0
462 |
463 | elif op == 0x0B:
464 | # Sltiu
465 | if reg[r1] < imm:
466 | reg[r2] = 1
467 | else:
468 | reg[r2] = 0
469 |
470 | elif op == 0x29:
471 | # Sh
472 | addr = reg[r1] + get_signed(imm, 16)
473 | if addr < config.DATA_ADDR_LOWER or addr+1 > config.DATA_ADDR_UPPER:
474 | program_end = True
475 | raise SimulationException('PC = %d: Trying to store half word out of data segment.' % (pc))
476 | mem[addr] = (reg[r2]>>8) & 0xFF
477 | mem[addr+1] = reg[r2] & 0xFF
478 |
479 | elif op == 0x2B:
480 | # Sw
481 | addr = reg[r1] + get_signed(imm, 16)
482 | if addr < config.DATA_ADDR_LOWER or addr+3 > config.DATA_ADDR_UPPER:
483 | program_end = True
484 | raise SimulationException('PC = %d: Trying to store word out of data segment.' % (pc))
485 | mem[addr] = reg[r2]>>24
486 | mem[addr+1] = (reg[r2]>>16) & 0xFF
487 | mem[addr+2] = (reg[r2]>>8) & 0xFF
488 | mem[addr+3] = reg[r2] & 0xFF
489 |
490 | elif op == 0x0E:
491 | # Xori
492 | reg[r2] = reg[r1] ^ imm
493 |
494 | else:
495 | SimulationException('PC = %d: Unsupported instruction.' % (pc))
496 |
497 | pc += 4
498 |
499 | # ------------------------------------------------------------------------------
500 | # Run all the program
501 | # ------------------------------------------------------------------------------
502 | def run():
503 | global program_end
504 |
505 | for i in range(0, STEP_LIMIT):
506 | if program_end:
507 | return
508 | step()
509 |
510 | program_end = True
511 | raise SimulationException('PC = %d: Too many instructions executed.' % (pc))
512 |
513 | # ------------------------------------------------------------------------------
514 | # Get output data of the simulator
515 | # ------------------------------------------------------------------------------
516 | def get_output():
517 | global output_data
518 |
519 | for c in output_data:
520 | if ord(c) >= 33 and ord(c) <= 126:
521 | ret = output_data
522 | output_data = ''
523 | return ret
524 | return ''
525 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/bin_browser.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QSize
2 | from PyQt5.QtGui import QFont, QTextCursor
3 | from PyQt5.QtWidgets import QTextBrowser
4 |
5 | # ------------------------------------------------------------------------------
6 | # Binary code browser
7 | # ------------------------------------------------------------------------------
8 | class BinBrowser(QTextBrowser):
9 |
10 | def __init__(self, parent = None):
11 | super(BinBrowser, self).__init__(parent)
12 |
13 | self.init_pc = 0
14 | self.mem = bytearray()
15 |
16 | # Set layout
17 | font = QFont('Consolas', 11)
18 | font.setFixedPitch(True)
19 |
20 | self.setFont(font)
21 | self.setStyleSheet(
22 | 'background-color: rgb(41, 49, 52);' \
23 | 'color: rgb(224, 226, 228);'
24 | )
25 |
26 | # --------------------------------------------------------------------------
27 | # Set size of the widget
28 | # --------------------------------------------------------------------------
29 | def sizeHint(self):
30 | return QSize(320, 0)
31 |
32 | # --------------------------------------------------------------------------
33 | # Display binary code
34 | # --------------------------------------------------------------------------
35 | def showBin(self, mem, pc = -1):
36 | self.mem = mem
37 |
38 | line_num = 0
39 | highlighted_line_num = 0
40 |
41 | # Set style
42 | html = \
43 | '' \
49 | ''
50 |
51 | zero = False
52 | for i in range(0, len(mem), 4):
53 | if mem[i] == 0 and mem[i+1] == 0 and mem[i+2] == 0 and mem[i+3] == 0:
54 | if not zero:
55 | line_num += 1
56 | html += ''
57 | for t in range(0, 11):
58 | html += ' | '
59 | html += '
'
60 | zero = True
61 | else:
62 | # Highlight current line if PC points to here
63 | line_num += 1
64 | if i == pc:
65 | highlighted_line_num = line_num
66 | html += ''
67 | else:
68 | html += '
'
69 |
70 | # Parse invisible characters to '.'
71 | char_lst = list(map(lambda x: 46 if x < 33 or x > 126 else x, mem[i:i+4]))
72 | html += \
73 | '%08X | ' \
74 | ' | ' \
75 | '%02x | ' \
76 | '%02x | ' \
77 | '%02x | ' \
78 | '%02x | ' \
79 | ' | ' \
80 | '%d; | ' \
81 | '%d; | ' \
82 | '%d; | ' \
83 | '%d; | ' \
84 | '
' \
85 | % (i, *mem[i:i+4], *char_lst)
86 | zero = False
87 | html += '
'
88 |
89 | self.setHtml(html)
90 |
91 | # Move to highlighted line
92 | if highlighted_line_num > 0:
93 | self.moveCursor(QTextCursor.End)
94 | cursor = QTextCursor(self.document().findBlockByLineNumber(highlighted_line_num*11))
95 | self.setTextCursor(cursor)
96 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/main_window.py:
--------------------------------------------------------------------------------
1 | import re
2 | from PyQt5.QtCore import Qt
3 | from PyQt5.QtGui import QIcon, QTextCursor
4 | from PyQt5.QtWidgets import QApplication, QFileDialog, QMainWindow, QMenu, QMessageBox, QDockWidget
5 | from com.tsreaper.yame.ui.mips_editor import MipsEditor
6 | from com.tsreaper.yame.ui.mips_highlighter import MipsHighlighter
7 | from com.tsreaper.yame.ui.message_browser import MessageBrowser
8 | from com.tsreaper.yame.ui.bin_browser import BinBrowser
9 | from com.tsreaper.yame.ui.simulator_window import SimulatorWindow
10 | from com.tsreaper.yame.ui.setting_dialog import SettingDialog
11 | from com.tsreaper.yame.ui.pseudo_dialog import PseudoDialog
12 |
13 | import com.tsreaper.yame.assemble.assembler as assembler
14 | import com.tsreaper.yame.assemble.pseudo as pseudo
15 | import com.tsreaper.yame.disassemble.disassembler as disassembler
16 | import com.tsreaper.yame.simulate.simulator as simulator
17 | import com.tsreaper.yame.constant.config as config
18 | import com.tsreaper.yame.io.coe_file as coe_file
19 | import com.tsreaper.yame.io.bin_file as bin_file
20 | import com.tsreaper.yame.constant.config as config
21 |
22 | # ------------------------------------------------------------------------------
23 | # YAME's main window
24 | # ------------------------------------------------------------------------------
25 | class MainWindow(QMainWindow):
26 |
27 | def __init__(self, parent = None):
28 | super(MainWindow, self).__init__(parent)
29 |
30 | self.initAssembler()
31 | self.initWindow()
32 |
33 | # --------------------------------------------------------------------------
34 | # Initialize assembler
35 | # --------------------------------------------------------------------------
36 | def initAssembler(self):
37 | # Load config and pseudo instructions
38 | pseudo.load_pseudo(config.CONFIG_FILE)
39 | config.load_config(config.CONFIG_FILE)
40 |
41 | # --------------------------------------------------------------------------
42 | # Initialize main window
43 | # --------------------------------------------------------------------------
44 | def initWindow(self):
45 | self.currentFile = ''
46 | self.dirty = False
47 |
48 | self.setupFileMenu()
49 | self.setupSettingMenu()
50 | self.setupAssembleMenu()
51 | self.setupHelpMenu()
52 | self.setupEditor()
53 | self.setupDockable()
54 |
55 | self.setCentralWidget(self.editor)
56 | self.setWindowTitle('Untitled - YAME')
57 | self.setWindowIcon(QIcon('icons/yame.png'))
58 |
59 | self.simulatorWindow = SimulatorWindow(self)
60 |
61 | # --------------------------------------------------------------------------
62 | # Set when text in the editor is modified
63 | # --------------------------------------------------------------------------
64 | def setDirty(self):
65 | self.dirty = True
66 | self.updateStatus()
67 |
68 | # --------------------------------------------------------------------------
69 | # Clear dirty state
70 | # --------------------------------------------------------------------------
71 | def clearDirty(self):
72 | self.dirty = False
73 | self.updateStatus()
74 |
75 | # --------------------------------------------------------------------------
76 | # Check if text in the editor is modified
77 | # --------------------------------------------------------------------------
78 | def isDirty(self):
79 | return self.dirty and (self.currentFile or self.editor.toPlainText())
80 |
81 | # --------------------------------------------------------------------------
82 | # YAME's main window
83 | # --------------------------------------------------------------------------
84 | def updateStatus(self):
85 | title = '* ' if self.isDirty() else ''
86 | if self.currentFile:
87 | title += self.currentFile
88 | else:
89 | title += 'Untitled'
90 | title += ' - YAME'
91 | self.setWindowTitle(title)
92 |
93 | # --------------------------------------------------------------------------
94 | # Confirm message box
95 | # --------------------------------------------------------------------------
96 | def okToContinue(self):
97 | if self.isDirty():
98 | reply = QMessageBox.question(
99 | self, 'YAME - 尚未保存的修改',
100 | '存在尚未保存的修改,是否保存?
',
101 | QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel
102 | )
103 | if reply == QMessageBox.Cancel:
104 | return False
105 | elif reply == QMessageBox.Yes:
106 | return self.saveFile()
107 | return True
108 |
109 | # --------------------------------------------------------------------------
110 | # Quit the app
111 | # --------------------------------------------------------------------------
112 | def closeEvent(self, event):
113 | if self.okToContinue():
114 | # Save config and pseudo instructions
115 | pseudo.save_pseudo(config.CONFIG_FILE)
116 | config.save_config(config.CONFIG_FILE)
117 |
118 | event.accept()
119 | else:
120 | event.ignore()
121 |
122 | # --------------------------------------------------------------------------
123 | # Assemble text to machine code
124 | # --------------------------------------------------------------------------
125 | def assemble(self):
126 | self.msgBrowser.clear()
127 | self.bottomDock.show()
128 |
129 | self.msgBrowser.append('Assembling...')
130 | try:
131 | mem, init_pc = assembler.assemble(self.editor.toPlainText())
132 | except Exception as e:
133 | # Move editor to the corresponding line
134 | regex_res = re.search('Line ([0-9]+?):', str(e))
135 | if regex_res != None:
136 | line_num = int(regex_res.group(1))
137 | self.editor.moveCursor(QTextCursor.End)
138 | cursor = QTextCursor(self.editor.document().findBlockByLineNumber(line_num-1))
139 | self.editor.setTextCursor(cursor)
140 |
141 | self.msgBrowser.append('[ERROR] %s' % (str(e)))
142 | self.msgBrowser.append('Assembling procedure terminated.')
143 | return False
144 | else:
145 | self.msgBrowser.append('Assembling procedure finished.')
146 | self.binBrowser.init_pc = init_pc
147 | self.binBrowser.showBin(mem)
148 | self.rightDock.show()
149 | return True
150 |
151 | # --------------------------------------------------------------------------
152 | # Disassemble machine code to text
153 | # --------------------------------------------------------------------------
154 | def disassemble(self):
155 | if not self.okToContinue():
156 | return False
157 |
158 | self.msgBrowser.clear()
159 | self.bottomDock.show()
160 | self.rightDock.show()
161 |
162 | self.msgBrowser.append('Disassembling...')
163 | try:
164 | text = disassembler.disassemble(self.binBrowser.mem)
165 | except Exception as e:
166 | self.msgBrowser.append('[ERROR] %s' % (str(e)))
167 | self.msgBrowser.append('Disassembling procedure terminated.')
168 | return False
169 | else:
170 | self.msgBrowser.append('Disassembling procedure finished.')
171 | self.currentFile = ''
172 | self.editor.setPlainText(text)
173 | return True
174 |
175 | # --------------------------------------------------------------------------
176 | # Simulate MIPS instructions
177 | # --------------------------------------------------------------------------
178 | def simulate(self):
179 | if not self.assemble():
180 | return False
181 |
182 | self.simulatorWindow.loadSimulator(self.binBrowser.mem, self.binBrowser.init_pc)
183 | self.simulatorWindow.show()
184 | return True
185 |
186 | # --------------------------------------------------------------------------
187 | # Pesudo instructions management
188 | # --------------------------------------------------------------------------
189 | def pseudoIns(self):
190 | pseudoDialog = PseudoDialog(self)
191 | pseudoDialog.exec_()
192 |
193 | # Update highlighter
194 | self.highlighter = MipsHighlighter(self.editor.document())
195 |
196 | # --------------------------------------------------------------------------
197 | # Setting memory size, text segment address, etc.
198 | # --------------------------------------------------------------------------
199 | def setting(self):
200 | settingDialog = SettingDialog(self)
201 | settingDialog.exec_()
202 |
203 | # --------------------------------------------------------------------------
204 | # About message box
205 | # --------------------------------------------------------------------------
206 | def about(self):
207 | QMessageBox.about(
208 | self, '关于 YAME',
209 | 'YAME: A MIPS Editor
'\
210 | 'Made by TsReaper
'\
211 | 'YAME 是一个简单的 MIPS 编辑器 / 汇编器 / 反汇编器 / 模拟器。
'
212 | '工程 github 页面:https://github.com/TsReaper/YAME-A-MIPS-Editor
'
213 | )
214 |
215 | # --------------------------------------------------------------------------
216 | # Clear editor
217 | # --------------------------------------------------------------------------
218 | def newFile(self):
219 | if not self.okToContinue():
220 | return False
221 |
222 | self.editor.clear()
223 | self.currentFile = ''
224 | self.clearDirty()
225 | return True
226 |
227 | # --------------------------------------------------------------------------
228 | # Open a file in the disk
229 | # --------------------------------------------------------------------------
230 | def openFile(self):
231 | if not self.okToContinue():
232 | return False
233 |
234 | path, _ = QFileDialog.getOpenFileName(
235 | self, '打开', '', '汇编文件 (*.asm)'
236 | )
237 |
238 | if path:
239 | try:
240 | # Try to use gbk decoder
241 | file = open(path, 'r')
242 | self.editor.setPlainText(file.read())
243 | except:
244 | # Try to use utf-8 decoder
245 | file.close()
246 | file = open(path, 'r', encoding = 'utf-8')
247 | self.editor.setPlainText(file.read())
248 | file.close()
249 |
250 | self.currentFile = path
251 | self.clearDirty()
252 | return True
253 |
254 | return False
255 |
256 | # --------------------------------------------------------------------------
257 | # Save current text
258 | # --------------------------------------------------------------------------
259 | def saveFile(self):
260 | if not self.currentFile:
261 | return self.saveAnotherFile()
262 |
263 | file = open(self.currentFile, 'w')
264 | file.write(self.editor.toPlainText())
265 | file.close()
266 |
267 | self.clearDirty()
268 | return True
269 |
270 | # --------------------------------------------------------------------------
271 | # Save copy of current text
272 | # --------------------------------------------------------------------------
273 | def saveAnotherFile(self):
274 | path, _ = QFileDialog.getSaveFileName(
275 | self, '另存为', self.currentFile if self.currentFile else '', '汇编文件 (*.asm)'
276 | )
277 |
278 | if path:
279 | file = open(path, 'w')
280 | file.write(self.editor.toPlainText())
281 | file.close()
282 |
283 | self.currentFile = path
284 | self.clearDirty()
285 | return True
286 |
287 | return False
288 |
289 | # --------------------------------------------------------------------------
290 | # Import coe or bin file
291 | # --------------------------------------------------------------------------
292 | def importFile(self):
293 | self.newFile()
294 |
295 | path, _ = QFileDialog.getOpenFileName(
296 | self, '导入', '', 'COE文件 (*.coe);;二进制文件 (*.bin)'
297 | )
298 |
299 | try:
300 | if path.split('.')[-1] == 'coe':
301 | mem = coe_file.read(path)
302 | elif path.split('.')[-1] == 'bin':
303 | mem = bin_file.read(path)
304 | else:
305 | return False
306 | except Exception as e:
307 | self.msgBrowser.clear()
308 | self.bottomDock.show()
309 | self.msgBrowser.append('[ERROR] %s' % (str(e)))
310 | return False
311 |
312 | self.rightDock.show()
313 | self.binBrowser.showBin(mem)
314 |
315 | return self.disassemble()
316 |
317 | # --------------------------------------------------------------------------
318 | # Export coe or bin file
319 | # --------------------------------------------------------------------------
320 | def exportFile(self):
321 | if not self.assemble():
322 | return False
323 |
324 | path, _ = QFileDialog.getSaveFileName(
325 | self, '导出', '', 'COE文件 (*.coe);;二进制文件 (*.bin)'
326 | )
327 |
328 | if path.split('.')[-1] == 'coe':
329 | coe_file.write(path, self.binBrowser.mem)
330 | return True
331 | if path.split('.')[-1] == 'bin':
332 | bin_file.write(path, self.binBrowser.mem)
333 | return True
334 |
335 | return False
336 |
337 | # --------------------------------------------------------------------------
338 | # Setup file menu
339 | # --------------------------------------------------------------------------
340 | def setupFileMenu(self):
341 | fileMenu = QMenu('文件(&F)', self)
342 | self.menuBar().addMenu(fileMenu)
343 |
344 | fileMenu.addAction('新建(&N)', self.newFile, 'Ctrl+N')
345 | fileMenu.addAction('打开(&O)...', self.openFile, 'Ctrl+O')
346 | fileMenu.addAction('保存(&S)', self.saveFile, 'Ctrl+S')
347 | fileMenu.addAction('另存为(&A)...', self.saveAnotherFile, 'Ctrl+Alt+S')
348 | fileMenu.addAction('导入(&I)...', self.importFile, 'Ctrl+I')
349 | fileMenu.addAction('导出(&E)...', self.exportFile, 'Ctrl+E')
350 | fileMenu.addAction('退出(&X)', self.close, 'Alt+F4')
351 |
352 | # --------------------------------------------------------------------------
353 | # Setup setting menu
354 | # --------------------------------------------------------------------------
355 | def setupSettingMenu(self):
356 | settingMenu = QMenu('设置(&S)', self)
357 | self.menuBar().addMenu(settingMenu)
358 |
359 | settingMenu.addAction('汇编器设置', self.setting, 'F6')
360 | settingMenu.addAction('伪指令', self.pseudoIns, 'F7')
361 |
362 | # --------------------------------------------------------------------------
363 | # Setup assemble menu
364 | # --------------------------------------------------------------------------
365 | def setupAssembleMenu(self):
366 | assembleMenu = QMenu('汇编(&A)', self)
367 | self.menuBar().addMenu(assembleMenu)
368 |
369 | assembleMenu.addAction('汇编(&A)', self.assemble, 'F9')
370 | assembleMenu.addAction('反汇编(&D)', self.disassemble, 'F10')
371 | assembleMenu.addAction('模拟(&S)', self.simulate, 'F11')
372 |
373 | # --------------------------------------------------------------------------
374 | # Setup help menu
375 | # --------------------------------------------------------------------------
376 | def setupHelpMenu(self):
377 | helpMenu = QMenu("帮助(&H)", self)
378 | self.menuBar().addMenu(helpMenu)
379 |
380 | helpMenu.addAction('关于(&A)', self.about)
381 |
382 | # --------------------------------------------------------------------------
383 | # Setup mips editor
384 | # --------------------------------------------------------------------------
385 | def setupEditor(self):
386 | self.editor = MipsEditor()
387 | self.editor.textChanged.connect(self.setDirty)
388 | self.highlighter = MipsHighlighter(self.editor.document())
389 |
390 | # --------------------------------------------------------------------------
391 | # Setup dockable widgets
392 | # --------------------------------------------------------------------------
393 | def setupDockable(self):
394 | self.msgBrowser = MessageBrowser()
395 | self.bottomDock = QDockWidget('信息', self)
396 | self.bottomDock.setFeatures(QDockWidget.DockWidgetClosable)
397 | self.bottomDock.setWidget(self.msgBrowser)
398 | self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock)
399 | self.bottomDock.hide()
400 |
401 | self.binBrowser = BinBrowser()
402 | self.rightDock = QDockWidget('机器码', self)
403 | self.rightDock.setFeatures(QDockWidget.DockWidgetClosable)
404 | self.rightDock.setWidget(self.binBrowser)
405 | self.addDockWidget(Qt.RightDockWidgetArea, self.rightDock)
406 | self.rightDock.hide()
407 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/message_browser.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QSize
2 | from PyQt5.QtGui import QFont
3 | from PyQt5.QtWidgets import QTextBrowser
4 |
5 | # ------------------------------------------------------------------------------
6 | # Message Window
7 | # ------------------------------------------------------------------------------
8 | class MessageBrowser(QTextBrowser):
9 |
10 | def __init__(self, parent = None):
11 | super(MessageBrowser, self).__init__(parent)
12 |
13 | # Set style
14 | font = QFont('Consolas', 11)
15 | font.setFixedPitch(True)
16 |
17 | self.setFont(font)
18 | self.setStyleSheet(
19 | 'background-color: rgb(41, 49, 52);' \
20 | 'color: rgb(224, 226, 228);'
21 | )
22 |
23 | # --------------------------------------------------------------------------
24 | # Set size of the widget
25 | # --------------------------------------------------------------------------
26 | def sizeHint(self):
27 | return QSize(0, 100)
28 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/mips_editor.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import Qt, QSize, QRect
2 | from PyQt5.QtGui import QFont, QColor, QPainter, QTextFormat
3 | from PyQt5.QtWidgets import QWidget, QTextEdit, QPlainTextEdit
4 |
5 | class LineNumberArea(QWidget):
6 |
7 | def __init__(self, parent):
8 | super(LineNumberArea, self).__init__(parent)
9 | self.editor = parent
10 |
11 | def sizeHint(self):
12 | return QSize(self.editor.lineNumberAreaWidth(), 0)
13 |
14 | def paintEvent(self, event):
15 | self.editor.lineNumberAreaPaintEvent(event)
16 |
17 | class MipsEditor(QPlainTextEdit):
18 |
19 | def __init__(self, parent = None):
20 | super(MipsEditor, self).__init__(parent)
21 |
22 | font = QFont('Consolas', 11)
23 | font.setFixedPitch(True)
24 |
25 | self.setFont(font)
26 | self.setStyleSheet(
27 | 'background-color: rgb(41, 49, 52);' \
28 | 'color: rgb(224, 226, 228);'
29 | )
30 |
31 | self.setLineWrapMode(QPlainTextEdit.NoWrap)
32 |
33 | self.lineNumberArea = LineNumberArea(self)
34 |
35 | self.blockCountChanged.connect(self.updateLineNumberAreaWidth)
36 | self.updateRequest.connect(self.updateLineNumberArea)
37 | self.cursorPositionChanged.connect(self.highlightCurrentLine)
38 |
39 | self.updateLineNumberAreaWidth(0)
40 |
41 | def lineNumberAreaWidth(self):
42 | digits = 0
43 | count = max(1, self.blockCount())
44 | while count > 0:
45 | count = count//10
46 | digits += 1
47 | return self.fontMetrics().width('9') * digits + 15
48 |
49 | def updateLineNumberAreaWidth(self, _):
50 | self.setViewportMargins(self.lineNumberAreaWidth(), 0, 0, 0)
51 |
52 | def updateLineNumberArea(self, rect, dy):
53 | if dy:
54 | self.lineNumberArea.scroll(0, dy)
55 | else:
56 | self.lineNumberArea.update(0, rect.y(), self.lineNumberArea.width(), rect.height())
57 |
58 | if rect.contains(self.viewport().rect()):
59 | self.updateLineNumberAreaWidth(0)
60 |
61 | def resizeEvent(self, event):
62 | super().resizeEvent(event)
63 |
64 | cr = self.contentsRect();
65 | self.lineNumberArea.setGeometry(
66 | QRect(cr.left(), cr.top(), self.lineNumberAreaWidth(), cr.height())
67 | )
68 |
69 | def lineNumberAreaPaintEvent(self, event):
70 | painter = QPainter(self.lineNumberArea)
71 | painter.fillRect(event.rect(), QColor(63, 75, 78))
72 |
73 | font = QFont('Consolas', 11)
74 | font.setFixedPitch(True)
75 |
76 | painter.setFont(font)
77 | painter.setPen(QColor(129, 150, 154))
78 |
79 | block = self.firstVisibleBlock()
80 | blockNumber = block.blockNumber()
81 | top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top()
82 | bottom = top + self.blockBoundingRect(block).height()
83 |
84 | height = self.fontMetrics().height()
85 | while block.isValid() and (top <= event.rect().bottom()):
86 | if block.isVisible() and (bottom >= event.rect().top()):
87 | number = str(blockNumber + 1)
88 | painter.drawText(
89 | 0, top, self.lineNumberArea.width(), height,
90 | Qt.AlignCenter, number
91 | )
92 |
93 | block = block.next()
94 | top = bottom
95 | bottom = top + self.blockBoundingRect(block).height()
96 | blockNumber += 1
97 |
98 | def highlightCurrentLine(self):
99 | extraSelections = []
100 |
101 | if not self.isReadOnly():
102 | selection = QTextEdit.ExtraSelection()
103 | lineColor = QColor(47, 57, 60)
104 |
105 | selection.format.setBackground(lineColor)
106 | selection.format.setProperty(QTextFormat.FullWidthSelection, True)
107 | selection.cursor = self.textCursor()
108 | selection.cursor.clearSelection()
109 | extraSelections.append(selection)
110 |
111 | self.setExtraSelections(extraSelections)
112 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/mips_highlighter.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QRegExp
2 | from PyQt5.QtGui import QFont, QColor, QSyntaxHighlighter, QTextCharFormat
3 |
4 | from com.tsreaper.yame.constant.instruction_template import *
5 | from com.tsreaper.yame.constant.register_list import *
6 | import com.tsreaper.yame.assemble.pseudo as pseudo
7 |
8 | # ------------------------------------------------------------------------------
9 | # Mips highlighter
10 | # ------------------------------------------------------------------------------
11 | class MipsHighlighter(QSyntaxHighlighter):
12 |
13 | def __init__(self, parent = None):
14 | super(MipsHighlighter, self).__init__(parent)
15 |
16 | # Set highlight rules
17 | self.highlightingRules = []
18 |
19 | # Symbols
20 | sym = '@~\!\^&\*\(\)\-\+\=\|;<\,>/'
21 | symFormat = QTextCharFormat()
22 | symFormat.setForeground(QColor(232, 226, 183))
23 |
24 | self.highlightingRules.append((QRegExp('[' + sym + ']'), symFormat))
25 |
26 | # Immediates
27 | immFormat = QTextCharFormat()
28 | immFormat.setForeground(QColor(255, 205, 34))
29 |
30 | self.highlightingRules.append((QRegExp(r'\b[0-9]\w*\b'), immFormat))
31 |
32 | # Text instruction highlight format
33 | textInsFormat = QTextCharFormat()
34 | textInsFormat.setForeground(QColor(147, 199, 99))
35 |
36 | textInsPatterns = []
37 | for i in R_INSTRUCTIONS.keys():
38 | textInsPatterns.append(r'\b' + i + r'\b')
39 | for i in I_INSTRUCTIONS.keys():
40 | textInsPatterns.append(r'\b' + i + r'\b')
41 | for i in J_INSTRUCTIONS.keys():
42 | textInsPatterns.append(r'\b' + i + r'\b')
43 |
44 | for pattern in textInsPatterns:
45 | self.highlightingRules.append((QRegExp(pattern), textInsFormat))
46 |
47 | # Data instruction highlight format
48 | dataInsFormat = QTextCharFormat()
49 | dataInsFormat.setForeground(QColor(160, 130, 189))
50 |
51 | dataInsPatterns = [r'\.text\b', r'\.data\b']
52 | for i in DATA_INSTRUCTIONS.keys():
53 | dataInsPatterns.append(i.replace('.', r'\.') + r'\b')
54 |
55 | for pattern in dataInsPatterns:
56 | self.highlightingRules.append((QRegExp(pattern), dataInsFormat))
57 |
58 | # pseudo instructions
59 | pseudoInsFormat = QTextCharFormat()
60 | pseudoInsFormat.setForeground(QColor(0, 128, 192))
61 |
62 | pseudoInsPatterns = []
63 | for i in pseudo.pseudo_dict.keys():
64 | pseudoInsPatterns.append(r'\b' + i + r'\b')
65 |
66 | for pattern in pseudoInsPatterns:
67 | self.highlightingRules.append((QRegExp(pattern), pseudoInsFormat))
68 |
69 | # Parameters for pseudo instructions
70 | pseudoParamFormat = QTextCharFormat()
71 | pseudoParamFormat.setForeground(QColor(103, 140, 177))
72 |
73 | qreg = QRegExp(r'\[[0-9]+\]')
74 | qreg.setMinimal(True)
75 | self.highlightingRules.append((qreg, pseudoParamFormat))
76 |
77 | # Register highlight format
78 | regFormat = QTextCharFormat()
79 | regFormat.setForeground(QColor(103, 140, 177))
80 |
81 | regPatterns = []
82 | for r in REGISTER_LIST:
83 | regPatterns.append(r.replace('$', r'\$') + r'\b')
84 | for r in REGISTER_NUM_LIST:
85 | regPatterns.append(r.replace('$', r'\$') + r'\b')
86 |
87 | for pattern in regPatterns:
88 | self.highlightingRules.append((QRegExp(pattern), regFormat))
89 |
90 | # Strings
91 | strFormat = QTextCharFormat()
92 | strFormat.setForeground(QColor(236, 118, 0))
93 |
94 | qreg = QRegExp('".*"')
95 | qreg.setMinimal(True)
96 | self.highlightingRules.append((qreg, strFormat))
97 | qreg = QRegExp('\'.*\'')
98 | qreg.setMinimal(True)
99 | self.highlightingRules.append((qreg, strFormat))
100 |
101 | # Comments
102 | comFormat = QTextCharFormat()
103 | comFormat.setForeground(QColor(102, 116, 123))
104 |
105 | self.highlightingRules.append((QRegExp('(#.*)|(//.*)'), comFormat))
106 | qreg = QRegExp('(/\*.*\*/)')
107 | qreg.setMinimal(True)
108 | self.highlightingRules.append((qreg, comFormat))
109 |
110 | # --------------------------------------------------------------------------
111 | # Simple highlight method, ignoring multiple lines of comments
112 | # --------------------------------------------------------------------------
113 | def highlightBlock(self, text):
114 | for pattern, format in self.highlightingRules:
115 | expression = QRegExp(pattern)
116 | index = expression.indexIn(text)
117 | while index >= 0:
118 | length = expression.matchedLength()
119 | self.setFormat(index, length, format)
120 | index = expression.indexIn(text, index + length)
121 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/pseudo_dialog.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QListWidget, QPushButton, QLabel, QLineEdit, QVBoxLayout, QHBoxLayout, QMessageBox
2 | from com.tsreaper.yame.ui.mips_editor import MipsEditor
3 | from com.tsreaper.yame.ui.mips_highlighter import MipsHighlighter
4 |
5 | import com.tsreaper.yame.assemble.pseudo as pseudo
6 | from com.tsreaper.yame.constant.instruction_template import *
7 |
8 | class PseudoDialog(QDialog):
9 |
10 | def __init__(self, parent = None):
11 | super(PseudoDialog, self).__init__(parent)
12 | self.initDialog()
13 |
14 | def initDialog(self):
15 | self.setWindowTitle('伪指令')
16 |
17 | self.addButton = QPushButton('添加')
18 | self.addButton.clicked.connect(self.addItem)
19 | self.delButton = QPushButton('删除')
20 | self.delButton.setEnabled(False)
21 | self.delButton.clicked.connect(self.delItem)
22 | self.saveButton = QPushButton('保存')
23 | self.saveButton.setEnabled(False)
24 | self.saveButton.clicked.connect(self.saveItem)
25 |
26 | self.pseudoNameLabel = QLabel('伪指令名')
27 | self.pseudoNameValue = QLineEdit()
28 | self.pseudoNameValue.setEnabled(False)
29 | self.operandNumberLabel = QLabel('操作数数量')
30 | self.operandNumberValue = QLineEdit()
31 | self.operandNumberValue.setEnabled(False)
32 | self.realInsLabel = QLabel('真指令')
33 | self.realInsValue = MipsEditor()
34 | self.realInsValue.setEnabled(False)
35 | self.highlighter = MipsHighlighter(self.realInsValue.document())
36 |
37 | self.pseudoList = QListWidget(self)
38 | for op in pseudo.pseudo_dict.keys():
39 | self.pseudoList.addItem(op)
40 | self.pseudoList.currentItemChanged.connect(self.changeItem)
41 | self.updateList('')
42 |
43 | buttonLayout = QVBoxLayout()
44 | buttonLayout.addWidget(self.addButton)
45 | buttonLayout.addWidget(self.delButton)
46 | buttonLayout.addWidget(self.saveButton)
47 |
48 | upperLayout = QHBoxLayout()
49 | upperLayout.addWidget(self.pseudoList)
50 | upperLayout.addLayout(buttonLayout)
51 |
52 | lowerLayout = QVBoxLayout()
53 | lowerLayout.addWidget(self.pseudoNameLabel)
54 | lowerLayout.addWidget(self.pseudoNameValue)
55 | lowerLayout.addWidget(self.operandNumberLabel)
56 | lowerLayout.addWidget(self.operandNumberValue)
57 | lowerLayout.addWidget(self.realInsLabel)
58 | lowerLayout.addWidget(self.realInsValue)
59 |
60 | layout = QVBoxLayout()
61 | layout.addLayout(upperLayout)
62 | layout.addLayout(lowerLayout)
63 | self.setLayout(layout)
64 |
65 | def updateList(self, itemName):
66 | self.pseudoList.sortItems()
67 |
68 | for i in range(0, self.pseudoList.count()):
69 | if self.pseudoList.item(i).text() == itemName:
70 | self.pseudoList.setCurrentRow(i)
71 | return
72 |
73 | self.pseudoList.setCurrentRow(0)
74 |
75 | def addItem(self):
76 | id = 0
77 | while ('pseudo' + str(id)) in pseudo.pseudo_dict.keys():
78 | id += 1
79 |
80 | ins = 'pseudo' + str(id)
81 | pseudo.pseudo_dict[ins] = [0, '']
82 | self.pseudoList.addItem(ins)
83 | self.updateList(ins)
84 |
85 | def delItem(self):
86 | ins = self.pseudoList.currentItem().text()
87 | pseudo.pseudo_dict.pop(ins)
88 | self.pseudoList.takeItem(self.pseudoList.currentRow())
89 | self.updateList('')
90 |
91 | def saveItem(self):
92 | ins = self.pseudoList.currentItem().text()
93 | new_ins = self.pseudoNameValue.text()
94 | try:
95 | opNum = int(self.operandNumberValue.text())
96 | except:
97 | opNum = 0
98 | real = self.realInsValue.toPlainText()
99 |
100 | if new_ins == '':
101 | QMessageBox.critical(self, '错误', '伪指令名不能为空!
')
102 | return
103 | elif ins != new_ins and (
104 | new_ins in pseudo.pseudo_dict.keys() or
105 | new_ins in R_INSTRUCTIONS.keys() or
106 | new_ins in I_INSTRUCTIONS.keys() or
107 | new_ins in J_INSTRUCTIONS.keys()
108 | ):
109 | QMessageBox.critical(self, '错误', '伪指令名与已有指令或伪指令重复!
')
110 | return
111 |
112 | pseudo.pseudo_dict.pop(ins)
113 | self.pseudoList.takeItem(self.pseudoList.currentRow())
114 | pseudo.pseudo_dict[new_ins] = [opNum, ';'.join(real.split('\n'))]
115 | self.pseudoList.addItem(new_ins)
116 | self.updateList(new_ins)
117 |
118 | def changeItem(self):
119 | if self.pseudoList.currentItem() == None:
120 | self.pseudoNameValue.clear()
121 | self.operandNumberValue.clear()
122 | self.realInsValue.clear()
123 |
124 | self.pseudoNameValue.setEnabled(False)
125 | self.operandNumberValue.setEnabled(False)
126 | self.realInsValue.setEnabled(False)
127 | self.delButton.setEnabled(False)
128 | self.saveButton.setEnabled(False)
129 | else:
130 | ins = self.pseudoList.currentItem().text()
131 |
132 | self.pseudoNameValue.setText(ins)
133 | self.operandNumberValue.setText(str(pseudo.pseudo_dict[ins][0]))
134 | self.realInsValue.setPlainText('\n'.join(pseudo.pseudo_dict[ins][1].split(';')))
135 |
136 | self.pseudoNameValue.setEnabled(True)
137 | self.operandNumberValue.setEnabled(True)
138 | self.realInsValue.setEnabled(True)
139 | self.delButton.setEnabled(True)
140 | self.saveButton.setEnabled(True)
141 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/reg_browser.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QSize
2 | from PyQt5.QtGui import QFont
3 | from PyQt5.QtWidgets import QTextBrowser
4 |
5 | from com.tsreaper.yame.constant.register_list import *
6 |
7 | # ------------------------------------------------------------------------------
8 | # Register value browser
9 | # ------------------------------------------------------------------------------
10 | class RegBrowser(QTextBrowser):
11 |
12 | def __init__(self, parent = None):
13 | super(RegBrowser, self).__init__(parent)
14 |
15 | # Set layout
16 | font = QFont('Consolas', 11)
17 | font.setFixedPitch(True)
18 |
19 | self.setFont(font)
20 | self.setStyleSheet(
21 | 'background-color: rgb(41, 49, 52);' \
22 | 'color: rgb(224, 226, 228);'
23 | )
24 |
25 | # --------------------------------------------------------------------------
26 | # Set size of the widget
27 | # --------------------------------------------------------------------------
28 | def sizeHint(self):
29 | return QSize(220, 0)
30 |
31 | # --------------------------------------------------------------------------
32 | # Display register value
33 | # --------------------------------------------------------------------------
34 | def showReg(self, reg):
35 | # Set style
36 | html = \
37 | '' \
41 | ''
42 |
43 | reg_list = list(map(lambda r: r[1:], REGISTER_LIST)) + ['pc', 'hi', 'lo']
44 |
45 | for i in range(0, len(reg_list)):
46 | if i == 32:
47 | html += '
'
48 |
49 | html += \
50 | '' \
51 | '%s | ' \
52 | ' | ' \
53 | '%02x | ' \
54 | '%02x | ' \
55 | '%02x | ' \
56 | '%02x | ' \
57 | '
' \
58 | % (reg_list[i], reg[i]>>24, (reg[i]>>16) & 0xFF, (reg[i]>>8) & 0xFF, reg[i] & 0xFF)
59 |
60 | html += '
'
61 |
62 | self.setHtml(html)
63 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/setting_dialog.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QDialog, QPushButton, QLabel, QLineEdit, QGridLayout, QMessageBox
2 |
3 | import com.tsreaper.yame.constant.config as config
4 |
5 | class SettingDialog(QDialog):
6 |
7 | def __init__(self, parent = None):
8 | super(SettingDialog, self).__init__(parent)
9 | self.initDialog()
10 |
11 | def initDialog(self):
12 | self.memSizeLabel = QLabel('内存大小(字节)')
13 | self.memSizeValue = QLineEdit()
14 | self.textLowerLabel = QLabel('代码段下界(字节)')
15 | self.textLowerValue = QLineEdit()
16 | self.textUpperLabel = QLabel('代码段上界(字节)')
17 | self.textUpperValue = QLineEdit()
18 | self.dataLowerLabel = QLabel('数据段下界(字节)')
19 | self.dataLowerValue = QLineEdit()
20 | self.dataUpperLabel = QLabel('数据段上界(字节)')
21 | self.dataUpperValue = QLineEdit()
22 |
23 | self.memSizeValue.setText(str(config.MEM_SIZE))
24 | self.textLowerValue.setText(str(config.TEXT_ADDR_LOWER))
25 | self.textUpperValue.setText(str(config.TEXT_ADDR_UPPER))
26 | self.dataLowerValue.setText(str(config.DATA_ADDR_LOWER))
27 | self.dataUpperValue.setText(str(config.DATA_ADDR_UPPER))
28 |
29 | self.okButton = QPushButton('确认')
30 | self.cancelButton = QPushButton('取消')
31 | self.okButton.clicked.connect(self.okClicked)
32 | self.cancelButton.clicked.connect(self.reject)
33 |
34 | layout = QGridLayout()
35 | layout.addWidget(self.memSizeLabel, 0, 0)
36 | layout.addWidget(self.memSizeValue, 1, 0)
37 | layout.addWidget(self.textLowerLabel, 2, 0)
38 | layout.addWidget(self.textLowerValue, 3, 0)
39 | layout.addWidget(self.textUpperLabel, 2, 1)
40 | layout.addWidget(self.textUpperValue, 3, 1)
41 | layout.addWidget(self.dataLowerLabel, 4, 0)
42 | layout.addWidget(self.dataLowerValue, 5, 0)
43 | layout.addWidget(self.dataUpperLabel, 4, 1)
44 | layout.addWidget(self.dataUpperValue, 5, 1)
45 | layout.addWidget(self.okButton, 6, 0)
46 | layout.addWidget(self.cancelButton, 6, 1)
47 | self.setLayout(layout)
48 |
49 | self.setWindowTitle('汇编器设置')
50 |
51 | def okClicked(self):
52 | try:
53 | mem_size = int(self.memSizeValue.text())
54 | text_addr_lower = int(self.textLowerValue.text())
55 | text_addr_upper = int(self.textUpperValue.text())
56 | data_addr_lower = int(self.dataLowerValue.text())
57 | data_addr_upper = int(self.dataUpperValue.text())
58 | except:
59 | QMessageBox.critical(self, '错误', '只能输入整数!
')
60 | return
61 |
62 | if mem_size > config.MAX_MEM_SIZE:
63 | QMessageBox.critical(self, '错误', '内存大小超限,至多 1024KB!
')
64 | return
65 |
66 | if text_addr_lower >= 0 and text_addr_lower < mem_size and \
67 | text_addr_upper >= 0 and text_addr_upper < mem_size and \
68 | data_addr_lower >= 0 and data_addr_lower < mem_size and \
69 | data_addr_upper >= 0 and data_addr_upper < mem_size and \
70 | text_addr_lower <= text_addr_upper and data_addr_lower <= data_addr_upper and \
71 | (text_addr_upper < data_addr_lower or data_addr_upper < text_addr_lower):
72 | config.MEM_SIZE = mem_size
73 | config.TEXT_ADDR_LOWER = text_addr_lower
74 | config.TEXT_ADDR_UPPER = text_addr_upper
75 | config.DATA_ADDR_LOWER = data_addr_lower
76 | config.DATA_ADDR_UPPER = data_addr_upper
77 | self.accept()
78 | else:
79 | QMessageBox.critical(self, '错误', '填入数据非法!请重新检查。
')
80 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/simulator_window.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import Qt, QSize
2 | from PyQt5.QtGui import QKeySequence, QIcon, QTextCursor
3 | from PyQt5.QtWidgets import QWidget, QMainWindow, QAction, QDockWidget, QVBoxLayout
4 | from com.tsreaper.yame.ui.message_browser import MessageBrowser
5 | from com.tsreaper.yame.ui.reg_browser import RegBrowser
6 | from com.tsreaper.yame.ui.bin_browser import BinBrowser
7 | from com.tsreaper.yame.ui.terminal_browser import TerminalBrowser
8 | from com.tsreaper.yame.ui.terminal_input import TerminalInput
9 |
10 | import com.tsreaper.yame.simulate.simulator as simulator
11 | from com.tsreaper.yame.simulate.simulation_info_exception import SimulationInfoException
12 | import com.tsreaper.yame.constant.config as config
13 |
14 | def parseHtml(s):
15 | s = s.replace('&', '&')
16 | s = s.replace(' ', ' ')
17 | s = s.replace('<', '<')
18 | s = s.replace('>', '>')
19 | s = s.replace('"', '"')
20 | s = s.replace('\'', ''')
21 | s = s.replace('\n', '
')
22 | return s
23 |
24 | class SimulatorWindow(QMainWindow):
25 |
26 | def __init__(self, parent = None):
27 | super(SimulatorWindow, self).__init__(parent)
28 |
29 | self.initWindow()
30 |
31 | def initWindow(self):
32 | self.setupToolBar()
33 | self.setupDockable()
34 | self.setupTerminal()
35 | self.setWindowTitle('模拟')
36 |
37 | def setupToolBar(self):
38 | self.toolBar = self.addToolBar('Control')
39 | self.toolBar.setIconSize(QSize(48, 48))
40 |
41 | self.resetAction = QAction(
42 | QIcon('icons/reset.png'), '初始化(F9)', self,
43 | shortcut = QKeySequence('F9'), statusTip = '初始化(F9)',
44 | triggered = self.resetSimulator
45 | )
46 | self.toolBar.addAction(self.resetAction)
47 |
48 | self.stepAction = QAction(
49 | QIcon('icons/step.png'), '单步(F10)', self,
50 | shortcut = QKeySequence('F10'), statusTip = '单步(F10)',
51 | triggered = self.stepSimulator
52 | )
53 | self.toolBar.addAction(self.stepAction)
54 |
55 | self.runAction = QAction(
56 | QIcon('icons/run.png'), '运行(F11)', self,
57 | shortcut = QKeySequence('F11'), statusTip = '运行(F11)',
58 | triggered = self.runSimulator
59 | )
60 | self.toolBar.addAction(self.runAction)
61 |
62 | def setupDockable(self):
63 | self.msgBrowser = MessageBrowser()
64 | self.bottomDock = QDockWidget('信息', self)
65 | self.bottomDock.setFeatures(QDockWidget.DockWidgetClosable)
66 | self.bottomDock.setWidget(self.msgBrowser)
67 | self.addDockWidget(Qt.BottomDockWidgetArea, self.bottomDock)
68 | self.bottomDock.hide()
69 |
70 | self.regBrowser = RegBrowser()
71 | self.leftDock = QDockWidget('寄存器', self)
72 | self.leftDock.setFeatures(QDockWidget.DockWidgetClosable)
73 | self.leftDock.setWidget(self.regBrowser)
74 | self.addDockWidget(Qt.LeftDockWidgetArea, self.leftDock)
75 |
76 | self.binBrowser = BinBrowser()
77 | self.rightDock = QDockWidget('内存', self)
78 | self.rightDock.setFeatures(QDockWidget.DockWidgetClosable)
79 | self.rightDock.setWidget(self.binBrowser)
80 | self.addDockWidget(Qt.RightDockWidgetArea, self.rightDock)
81 |
82 | def setupTerminal(self):
83 | self.terminal = TerminalBrowser()
84 | self.lineInput = TerminalInput()
85 | self.lineInput.returnPressed.connect(self.updateInput)
86 |
87 | layout = QVBoxLayout()
88 | layout.addWidget(self.terminal)
89 | layout.addWidget(self.lineInput)
90 | central = QWidget()
91 | central.setLayout(layout)
92 | self.setCentralWidget(central)
93 |
94 | def updateBrowser(self):
95 | self.regBrowser.showReg(simulator.reg + [simulator.pc, simulator.hi, simulator.lo])
96 | self.binBrowser.showBin(simulator.mem, simulator.pc)
97 |
98 | self.terminal.insertHtml(parseHtml(simulator.get_output()))
99 | self.terminal.moveCursor(QTextCursor.End)
100 |
101 | def updateInput(self):
102 | simulator.input_data.extend(self.lineInput.text().split())
103 |
104 | self.terminal.insertHtml('' + parseHtml(self.lineInput.text()) + '')
105 | self.terminal.moveCursor(QTextCursor.End)
106 | self.lineInput.clear()
107 |
108 | if self.state == 'STEP':
109 | self.stepSimulator()
110 | elif self.state == 'RUN':
111 | self.runSimulator()
112 |
113 | def setWidgetEnabled(self):
114 | self.stepAction.setEnabled(not simulator.program_end and self.state == 'IDLE')
115 | self.runAction.setEnabled(not simulator.program_end and self.state == 'IDLE')
116 |
117 | if self.state != 'IDLE':
118 | self.lineInput.setEnabled(True)
119 | self.lineInput.setFocus()
120 | else:
121 | self.lineInput.setEnabled(False)
122 |
123 | def loadSimulator(self, mem, init_pc):
124 | if init_pc < 0:
125 | simulator.load(mem, config.TEXT_ADDR_LOWER)
126 | self.resetSimulator()
127 | self.bottomDock.show()
128 | self.msgBrowser.append('[WARNING] Can not find "main" label. Program counter will be set to the lower bound of text segment instead.')
129 | else:
130 | simulator.load(mem, init_pc)
131 | self.resetSimulator()
132 |
133 | def resetSimulator(self):
134 | simulator.reset()
135 | self.state = 'IDLE'
136 |
137 | self.bottomDock.hide()
138 | self.terminal.clear()
139 | self.lineInput.clear()
140 | self.msgBrowser.clear()
141 |
142 | self.updateBrowser()
143 | self.setWidgetEnabled()
144 |
145 | def stepSimulator(self):
146 | self.state = 'STEP'
147 |
148 | self.msgBrowser.clear()
149 | self.bottomDock.show()
150 | self.msgBrowser.append('Simulating...')
151 |
152 | try:
153 | simulator.step()
154 | except SimulationInfoException as e:
155 | self.msgBrowser.append('[INFO] %s' % (str(e)))
156 | except Exception as e:
157 | self.msgBrowser.append('[EXCEPTION] %s' % (str(e)))
158 | self.msgBrowser.append('Simulation terminated.')
159 | self.state = 'IDLE'
160 | else:
161 | self.msgBrowser.append('Simulation terminated.')
162 | self.state = 'IDLE'
163 |
164 | self.updateBrowser()
165 | self.setWidgetEnabled()
166 |
167 | def runSimulator(self):
168 | self.state = 'RUN'
169 |
170 | self.msgBrowser.clear()
171 | self.bottomDock.show()
172 | self.msgBrowser.append('Simulating...')
173 |
174 | try:
175 | simulator.run()
176 | except SimulationInfoException as e:
177 | self.msgBrowser.append('[INFO] %s' % (str(e)))
178 | except Exception as e:
179 | self.msgBrowser.append('[EXCEPTION] %s' % (str(e)))
180 | self.msgBrowser.append('Simulation terminated.')
181 | self.state = 'IDLE'
182 | else:
183 | self.msgBrowser.append('Simulation terminated.')
184 | self.state = 'IDLE'
185 |
186 | self.updateBrowser()
187 | self.setWidgetEnabled()
188 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/terminal_browser.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QSize
2 | from PyQt5.QtGui import QFont
3 | from PyQt5.QtWidgets import QTextBrowser
4 |
5 | # ------------------------------------------------------------------------------
6 | # Terminal of the simulator
7 | # ------------------------------------------------------------------------------
8 | class TerminalBrowser(QTextBrowser):
9 |
10 | def __init__(self, parent = None):
11 | super(TerminalBrowser, self).__init__(parent)
12 |
13 | # Set layout
14 | font = QFont('Consolas', 11)
15 | font.setFixedPitch(True)
16 |
17 | self.setFont(font)
18 | self.setStyleSheet(
19 | 'background-color: rgb(41, 49, 52);' \
20 | 'color: rgb(224, 226, 228);'
21 | )
22 |
23 | # --------------------------------------------------------------------------
24 | # Set size of the widget
25 | # --------------------------------------------------------------------------
26 | def sizeHint(self):
27 | return QSize(480, 480)
28 |
--------------------------------------------------------------------------------
/src/com/tsreaper/yame/ui/terminal_input.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtCore import QSize
2 | from PyQt5.QtGui import QFont
3 | from PyQt5.QtWidgets import QLineEdit
4 |
5 | # ------------------------------------------------------------------------------
6 | # Line input for the terminal of the simulator
7 | # ------------------------------------------------------------------------------
8 | class TerminalInput(QLineEdit):
9 |
10 | def __init__(self, parent = None):
11 | super(TerminalInput, self).__init__(parent)
12 |
13 | # Set layout
14 | font = QFont('Consolas', 11)
15 | font.setFixedPitch(True)
16 |
17 | self.setFont(font)
18 | self.setStyleSheet(
19 | 'background-color: rgb(41, 49, 52);' \
20 | 'color: rgb(224, 226, 228);'
21 | )
22 |
23 | # --------------------------------------------------------------------------
24 | # Set size of the widget
25 | # --------------------------------------------------------------------------
26 | def sizeHint(self):
27 | return QSize(480, 0)
28 |
--------------------------------------------------------------------------------
/src/config.cfg:
--------------------------------------------------------------------------------
1 | [blti]
2 | operand = 3
3 | real = lui $at, ([2])>>16;ori $at, $at, ([2])&0xFFFF;subu $at, [1], $at;bltz $at, [3]
4 |
5 | [blt]
6 | operand = 3
7 | real = subu $at, [1], [2];bltz $at, [3]
8 |
9 | [nop]
10 | operand = 0
11 | real = sll $zero, $zero, 0
12 |
13 | [not]
14 | operand = 1
15 | real = addi $at, $zero, -1;xor [1], [1], $at
16 |
17 | [beqi]
18 | operand = 3
19 | real = lui $at, ([2])>>16;ori $at, $at, ([2])&0xFFFF;beq [1], $at, [3]
20 |
21 | [muli]
22 | operand = 3
23 | real = lui $at, ([3])>>16;ori $at, $at, ([3])&0xFFFF;mult $at, [2];mflo [1]
24 |
25 | [seq]
26 | operand = 3
27 | real = subu $at, [2], [3];sltu [1], $zero, $at;addi $at, $zero, 1;subu [1], $at, [1]
28 |
29 | [li]
30 | operand = 2
31 | real = lui [1], ([2])>>16;ori [1], [1], ([2])&0xFFFF
32 |
33 | [beqz]
34 | operand = 2
35 | real = beq [1], $zero, [2]
36 |
37 | [bnei]
38 | operand = 3
39 | real = lui $at, ([2])>>16;ori $at, $at, ([2])&0xFFFF;bne [1], $at, [3]
40 |
41 | [mul]
42 | operand = 3
43 | real = mult [2], [3];mflo [1]
44 |
45 | [bgt]
46 | operand = 3
47 | real = subu $at, [1], [2];bgtz $at, [3]
48 |
49 | [la]
50 | operand = 2
51 | real = lui $at, (@[2]@)>>16;ori $at, $at, (@[2]@)&0xFFFF;add [1], $zero, $at
52 |
53 | [move]
54 | operand = 2
55 | real = add [1], $zero, [2]
56 |
57 | [b]
58 | operand = 1
59 | real = j [1]
60 |
61 | [bgti]
62 | operand = 3
63 | real = lui $at, ([2])>>16;ori $at, $at, ([2])&0xFFFF;subu $at, $at, [1];bltz $at, [3]
64 |
65 | [bge]
66 | operand = 3
67 | real = subu $at, [1], [2];bgez $at, [3]
68 |
69 | [`]
70 | mem_size = 8192
71 | text_addr_lower = 0
72 | text_addr_upper = 4095
73 | data_addr_lower = 4096
74 | data_addr_upper = 8191
75 |
76 |
--------------------------------------------------------------------------------
/src/icons/reset.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/yame-a-mips-editor/c1e306054317711e2dbf263a4b9f8426effcfa00/src/icons/reset.png
--------------------------------------------------------------------------------
/src/icons/run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/yame-a-mips-editor/c1e306054317711e2dbf263a4b9f8426effcfa00/src/icons/run.png
--------------------------------------------------------------------------------
/src/icons/step.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/yame-a-mips-editor/c1e306054317711e2dbf263a4b9f8426effcfa00/src/icons/step.png
--------------------------------------------------------------------------------
/src/icons/yame.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/yame-a-mips-editor/c1e306054317711e2dbf263a4b9f8426effcfa00/src/icons/yame.ico
--------------------------------------------------------------------------------
/src/icons/yame.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tsreaper/yame-a-mips-editor/c1e306054317711e2dbf263a4b9f8426effcfa00/src/icons/yame.png
--------------------------------------------------------------------------------
/src/main.pyw:
--------------------------------------------------------------------------------
1 | import sys
2 | from PyQt5.QtWidgets import QApplication
3 | from com.tsreaper.yame.ui.main_window import MainWindow
4 |
5 | app = QApplication(sys.argv)
6 | window = MainWindow()
7 | window.resize(960, 640)
8 | window.show()
9 | sys.exit(app.exec_())
10 |
--------------------------------------------------------------------------------
/test/guess.asm:
--------------------------------------------------------------------------------
1 | # This program generates a random digit number with unique digits given a
2 | # length value input by the user (sized values of 1 to 9), and asks the user
3 | # to try to guess the generated number. For every digit the guess shares with the generated
4 | # number, the program prints the word Pico, but if the digit is in the same locations, it prints
5 | # Fermi. If no digits are shared, the program prints Bagel. If the user gives up they can input
6 | # 0 and the program will show them the generated value, along with the number of times
7 | # the user guessed incorrently.
8 | # By Alex Plaza
9 |
10 | .data
11 |
12 | init1: .asciiz "\nThe computer has generated a "
13 | init2: .asciiz " digit random number with unique digits. Try to guess it, or input 0 to give up."
14 | getLength: .asciiz "Select length of target b/w 1-9: "
15 | iPrompt: .asciiz "\nPlease enter your guess: "
16 | Fermi: .asciiz "Fermis"
17 | Pico: .asciiz "Pico"
18 | Bagel: .asciiz "Bagel"
19 | win: .asciiz "\nYou Won!!"
20 | newLine: .asciiz "\n"
21 | targetp: .asciiz "\nTarget Was: "
22 | counter: .asciiz "Guesses: "
23 |
24 | targetArray: .word 0,0,0,0,0,0,0,0,0
25 | guessArray: .word 0,0,0,0,0,0,0,0,0
26 | guessCounter: .word 0
27 |
28 | .text
29 |
30 | main:
31 | la $s5, guessCounter # s5 = guessCounter: counts the number of guesses
32 | lw $s5, 0($s5)
33 |
34 | la $a0, getLength
35 | li $v0, 4
36 | syscall # print message to get length from user
37 |
38 | li $v0, 5
39 | syscall
40 | move $t9, $v0 # move user input into t9
41 |
42 | la $a0, targetArray # a0 = address of the targetArray
43 | move $a1, $t9 # a1 = length
44 | jal GenerateNumber # GenerateNumber(targetArray, length)
45 | move $s7, $v0 # s7 = TargetNumber (NOT THE ARRAY, BUT THE ACTUAL NUMBER)
46 |
47 | la $a0, init1 # print initial message
48 | li $v0, 4
49 | syscall
50 |
51 | move $a0, $t9 # print length
52 | li $v0, 1
53 | syscall
54 |
55 | la $a0, init2
56 | li $v0, 4
57 | syscall
58 |
59 | # Uncomment the code below to "cheat" and
60 | # see the generated number before start guessing
61 |
62 | # move $a0, $t9
63 | # la $a1, targetArray
64 | # jal printList
65 |
66 | # la $a0, newLine
67 | # li $v0, 4
68 | # syscall
69 |
70 | game:
71 | move $a0, $s7
72 | la $a1, guessArray
73 | move $a2, $t9
74 | jal getInput #getInput(generatedNumber, addressGuessArray, length)
75 |
76 | la $a0, targetArray
77 | la $a1, guessArray
78 | move $a2, $t9
79 | jal CompareArrays #CompareArrays(addressTargetArray, addressGuessArray, length)
80 |
81 | j game
82 |
83 | #-------------------- GenerateNumber --------------------#
84 | # The function GenerateNumber takes as a parameter
85 | # the array where the generated number will be stored.
86 | #
87 | # It generates a random number b/t 10*length*1
88 | # and 10*length*9 using syscall 42 (i.e. if length = 4
89 | # then the generated number is between 1000-9990).
90 | #
91 | # Then, it separates the digits in the generated number
92 | # and stores them in the array that was passed as a
93 | # parameter.
94 | #
95 | # Then it checks if the digits of the number are unique,
96 | # if they are not, it generates a random number again.
97 | #
98 | # At the end the function will return the generated number,
99 | # and the digits of generated number will be in the array passed.
100 |
101 | GenerateNumber:
102 | ######### Allocate Stack Space #########
103 | addi $sp, $sp, -12 # allocate stack space for 3 values
104 | sw $ra, 0($sp)
105 | sw $s3, 4($sp)
106 | sw $s4, 8($sp)
107 |
108 | ######### Init variables #########
109 | move $s3, $a0 # s3 = array address
110 | move $s4, $a1 # s4 = length or array
111 | move $t8, $0 # t8-t1 auxiliary variables used for intermidiate calculations.
112 | move $t7, $0
113 | move $t5, $0
114 | move $t4, $0
115 | move $t3, $0
116 | move $t1, $0
117 |
118 | GenerateRandom:
119 | ######### Generate Random Number #########
120 | move $t0, $s4 # t0 = i
121 | li $t7, 1 # lower bound for random
122 | li $a1, 8 # upper bound for random
123 |
124 | CreateLimit:
125 | beqi $t0, 1, generate # if i != 1
126 |
127 | muli $a1, $a1, 10 # mul lupper bound by 10
128 | muli $t7, $t7, 10 # mul lowe bound by 10
129 | addi $t0, $t0, -1 # i--
130 |
131 | j CreateLimit
132 |
133 | generate:
134 | li $v0, 42 # generates random number and places it in a0
135 | syscall
136 | add $t8, $a0, $t7 # t8 = target number
137 |
138 | move $a0, $t8
139 | move $a1, $s3
140 | move $a2, $s4
141 | jal SeparateNumbers # SeparateNumbers(generatedNumber, addressTargetArray, length)
142 |
143 | move $t6, $0 # i = 0
144 | move $t2, $0
145 | addi $t2, $t2, 1 # j = 1
146 |
147 | UniqueLoop: # check if generated number has unique digits
148 | bge $t6, $s4, EndUnique # if i < length
149 |
150 | sll $t5, $t6, 2
151 | add $t4, $s3, $t5
152 | lw $t3, 0($t4) # t3 = array[i]
153 |
154 | InnerUnique:
155 | bge $t2, $s4, EndInnerUnique # if j < length
156 |
157 | sll $t5, $t2, 2
158 | add $t4, $s3, $t5
159 | lw $t1, 0($t4) # t1 = array[j]
160 |
161 | beq $t1, $t3, GenerateRandom # if array[i] = array[j]
162 | addi $t2, $t2, 1
163 |
164 | j InnerUnique
165 |
166 | EndInnerUnique:
167 | addi $t6, $t6, 1 # i++
168 | addi $t2, $t6, 1 # j = i+1
169 | j UniqueLoop
170 |
171 | EndUnique:
172 | ######### Prepare Return Values #########
173 | move $v0, $t8 # move generated number to retun register
174 | ######### Restore Stack Space #########
175 | lw $ra, 0($sp)
176 | lw $s3, 4($sp)
177 | lw $s4, 8($sp)
178 | addi $sp, $sp, 12
179 | jr $ra
180 |
181 | #-------------------- SeparateNumber --------------------#
182 | # The SeparateNumbers function takes as parameters a number,
183 | # an array address, and the length of the array.
184 | #
185 | # The function separates the digits of the number using
186 | # modulos and divisions, and stores the digits in the
187 | # provided array.
188 |
189 | SeparateNumbers:
190 | ######### Allocate Stack Space #########
191 | addi $sp, $sp, -16 # allocate stack space for 4 values
192 | sw $ra, 0($sp)
193 | sw $s0, 4($sp)
194 | sw $s1, 8($sp)
195 | sw $s2, 12($sp)
196 | ######### Init variables #########
197 | move $s0, $a0 # s0 = number to split
198 | move $s1, $a1 # s1 = address of array
199 | move $s2, $a2 # s2 = length
200 | li $t0, 1 # t0-t4 auxiliary variables used for intermidiate calculations.
201 | li $t1, 10
202 | move $t2, $0
203 | move $t3, $0
204 | move $t4, $0
205 | move $t5, $s2
206 | addi $t5, $t5, -1 # t5 = index = length - 1
207 |
208 | SeparateLoop:
209 | ######### Separate Numbers #########
210 | bltz $t5, EndSeparate # if index >= 0
211 |
212 | div $s0, $t1
213 | mfhi $t2 # t2 = s0 % t1
214 | div $t2, $t0
215 | mflo $t3 # t3 = t2/t0 (integer division) --> ith digit
216 |
217 | sll $t4, $t5, 2
218 | add $t6, $s1, $t4 # t6: get offset for array[index*4]
219 | sw $t3, 0($t6) # Store digit t3 in array[index*4]
220 | addi $t5, $t5, -1 # i--
221 |
222 | muli $t0, $t0, 10
223 | muli $t1, $t1, 10
224 |
225 | j SeparateLoop
226 |
227 | EndSeparate:
228 | ######### Restore Stack Space #########
229 | lw $ra, 0($sp)
230 | lw $s0, 4($sp)
231 | lw $s1, 8($sp)
232 | lw $s2, 12($sp)
233 | addi $sp, $sp, 16
234 | jr $ra
235 |
236 | #-------------------- getInput --------------------#
237 | # getInput takes as a a parameter the target number
238 | # and the address of the guessArray.
239 | #
240 | # It prompts the user to input a guess, then it
241 | # increases the guess counter, then if the target is
242 | # equal to the guess, go to Win, and if the target is
243 | # the special input 0 go to Terminate.
244 | #
245 | # Otherwise, separate the digits of the guess number
246 | # and store the digits in the provided array.
247 |
248 | getInput:
249 | ######### Allocate Stack Space #########
250 | addi $sp, $sp, -16 # allocate stack space for 3 values
251 | sw $ra, 0($sp)
252 | sw $s7, 4($sp)
253 | sw $s6, 8($sp)
254 | sw $s4, 12($sp)
255 | ######### Init variables #########
256 | move $s4, $a2 # s4 = length
257 | move $s6, $a1 # s6 = guessArray
258 | move $s7, $a0 # s7 = target number
259 | move $t5, $0 # t5-t6 = auxiliary variables used for intermidiate operations
260 | move $t6, $0
261 | ######### Print prompt and get guess from user #########
262 | la $a0, iPrompt
263 | li $v0, 4
264 | syscall # print please input guess
265 |
266 | li $v0, 5
267 | syscall
268 | move $t6, $v0 # t6 = guess
269 |
270 | addi $s5, $s5, 1 # guessCounter++
271 |
272 | beq $t6, $s7, Win # if the targetNumber and guessNumber are equal go to Win
273 | beq $t6, $zero, Terminate # if input is 0 go to Terminate
274 | j SeparateGuess # if none of the beq above are true,
275 | # continue to separate the digits in guess
276 |
277 | Win:
278 | ######### Print Win Message #########
279 | la $a0, win
280 | li $v0, 4
281 | syscall # print you Won!!
282 |
283 | la $a0, newLine # print new line
284 | li $v0, 4
285 | syscall
286 |
287 | la $a0, counter # guesses:
288 | li $v0, 4
289 | syscall
290 |
291 | move $a0, $s5 # print guessCounter
292 | li $v0, 1
293 | syscall
294 |
295 | li $v0, 10
296 | syscall
297 |
298 | Terminate:
299 | ######### Print Terminate Message #########
300 | addi $s5, $s5, -1
301 |
302 | la $a0, targetp # print target was:
303 | li $v0, 4
304 | syscall
305 |
306 | move $a0, $s4
307 | la $a1, targetArray
308 | jal printList # printList(length, addressTargetArray)
309 |
310 | la $a0, newLine # print new line
311 | li $v0, 4
312 | syscall
313 |
314 | la $a0, counter # guesses:
315 | li $v0, 4
316 | syscall
317 |
318 | move $a0, $s5 # print guessCounter
319 | li $v0, 1
320 | syscall
321 |
322 | li $v0, 10
323 | syscall
324 |
325 | SeparateGuess:
326 | ######### Separate digits in guess #########
327 | move $a0, $t6
328 | move $a1, $s6
329 | move $a2, $s4
330 | jal SeparateNumbers # SeparateNumbers(guessedNumber, guessArray, length)
331 |
332 | ######### Restore Memory #########
333 | lw $ra, 0($sp)
334 | lw $s7, 4($sp)
335 | lw $s6, 8($sp)
336 | lw $s4, 12($sp)
337 | addi $sp, $sp, 16
338 | jr $ra
339 |
340 | #-------------------- CompareArrays --------------------#
341 | # The function ComapareArrays takes as parametes two arrays,
342 | # and the length of the arrays (it assumes the leght of both
343 | # arrays is equivalent). It compares the two arrays using
344 | # two loops.
345 | #
346 | # Each number of array1 is compared with each number of array2.
347 | #
348 | # If, any of the number are the same, generate a message
349 | # accordingly.
350 | #
351 | # If the comparison is over and no picos or fermis were
352 | # printed, print bagel.
353 |
354 | CompareArrays:
355 | ######### Allocate Stack Space #########
356 | addi $sp, $sp, -12 # allocate stack space for 3 values
357 | sw $ra, 0($sp)
358 | sw $s0, 4($sp)
359 | sw $s1, 8($sp)
360 | ######### init Variables #########
361 | move $s0, $a0 # s0 = array1
362 | move $s1, $a1 # s1 = array2
363 | move $s2, $a2 # s2 = lenght
364 | move $t3, $0 # t3 = Fermis and Pico Counter
365 | move $t4, $0 # t4 = aux = 0
366 | move $t6, $0 # t6 = aux = 0
367 | move $t7, $0 # t7 = i = 0
368 | move $t5, $0 # t5 = j = 0
369 |
370 | CompareLoop:
371 | ######### Compare Numbers #########
372 | bge $t7, $s2, EndCompare # if i < length
373 |
374 | sll $t6, $t7, 2
375 | add $t4, $s0, $t6
376 | lw $t0, 0($t4) # t0 = array1[i]
377 |
378 | Inner:
379 | bge $t5, $s2, EndInner # if j < length
380 |
381 | sll $t6, $t5, 2
382 | add $t4, $s1, $t6
383 | lw $t1, 0($t4) # t1 = array2[i]
384 |
385 | beq $t0, $t1, generateMessage # if array[i] = array[j] generate a message.
386 | addi $t5, $t5, 1
387 |
388 | j Inner
389 |
390 | generateMessage:
391 | ######### Generate Message #########
392 | addi $t3, $t3, 1 # Fermis&PicoCounter++
393 | beq $t7, $t5, printFermi # if i = j
394 |
395 | ######### Print Pico #########
396 | la $a0, newLine
397 | li $v0, 4
398 | syscall
399 |
400 | la $a0, Pico
401 | li $v0, 4
402 | syscall
403 | addi $t5, $t5, 1
404 |
405 | j Inner
406 |
407 | printFermi:
408 | ######### Print Fermi #########
409 | la $a0, newLine
410 | li $v0, 4
411 | syscall
412 |
413 | la $a0, Fermi
414 | li $v0, 4
415 | syscall
416 | addi $t5, $t5, 1
417 |
418 | j Inner
419 |
420 | printBagel:
421 | ######### Print Bagel #########
422 | la $a0, newLine
423 | li $v0, 4
424 | syscall
425 |
426 | la $a0, Bagel
427 | li $v0, 4
428 | syscall
429 |
430 | j afterBagel
431 |
432 | EndInner:
433 | ######### End Inner loop and Restart outer loop #########
434 | move $t5, $0 # restart inner loop j = 0
435 | addi $t7, $t7, 1 # j++
436 | j CompareLoop
437 |
438 | EndCompare:
439 | ######### Print Bagel if necessary, and end function #########
440 | beqz $t3, printBagel # if no picos or fermis were printer, print bagel
441 |
442 | afterBagel:
443 | ######### Restore Stack Space #########
444 | lw $ra, 0($sp)
445 | lw $s0, 4($sp)
446 | lw $s1, 8($sp)
447 | addi $sp, $sp, 12
448 | jr $ra
449 |
450 | #-------------------- printList --------------------#
451 | # Function printList take as parameters the length of
452 | # the array and its address and loops over the elements
453 | # and prints them one by one.
454 | #
455 | # No need to allocate stack space since this function
456 | # isn't using s register.
457 |
458 | printList:
459 | move $t0, $0 # t0: index i = 0
460 | move $t1, $a0 # t1: arryLength
461 | move $t2, $a1 # t2: Address
462 |
463 | printLoop:
464 | bge $t0, $t1, endPrint # if i < arrayLength
465 |
466 | lw $a0, 0($t2) # print element
467 | li $v0, 1
468 | syscall
469 |
470 | addi $t0, $t0, 1 # ++i
471 | addi $t2, $t2, 4 # Address = address + 4
472 | j printLoop
473 |
474 | endPrint:
475 | jr $ra
476 |
--------------------------------------------------------------------------------
/test/sum.asm:
--------------------------------------------------------------------------------
1 | .text
2 | main: la $1, data # address of data[0]
3 | addi $4, $1, 80 # address of data[0]
4 | call: addi $5, $0, 4 # counter
5 | jal sum # call function
6 | return: sw $2, 0($4) # store result
7 | lw $9, 0($4) # check sw
8 | sw $9, 4($4) # store result again
9 | addi $8, $9, -96 # $8 <- $9 - 96
10 |
11 | print: li $2, 1 # print $8
12 | add $4, $8, $0 # print $8
13 | syscall # print $8 (should be 0x1f8 = 504)
14 | li $2, 11 # print space
15 | li $4, 32 # print space
16 | syscall # print space
17 | li $2, 1 # print $9
18 | add $4, $9, $0 # print $9
19 | syscall # print $9 (should be 0x258 = 600)
20 | li $2, 10 # exit
21 | syscall # exit
22 |
23 | sum: add $8, $0, $0 # sum function entry
24 | loop: lw $9, 0($4) # load data
25 | add $8, $8, $9 # sum
26 | addi $5, $5, -1 # counter - 1
27 | addi $4, $4, 4 # address + 4
28 | slt $3, $0, $5 # finish?
29 | bne $3, $0, loop # finish?
30 | or $2, $8, $0 # move result to $v0
31 | jr $ra # return
32 | nop # done
33 |
34 | .data
35 | data: .word 0xBF800000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x000000A3, 0x00000027, 0x00000079, 0x00000115, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
36 |
--------------------------------------------------------------------------------