Morten said:
You seem to have some knowledge about this.
Actually I like compiler construction and built various
virtual CPU's for them. It's all about practice.
What do you think about this
as a translated 'for' loop? My virtual machine can handle this now. It
should be the equivalent of
for (int i = 0; i < 10; i++)
{
}
-------------------- SAGA code --------------------
push [addr0] ;\
push 10 ;} Store 10 into the first variable
store ;/
push [addr1] ;\
push 0 ;} Store 0 into the second variable
store ;/
loopStart:
push [addr1] ;} Load the second variable
load ;/
push [addr0] ;} Load the first variable
load ;}
lessi ; Compare integer. Is A less than B?
jmpzero endLabel ; No, exit loop
push [addr1] ; Push address of second variable
push [addr1] ;} Load the second variable
load ;/
push 1 ;} Add 1 to the value
addi ;/
store ; Store into the second variable
jmp loopStart ; Start loop over
endLabel:
end ; End function
------------------ SAGA code end ------------------
I really appreciate your help.
Hmm. In the source code, 10 is a compile time constant not a variable.
So I would have expected something like this.
push [addr1] ;\
push 0 ;} Store 0 into the second variable
store ;/
loopStart:
push [addr1] ;} Load the second variable
load ;/
push 10 ;} Load the constant
lessi ; Compare integer. Is A less than B?
jmpzero endLabel ; No, exit loop
push [addr1] ; Push address of second variable
push [addr1] ;} Load the second variable
load ;/
push 1 ;} Add 1 to the value
addi ;/
store ; Store into the second variable
jmp loopStart ; Start loop over
endLabel:
end ; End function
Other then that: looks good.
Now we are back to your original question: 'What instructions should
a virtual CPU have'. Looking at your code, you will easily see a need
for an additional instruction: inci (increment integer). The sequence
push 1
addi
can easily be replaced by
inci ; increment top of stack elemnt
Other improvements: You often will see the sequence
push [some_addr]
load
which can easily be replaced with
load_from [some_addr]
and so on, and so on.
This is what I ment earlier: By looking at the generated assembly
one can often see possible improvements and adjust the instruction
set to include them. But beware: If you see such patterns, make
sure that they are frequent enough that it really pays to introduce
a new instruction. Eg. I once created a language which included
elements for doing 3D-graphics programming. In the instruction set
I had instructions for creating points, lines, edges, faces, lights,
and so on. I thought a while about also including a special instruction
for calculating the phythagorean distance ( sqrt(x*x+y*y+z*z) ) of 2
points. But I noticed that it was far to infrequently used to keep
it.