An important aspect of many computer architecture projects is to modify an instruction set, often to extend the instructions with a new instruction that implements a proposed feature. I'm working on moving some of my research to the GEM5 open source simulator, but first I need to get an idea of the level of effort involved. My first move is to figure out how to add new instructions.
GEM5, being designed especially for computer architecture research, has a well-defined set of pseudo instructions that can be extended to serve my purposes. However, there are not really any instructions on how to extend these instructions. The few emails that I could find about pseudo instructions basically just said go look at what is implemented and extend it. So that is what I did. For posterity, I'll relay my findings here. Maybe they will be helpful to others, or to myself in the future.
Adding a new pseudo instruction (for X86)
I'm interested primarily in the X86 full-system simulation capabilities of GEM5 at the moment, so my effort is in that area. However, the pseudo instructions have implementations in the other architectures, and most of the following will translate directly to them.
- Overwrite a reserved opcode in src/arch/x86/isa/decoder/two_byte_opcodes.isa near the other pseudo instructions (look for m5panic).
- Add the instruction’s functional simulation implementation in src/sim/pseudo_inst.cc
- Add the function prototype in src/sim/pseudo_inst.hh. The function prototype will define the available registers for parameters and return values based on the compiler’s calling conventions for the architecture.
- Create an m5op for easily emitting the instruction in compiled code.
- Add function number in util/m5/m5ops.h
- Add function prototype in util/m5/m5op.h
- Instantiate a TWO_BYTE_OP in m5op_x86.S
I have written a simple example that implements addition as a pseudo instruction. The patch may bit-rot, but the idea should be easy enough to follow.
To use the new pseudo instruction call the function declared in
util/m5/m5op.h. Then (cross-)compile your source code with the m5 utilities like:
gcc -o foo foo.c -I ${GEM5}/util/m5 ${GEM5}/util/m5/m5op_x86.S
To get your code into the simulation, you can
- add the binary to the disk image
- sudo mount -o loop,offset=32256 /dist/m5/system/disks/linux-x86.img /mnt/tmp
- cp foo /mnt/tmp/bin
- or read it directly into the simulation
- build/X86/gem5.debug configs/example/fs.py -r 1 --script=foo
- m5term localhost 3456
- m5 readfile > foo
- chmod +x foo
- ./foo
Adding to the disk image requires restarting the simulation, whereas if you have a checkpoint loaded you can read the file in directly using m5 readfile.
Executing the pseudo instruction on real hardware
You
can also use your new pseudo-instruction in real hardware by providing
an illegal instruction handler (SIGILL handler) that emulates the functionality of the
instruction. This may be useful for debugging purposes, since native hardware can run the emulation code much faster than the simulator will. I have written a simple example that shows how to handle the illegal instruction signal that gets caused when the pseudo instruction is executed. This sample example will execute in both GEM5 and natively (on a 64-bit X86).
I guess that covers it for now. Happy hacking!
How about adding a new instruction ( not a pseudo instruction ) to X86 ISA? Is it possible? is there any location in decoder or other files to add new instruction ?
ReplyDeleteDo you know how I can start changing in ISA ?
Hi. Any knowledge you can share about adding a new instruction?
DeleteAlso thanks for your good information , It helped me a lot :)
ReplyDeleteHey mehrfar, I have not done any work with adding new instructions to the ISA. I'm pretty sure everything is located in a single file "decoder". There may be other resources/notes out there on how to do this right.
ReplyDeleteHey mehrfar, I have not done any work with adding new instructions to the ISA. I'm pretty sure everything is located in a single file "decoder". There may be other resources/notes out there on how to do this right.
ReplyDeleteThank you for sharing this information, but I'm a little bit confused by the difference between adding a new pseudo instruction and a new instruction. Is that both way can extend the ISA, but the pseudo one degrades the performance a lot?
ReplyDeleteThanks a lot!
A pseudo instruction executes atomically and non-speculatively, which roughly means the pipeline has to be flushed and the pseudo instruction has to execute by itself. So the performance could be really bad if you use the pseudo instruction frequently. When you extend the ISA, your instruction should encode its register dependencies so that the instruction can be pipelined and speculated. However, extending the ISA is a lot harder than writing a pseudo instruction.
Deleteis it possible add pseudo instruction and ran a SE system?
ReplyDeletedo you have the source codes? I want simulate your approach.
Psuedo instructions only work in full system as I remember. On SE, you can maybe achieve a similar effect with a custom syscall...
Deletegot it, thanks.
Deleteliuty10 AT gmail DOT com
DeleteI've just tested in gem5 08c79a194d1a3430801c04f37d13216cc9ec1da3 (2019q2) and pseudo-instructions did work in SE, here is my setup: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/038c23729bdea50ed0b6e24cf72d0119645d2b94#m5ops-instructions I would be surprised if they didn't work :-)
DeleteHi, have you succeeded in adding a new instruction to the ISA?
ReplyDeleteHi, I changed the plans e I don't need anymore add new instructions to my work.
DeleteHi, I just wanted to thank you a lot for this demo. I think you just saved my honours project.
ReplyDeleteHello. Thanks for this blog. It helped me a lot.
ReplyDeleteAlso I wanted to know how different it is to add a pseudo instruction for an alpha system. Could you provide any inputs please.
You'll want to start by examining how current pseudoinstructions work for Alpha. The decoder end will differ, and so will the assembly frontend for emitting the instruction.
DeleteThanks for the post. Do you know how we can capture the instruction in the pipeline. I need to send a packet to caches once the instruction executed. But I am not bale to find the instruction while executed.
ReplyDeleteThe instructions are encapsulated in an OO manner, and you could possibly hook into their Execute() or other stage. If the CPU model is OoO or speculative this can be a little challenging.
Delete