Age | Commit message (Collapse) | Author |
|
Here is where we may have differing interpretations of what the bits
in the data pile may actually mean. This in particular refers to
printing the signed or unsigned versions of the bits given. Also,
interpreting some byte as a character or just a raw number.
|
|
Only happens when vm_print_program(STDERR), as STDERR occurs before
STDOUT on Emacs. So while the lines would print, no instructions
would follow. This fixes that by using fp.
|
|
Was only used for OP_PUSH data types anyway, so is essentially
useless. Only OP_PUSH has operands after it that directly relate to
it: the rest either have a fixed type (a byte for registers, for
example) or NIL (because they have no operand).
|
|
Routines that use the stack for their operands i.e. aren't supplied
operands directly all have the same signature. We may as well stick
them all together in one array and one conditional, just reduces the
number of branches. Also looks nicer.
Implemented OP_PLUS_*. Pretty simple to implement.
Deleted vm_peek as it was only necessary to update the `ret` register.
|
|
Takes two operands from the stack then pushes their sum.
|
|
|
|
Every vm routine now returns an err_t, which is an enumeration of
possible error states. ERR_OK represents the good state and is 0 so
error checking seems very natural in terms of language `if (err) ...`.
Errors bubble up the runtime, with any callers forced to check if an
error occurred.
This does mean that routines that call other routines cannot provide
an accurate trace of the subcaller (based on the fact that an error is
generated for the current instruction), but this should be a non issue
as no instruction should be complex enough to need proper traces.
|
|
Uses the stack and register, respectively, to jump to an absolute
address. The stack based jump pops a word off the stack to perform a
jump, while the register based one uses the operand to figure out
which register to use.
|
|
Wasn't useful or necessary.
|
|
Jumps to the operand given, interpreted as a word, an absolute
address.
|
|
This adds a bound on vm_execute_all to stop program->ptr from going
past program->max.
|
|
|
|
Wasn't very secure for endianness, and using these helpers abstracts
the details away a bit in case I want to enforce a certain system.
|
|
If I add a new operand I want the build system to be more helpful in
finding the places I need to change to make it work.
|
|
Duplicates the nth datum off the stack, pushing it to the top. Useful
for operations such as MOV which eat the stack.
|
|
Use (H)WORD_SIZE more, added some notes, etc
|
|
Uses memcpy internally, so we don't need to care about endianness.
|
|
|
|
This is because we were checking them as if they were word registers.
|
|
For each cycle, print the cycle and any changes. We track changes on
the stack by remembering the previous stack pointer. For registers, I
remember the previous array of registers and do a byte level compare
of the current registers and the remembered ones.
Produces pretty log messages and an easy way to track execution.
|
|
Easier to read now
|
|
|
|
Will be used to provide traces during program execution or assembly.
|
|
|
|
Prints the opcode then any operands in the following brackets
|
|
Instead of making routines to handle data in the `ret` register, just
store the result of POP into the last word register.
This means we are no longer using vm_pop_* or POP_ROUTINES for the
vm_execute script on OP_POP: instead we'll just use vm_mov_* which
automatically pops the datum for us, while moving the datum to the
last register.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Does a bit level version of each of these.
|
|
Instead of having 3 differing macros for each typed version of each
opcode, just supply the type as a symbol to the macro, which will
concatenated the type to all the places necessary.
Relies on D(BYTE|HWORD|WORD) and OP_*_(BYTE|HWORD|WORD) being a
consistent naming style.
|
|
Handles OP_HALT
|
|
|
|
|
|
|
|
Registers are now just words, with pushing from and moving to
registers with specified subtypes just pushing those types into the
word registers. That means there are 8 word registers which can act
as 16 half word registers, which themselves can act as 64 byte
registers.
|
|
Prints each aspect of the vm, and vm_print_all does it all.
|
|
Pretty self explanatory, helps with logging.
|
|
Given a filepath, helper function to write a buffer of bytes to a file
and to read a file completely as a buffer.
|
|
Seems pretty nice to use, and it works according to GDB.
|
|
Pushed the bits one step too far.
|
|
|
|
|
|
We won't have more than 255 registers, so a byte is all that's
necessary.
|
|
Uses some bit hacks to quickly check what data type an opcode may have
by shifting down to units then casting it to a data_type_t.
Not very well tested yet, we'll need to see now.
|
|
|
|
Instead of taking an operand and a register, mov just uses the stack
for the operand. Therefore, there's no need for a register member in
inst_t.
As a result, PUSH_*_REGISTER now uses the operand for the register.
|