Virtual Machine (definition)
version 2.0, done by Mc in 2002

table of contents:

- short description
- register sizes
- memory formats
- register signs
- register set
- addressing modes
- condition codes
- syntax codes
- instruction sets
- system calls
- error codes
- keyboard codes
- access rights
- filesys buffer

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.

table of contents

sizes:

b | byte | 8 bits
w | word | 16 bits
d | double word | 32 bits
q | quad word | 64 bits

table of contents

formats:

d | default bit order
m | Most Significant Bit first
l | Least Significant Bit first

table of contents

signs:

s | signed
u | unsigned

table of contents

registers:

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

table of contents

addressing:

[src+-number]
[trg+-number]

table of contents

conditions:

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

table of contents

syntax:

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

table of contents

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

table of contents

syscalls:

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) format: d:size, d:rights, d:owner, t:create, t:modify, pascii:name t: w:year, b:month, b:day, b:hour, b:minute, b:second
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: 0=demand, 1=single, 2=block, 3=cascade; 00h=verify, 10h=card>>mem, 20h=mem>>card
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

table of contents

errors:

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

table of contents

keys:
first byte bits:

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

table of contents

rights:

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

table of contents

filesys:
buffer:

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

table of contents