File MyVM.c added (mode: 100644) (index 0000000..eae6c1b) |
|
1 |
|
// Compile cmd: gcc MyVM.c -o MyVM |
|
2 |
|
// View vm: ./<filename> | xxd |
|
3 |
|
// View bin files: xxd <filename> |
|
4 |
|
|
|
5 |
|
#define NUM_REGS 4 |
|
6 |
|
#define BUF_SIZE 17 |
|
7 |
|
#include <stdio.h> |
|
8 |
|
#include <stdlib.h> |
|
9 |
|
//#include <fcntl.h> // For file read/write |
|
10 |
|
//#include <unistd.h> // For file close |
|
11 |
|
|
|
12 |
|
int regs[NUM_REGS]; |
|
13 |
|
ushort prog[] = {0x0000, 0x0000, 0x0000, 0x0000}; //{ 0x1064, 0x11c8, 0x2201, 0x0000 }; |
|
14 |
|
|
|
15 |
|
int pc = 0; |
|
16 |
|
int fc = 0; |
|
17 |
|
int running = 1; |
|
18 |
|
|
|
19 |
|
int fetch() { return prog[pc++]; } |
|
20 |
|
|
|
21 |
|
int instruction = 0; |
|
22 |
|
int reg1 = 0; |
|
23 |
|
int reg2 = 0; |
|
24 |
|
int reg3 = 0; |
|
25 |
|
int imm = 0; |
|
26 |
|
|
|
27 |
|
void decode (int Instruction) { |
|
28 |
|
instruction = (Instruction & 0xf000) >> 12; |
|
29 |
|
reg1 = (Instruction & 0xf00) >> 8; |
|
30 |
|
reg2 = (Instruction & 0xf0) >> 4; |
|
31 |
|
reg3 = (Instruction & 0xf); |
|
32 |
|
imm = (Instruction & 0xff); |
|
33 |
|
} |
|
34 |
|
|
|
35 |
|
void eval () { |
|
36 |
|
switch(instruction) { |
|
37 |
|
case 0: // instruction = halt |
|
38 |
|
printf("halt\n"); |
|
39 |
|
running = 0; |
|
40 |
|
break; |
|
41 |
|
case 1: // instruction = loadi |
|
42 |
|
printf("loadi r%d #%d\n", reg1, imm); |
|
43 |
|
regs[reg1] = imm; |
|
44 |
|
break; |
|
45 |
|
case 2: // instruction = add |
|
46 |
|
printf("add r%d r%d r%d\n", reg1, reg2, reg3); |
|
47 |
|
regs[reg1] = regs[reg2] + regs[reg3]; |
|
48 |
|
break; |
|
49 |
|
} |
|
50 |
|
} |
|
51 |
|
|
|
52 |
|
void showRegs () { |
|
53 |
|
int i; |
|
54 |
|
printf("regs = "); |
|
55 |
|
for(i = 0; i < NUM_REGS; i++) |
|
56 |
|
printf("%04x ", regs[i]); |
|
57 |
|
printf("\n"); |
|
58 |
|
} |
|
59 |
|
|
|
60 |
|
void run () { |
|
61 |
|
while(running) { |
|
62 |
|
showRegs(); |
|
63 |
|
int instruction = fetch(); |
|
64 |
|
decode(instruction); |
|
65 |
|
eval(); |
|
66 |
|
} |
|
67 |
|
} |
|
68 |
|
|
|
69 |
|
void loadBin () { |
|
70 |
|
char filename[] = { 'p', 'r', 'o', 'g', '.', 'd', 'a', 't' }; |
|
71 |
|
FILE* filedes; |
|
72 |
|
|
|
73 |
|
printf("Loading binary..\n"); |
|
74 |
|
|
|
75 |
|
filedes = fopen(filename, "rb"); |
|
76 |
|
|
|
77 |
|
if(filedes == 0) |
|
78 |
|
printf("loading failed :("); |
|
79 |
|
|
|
80 |
|
for (int i = 0; i < sizeof(prog) / sizeof(prog[0]); i++) { |
|
81 |
|
fread(&prog[i], sizeof(ushort), 1, filedes); |
|
82 |
|
printf("%04x\n", prog[i]); |
|
83 |
|
} |
|
84 |
|
fclose(filedes); |
|
85 |
|
printf("Done!\n"); |
|
86 |
|
} |
|
87 |
|
|
|
88 |
|
int main (int argc, const char* argv[]) { |
|
89 |
|
loadBin(); |
|
90 |
|
run(); |
|
91 |
|
return 0; |
|
92 |
|
} |
File README.md added (mode: 100644) (index 0000000..973a88e) |
|
1 |
|
# Bytecode OS |
|
2 |
|
|
|
3 |
|
This Readme is separated in two parts: |
|
4 |
|
|
|
5 |
|
* The Bytecode part, which shows how to write a binary file and parse it with |
|
6 |
|
an executable. |
|
7 |
|
|
|
8 |
|
* The OS part, which shows how to create a bare-bone OS that uses the Bytecode |
|
9 |
|
part. |
|
10 |
|
|
|
11 |
|
If you consider the bare-bone OS as an actual OS, then you could say that the |
|
12 |
|
executable from the bytecode part is basically a virtual machine. |
|
13 |
|
|
|
14 |
|
## The bytecode part |
|
15 |
|
|
|
16 |
|
### Building |
|
17 |
|
|
|
18 |
|
<placeholder> |
|
19 |
|
|
|
20 |
|
### Bytecode reference |
|
21 |
|
|
|
22 |
|
`prog.dat` is an example (binary) file that can be read by the executable. |
|
23 |
|
The reference of the bytecode can be found below: |
|
24 |
|
|
|
25 |
|
``` |
|
26 |
|
#!Virtual Machine |
|
27 |
|
|
|
28 |
|
VM bytecode prog bytecode description |
|
29 |
|
|
|
30 |
|
1064 6410 1 - loadi, 0 - arg0 (register), 64 - value |
|
31 |
|
11c8 c811 1 - loadi, 1 - arg0 (register), c8 - value |
|
32 |
|
2201 0122 2 - add, 2 - arg0 (result register), 0 - arg1 (register 1), 1 - arg2 (register 2) |
|
33 |
|
0000 0000 0000 - halt |
|
34 |
|
``` |
|
35 |
|
|
|
36 |
|
## The OS part |
|
37 |
|
|
|
38 |
|
### Building |
|
39 |
|
|
|
40 |
|
<placeholder> |
File bootloader/main.asm added (mode: 100644) (index 0000000..2edf55f) |
|
1 |
|
; Te compileren met NASM: nasm -f bin -o allersmaboot.bin main.asm |
|
2 |
|
BITS 16 |
|
3 |
|
|
|
4 |
|
start: |
|
5 |
|
; Define Stack Space |
|
6 |
|
mov ax, 07C0h ; De initial location van deze bootloader (ax = 0x7C00 / BITS). |
|
7 |
|
add ax, 20h ; Einde bootloader data (ds). |
|
8 |
|
mov ss, ax ; ss = Stack Space Location. Hier begint de stack. |
|
9 |
|
mov sp, 4096 ; Stack Pointer. Werkt achterstevoren; begint dus bij einde. |
|
10 |
|
|
|
11 |
|
; Define Data Space |
|
12 |
|
mov ax, 07C0h |
|
13 |
|
mov ds, ax ; ds = Data Space Location. Hier begint de data. |
|
14 |
|
|
|
15 |
|
; Print string |
|
16 |
|
mov si, message ; si = Source Index register. |
|
17 |
|
call print |
|
18 |
|
call read |
|
19 |
|
cli ; Disable External interrupts |
|
20 |
|
hlt ; Halt CPU. |
|
21 |
|
|
|
22 |
|
data: |
|
23 |
|
message db 'Bootloader booted.',0 |
|
24 |
|
|
|
25 |
|
read: |
|
26 |
|
mov ah, 0h ; Get char |
|
27 |
|
int 16h ; puts(char) |
|
28 |
|
mov ah, 0Eh;call print ; display(char) |
|
29 |
|
int 10h ; echo char |
|
30 |
|
jmp read ; start over again. |
|
31 |
|
|
|
32 |
|
print: |
|
33 |
|
mov ah, 0Eh |
|
34 |
|
|
|
35 |
|
.printchar: |
|
36 |
|
lodsb ; Load byte from Source Index & increment it. |
|
37 |
|
cmp al, 0 ; Compare al with NULL. |
|
38 |
|
je .done ; if(cmp al, 0) { .done; } |
|
39 |
|
int 10h ; puts(loaded_byte); |
|
40 |
|
jmp .printchar |
|
41 |
|
|
|
42 |
|
.done: |
|
43 |
|
ret |
|
44 |
|
|
|
45 |
|
times 510-($-$$) db 0 ; Fill 510 bytes with this bootloader. |
|
46 |
|
dw 0xAA55 ; Bootloader signature: EOF & Geeft aan dat dit een bootloader is. |