First, logically speaking, some of the most useful and complex operations are the binary operators, which are three operand in the sense they use two sources and one destination; they are useful like addition, and complex because of the number of operands necessary.
A one operand machine like MARIE almost certainly has an accumulator. It can specify one of the sources and then uses the accumulator for the 2nd source operand, and also to for the target to capture the result. (As @Peter notes, a one operand machine can also be a stack machine.)
MARIE is already such a machine: we look to see how the binary operators are performed, and in case of MARIE, these are add
and subt
— these instructions specify one (source) memory operand and the other source operand is taken as the accumulator, while the result is captured back into the accumulator.
MARIE also has "unary" operations, the load & store, that provide one memory operand (as source or as target, respectively) and also work with the accumulator.
I'm not sure how I'd go about translating my program into this type of instructions.
When we translate C code to assembly, or one assembly to another, there are three logical constructs that you will need to identify to translate:
- variables
- expressions
- statements
I'd suggest you focus, for starters, on code sequences like the following:
load result
add a
store result
For the above, you will need to make a mapping of a
and result
to storage, this goes to the translation of variables. So, for example, you might choose to put a
into location 0, (b
into location 1), and result
into location 2.
(We can't tell you whether these locations are free for you to use, but since you specify Harvard Architecture, we'll assume you can use data locations starting from 0.)
Next, you'll need to translate instructions for doing the complete addition assignment statement, using the variable mapping you've already done. So, something like:
MARIE |
Variables Mapped |
Your VM |
load result |
load 2 |
1 2 |
add a |
add 0 |
2 0 |
store result |
store 2 |
3 2 |
Finally, as this is a simple assignment statement, you would generally put it in the same place relative to other code as it is in the MARIE assembly.
Loops require that you look at the control flow constructs more closely, but MARIE already has relatively primitive control structures that are reflected in your VM.
multiply, load result
add a
store result
load b
subt one
store b
skipcond 400
jump multiply
This loop does the following (in C):
do {
result += a;
} while (--b != 0);
The intent is to repeat the addition until b
, counted downwards, becomes zero. Translation to your VM should be straightforward.
Since the MARIE code is using SkipCond 400
, which is skip on zero — and what is being skipped is a jump
, then semantically it means jump
on non-zero.
However, since MARIE is using an assembler with labels that I think you don't have, you'll need to supply a count or value instead of a label for the operand of the jump
instruction. There's two basic architectural choices in what the operand for jump
would mean, either an absolute address (this is what MARIE does), or a pc-relative offset (that most other machines will do). Once you decide what the operand means (how the operand identifies the target), then you need an encoding for that (i.e. if pc-relative, how to encode negative numbers for backward branch).
You can think a bit on what you want your in
(and out
) to do. MARIE doesn't take operands for this; it uses the accumulator for the target of input
and source of output
. Of course, you can make your in
& out
use operands instead, so in MARIE we might say two instructions: in; store a
and you will have just one instruction, i.e. in a
, or 5 0.