使用 Java/C/C++ 创建 MIPS 机器
大家好,我正在上汇编语言和计算机组织课程。最近,我收到一项作业,要求我创建一个程序,用 Java、C 或 C++ 模拟 MIPS 机器。
该程序从 ASM 文件中读取十六进制并将行存储在数组中。然后它应该模拟 MIPS 机器。
我一直在四处寻找,但不知道如何开始。有谁有一些想法甚至伪代码来让我走上正确的道路?
要读取的文件的示例:
24080019
2409001e
240a0023
01094020
010a4020
00082021
如果有人能让我开始走上正确的道路,那就太棒了,谢谢!
Hey everyone I'm in an Assembly Language and Computer Organization class. Recently I got an assignment that requires that I create a program that emulates a MIPS machine in Java, C, or C++.
The program reads hex from a ASM file and stores the lines in an array. Then it is supposed to emulate the MIPS machine.
I've been searching all around but have no idea how to even start. Does anyone have some ideas or even pseudo-code to get me on the right path?
An example of the file to be read:
24080019
2409001e
240a0023
01094020
010a4020
00082021
If anyone can just get me started down the right path that would be fantastic, thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您需要做的第一件事就是学会破译这些指令。
看来它们是 8 个十六进制数字。这很好,因为 MIPS 指令是 32 位长。 (当然,十六进制数字是 4 位。)
因此文件中的每一行对应一条指令。
请查看此处的说明格式:http://www.d.umn。 edu/~gshute/spimsal/talref.html
您需要跟踪机器内的一些寄存器。 (您知道 MIPS 寄存器是什么,对吧?)
然后您需要确定操作的作用以及它们影响哪些寄存器。
The first thing you need to do is to learn to decypher those instructions.
It appears they're 8 hex digits. This is nice, because MIPS instructions are 32 bits long. (a hex digit is 4 bits, of course.)
So each line in the file cooresponds to one instruction.
Look at the format of instructions here: http://www.d.umn.edu/~gshute/spimsal/talref.html
You need to keep track of a few registers inside the machine. (You know what the MIPS registers are, right?)
Then you need to determine what the operations do, and what registers they effect.
SPIM 可能是开始研究如何构建此类程序的好地方。这是一个 MIPS32 模拟器。
SPIM might be a good place to start looking at how such a program might be constructed. It's a MIPS32 simulator.
因此,基本上您的程序将是一个循环,它读取一条指令(输入文件中的一行)*,并以与指令更改其寄存器相同的方式更改其变量。
这将是操作码上的一个大“开关案例”,对于每种情况,您都处理特定的指令。
程序的变量基本上就是寄存器,并且您还必须以某种方式模拟内存(您应该能够一次性分配整个内存作为您将处理的一大块内存)并处理从 MIPS 地址到内存块中的地址的转换。
那么处理操作码基本上就是一个改变寄存器和内存的问题。您可能能够从您的语言中受益于执行一些操作(例如求和、乘积等),但您肯定需要处理比这更多的事情:例如在状态寄存器中设置标志。
我不熟悉 MIPS 指令集,但您可能还需要根据可用的寻址模式进行一些地址转换。
*:实际上,它应该比仅仅逐行读取输入文件更聪明:您应该首先将程序加载到该“内存”数组中,并处理一个程序计数器,该计数器将从第一条指令开始并在处理完后递增。当前指令。有时,流程可能会将 PC 移回原处。理想情况下,您还希望使“内存”的这一部分不可修改,但这不是您首先要关注的内容。
我希望我没有说任何与MIPS无关的话。
所以从结构上来说,这个伪代码给出了一个想法:
So basically your program will be a loop that reads one instruction (one line in the input file)*, and alters its variables in the same fashion the instruction would alter its registers.
This would be a big "switch case" on the opcode, and for each case you handle the particular instruction.
The variables of your program would basically be your registers, and you will also have to simulate a memory somehow (you should be able to allocate your whole memory once and for all as a big chunk of memory that you will handle) and to handle the translation from the MIPS addresses to addresses in your chunk of memory.
Then dealing with the opcodes is basically a question of altering your registers and your memory. You might be able to benefit from your language to do some operations (like sum, product, ...) but you'll most certainly have to handle a bit more than this: set the flags in your status register for instance.
I'm not familiar with MIPS instruction set, but you might also have to do some address translation depending on the available addressing modes.
*: Actually, it should be more clever than just reading the input file line by line: you should load your program in that "memory" array first, and handle a program counter that will start at the first instruction and be incremented after handling the current instruction. Sometimes, the flow might move the PC back. Ideally you'd also want to make this part of the "memory" unmodifiable, but it's not what you want to focus on first.
I hope I didn't say anything irrelevant to MIPS.
So in terms of structure, this pseudo-code gives an idea:
很多年前,我作为课程作业做过类似的事情。不幸的是,资料来源没有保存下来,所以我将尝试整理一些我记得的一般想法。我希望它对您的项目有所帮助。
第一个也是最简单的 - 寄存器块。我把它做成了一个简单的结构。对于标志寄存器,为了方便起见,我创建了一些设置/清除函数。
第二,可能是最需要付出的努力——指令解码。我有一本关于我的目标 CPU 指令集的手册,其中解释了二进制代码中不同位的含义。通常有一些基本的指令类别:算术/布尔运算、控制流指令、内存/寄存器复制/交换以及可能的其他一些指令。另一方面是指令如何寻址操作数。一般来说,有 2 个操作数,每个操作数的寻址都编码在二进制命令中。因此,要解释它们,您需要两件事:
第三——记忆。这取决于目标架构。就我而言,没有段/选择器,并且最大内存量很小,因此我刚刚分配了相应的块。为了访问具体的内存单元,我添加了一个设置/获取函数。内存的某些区域应该由 ROM 占用,因此这个薄层有助于实现它。
第四 - I/O 和中断。这就是事情变得非常复杂的地方,具体取决于要求和平台。最简单的终端输出可以通过将内存块专用于某种屏幕缓冲区来实现。当您的 mem-setter 函数看到对该块的写入时,它会更新您的控制台模拟(您的应用程序中需要一个 GUI,对吗?)。最简单的控制台输入也类似于 8086 架构 - 当用户按下一个键时,您会模拟一个中断,将关键代码传递到其中等。如果您需要更复杂的东西,即具有可加载中断处理程序和/或模拟的真正 BIOS 支持一些 I/O 控制器,那么它将花费与您在机器的先前部件上花费的时间相同的时间。所以不要推迟到最后一周。
I did something like this many years ago as a coursework. Unfortunately, sources didn't survive, so I'll try to put together some general ideas which I remember. I hope it will help you with your project.
First and most simple - register block. I did it as a plain structure. For flag register(s) I created few set/clear functions for the sake of convenience.
Second and probably requiring most effort - instruction decoding. I had a handbook on my target CPU instruction set which explained meaning of different bits in the binary code. There are normally few basic classes of the instructions: arithmetic/boolean operations, control flow instructions, memory/register copying/exchange and probably a couple of others. Another aspect is how the operands are addressed by an instruction. In general there are 2 operands and addressing of each of them is encoded in the binary command. So to interpret them you need two things:
Third - memory. This depends on the target architecture. In my case there were no segments/selectors and the max memory amount was small, so I've just allocated a corresponding block. To access concrete memory cells I added a set/get functions. Some areas of the memory were supposed to be taken by ROM, so this thin layer was helpful to implement it.
Forth - I/O and interrupts. And this is where it can get really complicated, depending on the requirements and the platform. The the simplest terminal output can be achieved by dedicating a memory block for some sort of screen buffer. When your mem-setter function sees a write to that block, it updates your console emulation (you need a GUI in your app, right?). A simplest console input will also resemble a 8086 architecture - when user presses a key you emulate an interrupt, pass key code into it etc. If you need something more complex that that, i.e. real BIOS support with loadable interrupt handlers and/or emulation of some I/O controllers then it will take the same amount of time that you have spent on the previous parts of the machine. So don't delay it to the last week.
你需要考虑两个问题:映射内部状态
模拟机器到模拟器中的变量,并执行代码。
第一个通常由寄存器数组处理,可能在
具有各种其他信息的结构:程序计数器、位图
带有条件代码(假设处理器有这些——我不知道
MIPS 架构)等。第二个将是交换机或
指向函数或函数对象的指针表。如果
架构使用不同的机器指令格式,这可能是
多级表。然后模拟器读取“指令”
当前指令指针,然后通过打开它来“执行”它或
使用它来索引表。一遍又一遍,无限循环。
You need to think about two issues: mapping the internal state of the
emulated machine to variables in your emulator, and executing the code.
The first is normally handled by an array for the registers, probably in
a struct with various other information: a program counter, a bit map
with condition codes (supposing the processor has these---I don't know
the MIPS architecture), etc. The second will be either a switch or
a table of pointers to functions or functional objects. If the
architecture uses different machine instruction formats, this could be
a multilevel table. The emulator then reads the "instruction" at the
current instruction pointer, then "executes" it by switching on it or
using it to index into the table. Over and over, in an endless loop.
这应该可以帮助您开始:
http://www.oberle.org/procsimu-index.html
您必须针对 MIPS 指令集对其进行定制。
This should get you started:
http://www.oberle.org/procsimu-index.html
You would have to customize it for MIPS instruction set.