5 ms·
I recently did a similar project but I tried something different in an attempt to avoid large switch statements. I created a collection of functions which could
by gravypod 9y ago
I recently did a similar project but I tried something different in an attempt to avoid large switch statements. I created a collection of functions which could mutate my version of the "Frame" object, created an array of pointers to these functions, and called them as their opcodes were encountered. [0] It's a little over complicated for a simple example but adding a new opcode will never be more work then this [1].
I hope one day my VM/Assembler will become as fully featured as this.
My last major achievement was implementing multiplication in my assembly language [2] so I've got a lot of catching up to do with this author!
[0] - https://github.com/gravypod/computer/blob/master/isa/main.c#L89-L120 https://github.com/gravypod/computer/blob/master/isa/main.c#...
[1] - https://github.com/gravypod/computer/blob/master/isa/instructions/add.c#L3-L11 https://github.com/gravypod/computer/blob/master/isa/instruc...
[2] - https://github.com/gravypod/computer/blob/master/examples/mul.asm https://github.com/gravypod/computer/blob/master/examples/mu...
- katastic 9y ago>but I tried something different in an attempt to avoid large switch statements. This must be some sort of generation gap. Because array of pointers for opcodes is like... emulator 101. It's just a jump table. Glad you're learning and trying stuff though!
- loeg 9y agoAnd compilers will often create jump tables from large switch statements anyway.
- mikebenfield 9y agoIndeed. At least in my experience, Rust (or LLVM, presumably) will make jump tables from all sorts of nonsense, doing something efficient even when there are gaps in matched values. Manually creating jump tables seems to be a waste of time. (Actually, it doesn't even need to be a switch statement... Just a succession of `if`s works fine.)
- FRex 9y agoTables made out of computed gotos (so not exactly function pointers) are supposedly speeding CPython up: https://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables https://eli.thegreenplace.net/2012/07/12/computed-goto-for-e... I've also found this comment in Python 3.6 source code in ceval.c which is where opcode dispatch is: https://pastebin.com/kuV7UfG0 https://pastebin.com/kuV7UfG0
- DSMan195276 9y ago> At least in my experience, Rust (or LLVM, presumably) will make jump tables from all sorts of nonsense, doing something efficient even when there are gaps in matched values. Manually creating jump tables seems to be a waste of time. I wouldn't say it is always a waste of time just because jump tables can be easier to read and manage when you have a decent number of opcodes. Being able to have all your opcodes in separate functions and then just have one single list that shows exactly what opcode maps to what instruction is really nice: https://github.com/mkilgore/yaji/blob/master/src/op.c#L336 https://github.com/mkilgore/yaji/blob/master/src/op.c#L336 To each his own though, you're right it likely doesn't matter that much performance wise.
- Cyph0n 9y agoWhy do you need to implement multiplication in software? Does your target architecture not have a hardware multiplier? FYI, even microcontrollers nowadays have efficient hard multipliers. It would make more sense to emulate floating point multiplication imo. Anyways, keep up the good work!
- gravypod 9y agoI was designing my own ISA for a computer I want to build out of relays (eventually). I want everything to be in software because I'm a software guy and relays are expensive. You can find more about what I was trying to do here: http://blog.gravypod.com/?title=lets_write_a_processor http://blog.gravypod.com/?title=lets_write_a_processor
- HumanDrivenDev 9y agoIIRC this is called "subroutine threaded code". A few techniques for dispatching instructions for virtual machines are discussed here: http://www.complang.tuwien.ac.at/forth/threaded-code.html http://www.complang.tuwien.ac.at/forth/threaded-code.html
- larsbrinkhoff 9y agoYou probably mean "direct threaded" or "indirect threaded". Subroutine threading is when the VM code compiles to subroutine call instructions that the host computer can execute directly.
- gravypod 9y agoI'll have to read up on that. Seems like a case of me not knowing the terms! Thanks for the pointer.
- FRex 9y agoIf everyone uses switches or computed goto[0] then I assume there is a reason for using that over portable and easy to understand (compared to huge function that switch causes or the compiler specific computed goto) array of function pointers. Performance probably. If array of pointers would end up quicker than either it'd be quite funny because computed goto is a performance (and well, allows jumping programatically to different labels without a switch, I guess) tool and a large switch is IMO less readable than either of the other two. There is a big comment [1] in ceval.c in Python 3.6 source explaining the computed goto mechanics. [0] - https://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables https://eli.thegreenplace.net/2012/07/12/computed-goto-for-e... [1] - https://pastebin.com/kuV7UfG0 https://pastebin.com/kuV7UfG0