Virtual
Machine (definition)
version
1.0, done by Mc in 2002
The purpose of this
virtual machine is to create a new, general purpose, hardware
independent environment to speed up application development. Imagine
that applications could be developed in any (high level) language.
The compiler first generates code for this virtual machine and in the
second step, an other simply assembler generates working code for
existing processors. The main advantage of this technique is that
high level compilers do not require modification to support new
hardware environment, and every application could compile to any
hardware without modification. So we can say that once we have a good
compiler, it can compile for any (possible not yet existing) hardware
environments. To do this, a simple assembler is needed to generate
machine specific code. It means that this virtual machine code could
be used as an intermediate language between higher level languages
and the machine code. Because of this, virtual machine is defined
with minimal set of instructions and registers, so every existing
(and hopefully future) processors could used as target machine.
The
only things what higher level compilers should know about target
environment are the size of address, and the default integer size,
but of course this knowledge is not required, a well chosen address
size could be enough for every platform.
Another partition of
this idea is the way how applications make system calls (such as file
handling, etc). To make a general purpose virtual machine, we need to
define these complex things at 'processor' level. This is done
through the syscall instruction. Once an application wants to do
something with the system, puts the appropriate syscall to the
virtual machine code, and the assembler generates the hardware
specific code to binary output.
b |
byte |
8 bits |
w |
word |
16 bits |
d |
double word |
32 bits |
q |
quad word |
64 bits |
d |
default bit order |
m |
Most Significant Bit first |
l |
Least Significant Bit first |
s |
signed |
u |
unsigned |
a |
data |
b, w, d, w |
b |
data |
b, w, d, w |
c |
data |
b, w, d, w |
d |
data |
b, w, d, w |
src |
pointer |
depends on architecture |
trg |
pointer |
depends on architecture |
[src+-number] |
[trg+-number] |
a |
above |
b |
below |
e |
equal |
ae |
above or equal |
be |
below or equal |
na |
not above |
nb |
not below |
ne |
not equal |
nae |
nor above nor equal |
nbe |
nor below nor equal |
platform |
name |
|
the name of platform used at higher level |
proc |
label |
|
beginning of subroutine |
endp |
|
|
end of subroutine |
label |
label |
|
place a label here |
defb |
number(s) |
|
place byte(s) in code |
defw |
number(s) |
|
place word(s) in code |
defd |
number(s) |
|
place double word(s) in code |
defq |
number(s) |
|
place quad word(s) in code |
const |
name |
number |
let constant name equal to number |
instructions:
note1:
the upper remainder parts of registers are not tested, and have
invalid contents after execution.
note2: the conditions are
destroied by instructions, so a jmpc or setc must preceded by a comp
instruction.
add |
size |
reg |
reg/num |
adding op2 to op1 |
sub |
size |
reg |
reg/num |
subtract op2 from op1 |
mul |
sign size |
reg |
reg/num |
multiply op1 by op2 |
div |
sign size |
reg |
reg/num |
divide op1 by op2 |
mod |
sign size |
reg |
reg/num |
remainder from dividing op1 by op2 |
or |
size |
reg |
reg/num |
bitwise oring op1 by op2 |
xor |
size |
reg |
reg/num |
bitwise xoring op1 by op2 |
and |
size |
reg |
reg/num |
bitwise anding op1 by op2 |
not |
size |
reg |
|
bitwise noting op1 |
neg |
size |
reg |
|
negating op1 |
shl |
size |
reg |
reg/num |
shift left op1 by op2 bits |
shr |
size |
reg |
reg/num |
shift right op1 by op2 bits |
push |
size |
reg |
|
put op1 to top of stack |
pop |
size |
reg |
|
get value from top of stack to op1 |
comp |
sign size |
reg |
reg/num |
compare op1 to op2 |
move |
op1.sign op1.size op2.sign op2.size |
reg |
reg/num |
move op2 to op1 |
movr |
format op1.sign op1.size op2.sign op2.size |
reg |
mem |
read op1 from memory |
movw |
format op1.sign op1.size op2.sign op2.size |
mem |
reg |
write op2 to memory |
call |
label |
|
|
jump to label, push offset to stack |
cllr |
src/trg |
|
|
jump to an address, push offset to stack |
ret |
|
|
|
return to saved offset |
jump |
label |
|
|
jump to label |
jmpr |
src/trg |
|
|
jump to an address |
jmpc |
condition |
label |
|
jump to label if condition is true |
setc |
condition |
size |
reg |
set the register to 1 if condition is true, else 0 |
xchg |
size |
mem |
reg |
exchange value in op2 register with op1 memory |
addrLod |
src/trg |
mem |
|
load address from memory to op1 |
addrSav |
mem |
src/trg |
|
save address from op2 to memory |
procAddr |
src/trg |
num |
|
setup op1 to beginning of op2 subroutine's data block |
procAllocBeg |
num |
num |
|
begin allocating op2 bytes to op1 subroutine; use the - as number |
procAllocEnd |
num |
num |
|
finish allocating op2 bytes to op1 subroutine |
procFree |
num |
num |
|
release op2 bytes from op1 subroutine |
codeOfs |
src/trg |
label |
|
get offset of label in code |
sysCall |
function |
|
|
do the function, parameters are in registers |
startup |
|
|
starts the code here [maxproc] [maxstack] [maxheap] |
terminate |
w:a |
|
terminates the code withe error code a |
sleep |
|
|
sleeps the process for a while |
memCopy |
src trg d:c |
|
copy c bytes from [src] to [trg] in memory |
memCopy2 |
src trg d:c |
|
copy c bytes from [src] to [trg] in memory, cares on overlapping |
memFillByte |
trg b:a d:c |
|
fill a byte to trg c times |
memResize |
d:c |
d:c trg |
resize the memory to c, returns the size, and beginning |
getMemInfo |
|
d:c trg |
returns the size, and beginning of extended memory |
codeCopy |
src trg d:c |
|
copy c bytes from code [src] to memory [trg] |
console.write |
src d:c |
|
write c bytes from src to the console |
console.iskey |
|
b:a |
test for char on console (1=yes, 0=no) |
console.read |
trg d:c |
d:c |
read c bytes to trg from the console, returns number of bytes read in c |
console.size |
|
w:a w:b |
read console size (a=x, b=y) |
console.clear |
|
|
clears the console |
console.gotoXY |
w:a w:b |
|
set the cursor to a column and b row |
console.setColor |
b:a |
|
set the pen color to ibm attributes |
console.getDate |
|
w:a w:b w:c |
returns current date, a-year, b-month, c-day |
console.getTime |
|
w:a w:b w:c |
returns current time, a-hour, b-minute, c-second |
console.execWait |
src trg |
w:a w:b |
execute process in trg with src parameter, wait until terminate, returns exitcode in a (b=error) |
file.maxName |
|
w:a |
returns maximum name length |
file.myName |
trg |
w:c |
returns pathname of running process |
file.myParam |
trg |
w:c |
returns parameters of running process |
file.open |
src d:a |
d:a w:b |
open file on pascii name src with a rights, handler returned in a (b=error) |
file.read |
d:a trg d:c |
d:c w:b |
read c bytes to trg memory from file handler a, return c bytes read, (b=error) |
file.write |
d:a src d:c |
w:b |
write c bytes from src memory to file handler a (b=error) |
file.seek |
d:a d:c |
w:b |
seek to c position in file handler a (b=error) |
file.getSize |
d:a |
d:c w:b |
get file size to c from handler a (b=error) |
file.getPos |
d:a |
d:c w:b |
get file position to c from handler a (b=error) |
file.truncate |
d:a |
w:b |
truncate file handler a (b=error) |
file.close |
d:a |
w:b |
close the file handler a (b=error) |
file.create |
src |
w:b |
create pascii src named file (b=error) |
file.erase |
src |
w:b |
erase pascii src named file (b=error) |
dir.current |
trg |
w:b |
get working directory to trg in pascii (b=error) |
dir.change |
src |
w:b |
change working directory from src in pascii (b=error) |
dir.statistic |
|
d:a d:b d:c d:d |
get disk statistics: a-free, b-used, c-bad, d-blocksize |
dir.setRights |
src d:a d:b |
w:b |
set directory entry access rights to a and owner to b (b=error) |
dir.setDate |
src trg |
w:b |
set src directory entry create,modify date to trg (b=error) |
dir.reName |
src trg |
w:b |
rename src directory entry to trg name (b=error) |
dir.makeLink |
src trg |
w:b |
create link to src directory entry under trg name (b=error) |
dir.open |
src |
d:a w:b |
open directory on pascii src name, handler returned in a (b=error) |
dir.read |
d:a trg |
w:b |
read dir entry to trg memory from dir handler a
(b=error) |
dir.close |
d:a |
w:b |
close the directory handler a (b=error) |
dir.create |
src |
w:b |
create pascii src named directory (b=error) |
dir.erase |
src |
w:b |
erase pascii src named directory (b=error) |
pipeline.startListen |
|
w:b |
start listening for incoming pipelines (b=error) |
pipeline.stopListen |
|
w:b |
stop listening for incoming pipelines (b=error) |
pipeline.getIncoming |
|
w:b d:a |
get next incoming pipeline number in a (b=error) |
pipeline.create |
d:a d:c b:b |
w:b d:a |
create c bytes pipe to a process b=1 if block mode, pipe id a (b=error) |
pipeline.close |
d:a |
w:b |
close pipeline a (b=error) |
pipeline.info |
d:a |
d:a d:c d:d w:b |
pipeline info, a=process, c=freeTx, d=usedRx (b=error) |
pipeline.receive |
d:a trg d:c |
d:c w:b |
receive c bytes to trg from a pipeline, c bytes received (b=error) |
pipeline.send |
d:a src d:c |
w:b |
send c bytes from src to a pipeline (b=error) |
system.getPID |
|
d:a d:b d:c |
returns a=process id, b=parent process id, c=rights |
system.getUID |
|
d:a d:b |
returns my user id in a, original in b |
system.sysInfoNum |
|
d:a d:c d:d |
returns a=#of proc, c=#of pipes, d=#of files |
system.sysInfoMem |
|
d:a d:c d:d |
returns memory in byte a=total, c=kernel, d=free |
system.sysInfoProc |
|
d:a d:b d:c d:d |
returns process starts a=idles, b=rounds, c=full rounds, d=active start |
system.procInfoNam |
d:a trg |
d:a d:c d:d |
returns info about [a] process, trg=pathname+param, a=uid, c=parent pid, d=rights |
system.procInfoNum |
d:a |
d:a d:c d:d |
returns info about [a] process, a=bytes, c=pipes, d=files |
system.procInfoRun |
d:a |
d:a d:b d:c |
returns process runs a=working since, b=times was busy, c=times run |
system.findProcNum |
d:a |
d:a |
find process by number (0..max-1) |
system.findProcNam |
src |
d:a |
find process by name |
system.cpuInfo |
d:a trg |
d:a d:c |
get cpu info (0..max-1), a=max, c=number |
system.kernelInfo |
trg |
|
get kernel info to trg in asciiZ |
system.kernelLogo |
trg |
|
get kernel logo to trg in asciiZ |
system.procLive |
d:a |
d:b |
check process existence, 0=no, 1=yes |
system.uptimeInfo |
|
d:a d:c d:d |
get uptime info, a=days, c=ticks, d=ticks/day |
system.killProcess |
d:a |
d:b |
kill another process |
syscalls require extra privileges:
system.setUID |
d:a |
|
sets my user id |
console.execBckgnd |
src trg |
d:a w:b |
execute process in background, returns pid in a (b=error) |
console.execInme |
src trg |
d:a d:c w:b |
execute process inside me, returns pid in a, pipe in c (b=error) |
system.mapMemory |
d:a d:c |
d:b trg d:a d:c |
map c bytes from a of physical memory, returns trg as logical offset |
system.contMem |
d:c |
d:b d:a d:c trg |
allocate continous c bytes, returns b=error, a=physical, c=size, trg=beginning |
system.IOportRead |
d:d b:c |
d:a |
read c bits from d port to a |
system.IOportWrite |
d:d b:c d:a |
|
write c bits from d port from a |
system.DMAcount |
w:d |
d:c |
get byte count of dma channel |
system.DMAstop |
w:d |
|
stop dma channel |
system.DMAstart |
w:d d:a d:c b:b |
|
start dma channel a=physical, c=count, b=mode: |
system.driveLogin |
b:a src |
d:b |
login as drive letter |
system.driveLogout |
b:a |
d:b |
logout as drive letter |
system.driveFinished |
|
|
drive signals end of processing |
system.dropPrivi |
|
|
drop privileged flag |
0 |
no error |
1 |
unknown error |
2 |
out of memory |
3 |
out of disk space |
4 |
no right |
5 |
sharing violation |
6 |
path not exists |
7 |
file not exists |
8 |
file already exists |
9 |
invalid handle |
10 |
directory not empty |
11 |
embedded directories |
12 |
file/directory mismatch |
13 |
file pointer too big |
14 |
drive io fault |
15 |
drive not ready |
16 |
eof encountered |
17 |
invalid filename format |
18 |
abnormal program termination |
7 |
extended key |
2 |
alt |
1 |
ctrl |
0 |
shift |
extended keys:
0 |
no operation |
1 |
redraw screen |
2 |
tab |
3 |
backspace |
4 |
enter |
5 |
escape |
6 |
insert |
7 |
delete |
8 |
home |
9 |
end |
10 |
pgup |
11 |
pgdn |
12 |
up |
13 |
down |
14 |
left |
15 |
right |
16 |
printscreen |
17 |
break |
18 |
start-left |
19 |
menu |
20..49 |
f1..f30 |
50 |
start-right |
51 |
wake-up |
52 |
sleep |
53 |
power |
001h |
owner read |
002h |
owner write |
004h |
owner execute |
008h |
anybody read |
010h |
anybody write |
020h |
anybody execute |
040h |
extended privileges |
080h |
directory |
100h |
owner read |
200h |
owner write |
dword |
command/result |
dword |
userid |
dword |
rights |
dword |
buffer size |
string |
current directory |
string |
filename1 |
string |
filename2 |
512 bytes |
handler |
65536 bytes |
data |
commands:
1 |
change directory |
dir, fn1, uid |
2 |
drive statistics |
data: free,used,bad,blockSize:dword |
3 |
create directory |
dir, fn1, uid |
4 |
erase directory |
dir, fn1, uid |
5 |
create file |
dir, fn1, uid |
6 |
erase file |
dir, fn1, uid |
7 |
rename |
dir, fn1, fn2, uid |
8 |
create link |
dir, fn1, fn2, uid |
9 |
set rights |
dir, fn1, uid, data: rights,owner:dword |
10 |
set date |
dir, fn1, uid, data: create,modify:time |
11 |
open directory |
dir, fn1, uid, hdr, data: inode,rights:dword; name:string |
12 |
read directory |
hdr, data: size,right,own:dword; create,modify:time; name:string |
13 |
open file |
dir, fn1, right, uid, hdr, data: inode,rights:dword; name:string |
14 |
read file |
hdr, size, data |
15 |
write file |
hdr, size, data |
16 |
seek file |
hdr, data: position:dword |
17 |
get file size |
hdr, data: filesize:dword |
18 |
get file position |
hdr, data: position:dword |
19 |
truncate file |
hdr |