Ниже приведена реализация своего рода виртуальной машины, и хотя она работает методом одной команды за раз, занимая все 4 цикла (выборка, декодирование, выполнение, сохранение), а затем переходя к следующей команде. Что я пытаюсь выяснить, если это возможно, и если да, то как я могу отредактировать свою программу, чтобы я мог выполнять несколько команд параллельно? Под этим я подразумеваю, что команда 1 проходит через Fetch и переходит к декодированию, а команда декодирования 1, команда 2 проходит через Fetch. Сначала я хотел использовать два логических значения и два массива команд fetchresult / current. Однако я понимаю, что это можно сделать с помощью двойной буферизации, но тогда, когда одновременно запускаются несколько команд, необходимо также считать риск записи в текущий момент в регистр или наоборот, так что переадресация регистра будет необходимо. Может ли кто-нибудь дать мне пример того, как это можно сделать, и если это вообще возможно сделать в этом типе виртуальной машины?
VM. c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#define MAXMEM 1024
#define NUM_REGS 16
int regs[ NUM_REGS];
uint8_t memory[MAXMEM];
uint8_t fetchresult[5];
//globals to be used throughout processing
bool Call = false;
int pc = 0;
int opcode = 0;
int reg1 = 0;
int reg2 = 0;
int reg3 = 0;
int imm = 0;
int br1 = 0;
int br2 = 0;
int stack_op = 0;
int stack_op2 = 0;
int br_op = 0;
uint8_t callnxt = 0;
int sp = -1;
int stored = 0;
void showRegs();
void printStack();
size_t loads (char *filename)
{
FILE *file = fopen(filename, "rb");
if(!file) {
perror("Failed to read file");
exit( EXIT_FAILURE);
}
fseek(file, 0, SEEK_END);
int filesize = ftell(file);
//printf("filesize is %d\n", filesize);
sp = filesize;
rewind(file);
return fread(memory, sizeof(memory), filesize, file);
}
void fetch(){
//printf("%02x\n", memory[pc]);
fetchresult[0] = memory[pc];
fetchresult[1] = memory[pc+1];
fetchresult[2] = memory[pc+2];
fetchresult[3] = memory[pc+3];
fetchresult[4] = memory[pc+4];
pc+=2;
}
int running = 1; // shows vm is running until flag is 0
void decode () {
opcode = (fetchresult[0]) >> 4;
//printf("opcode is %d\n", opcode);
reg1 = (fetchresult[0])&0xf;
//printf("reg1 is %d\n", reg1);
reg2 = (fetchresult[1]) >> 4;
//printf("reg2 is %d\n", reg2);
reg3 = (fetchresult[1])&0xf;
//printf("reg3 is %d\n", reg3);
imm = (fetchresult[1] & 0xFF);
//printf("immediate value is %d\n", imm);
br1 = (fetchresult[2] << 8 | fetchresult[3]);
//printf("br1 value is %d\n", br1);
br2 = (fetchresult[1] << 16 | br1);
//printf("br2 value is %d\n", br2);
stack_op = fetchresult[1] >> 4;
//printf("stack_op value is %d\n", stack_op);
stack_op2 = fetchresult[1] & 0xf;
//printf("stack_op2 value is %d\n", stack_op2);
br_op = (fetchresult[0] &0xf);
//printf("br_op value is %d\n", br_op);
callnxt = (fetchresult[4]);
//printf("Callnxt is %02x\n", callnxt);
}
void eval() {
switch (opcode)
{
case 0:
printf("halt\n");
running = 0;
break;
case 11:
printf("Move r%d with value of %d\n", reg1, imm);
regs[reg1] += imm;
break;
case 1:
printf("add r%d r%d r%d\n", reg1, reg2, reg3);
regs[reg3] += regs[reg1] + regs[reg2];
break;
case 2:
printf("and r%d r%d r%d\n", reg1, reg2, reg3);
regs[reg3] = regs[reg1] & regs[reg2];
break;
case 3:
printf("divide r%d r%d r%d\n", reg1, reg2, reg3);
regs[reg3] = regs[reg1] / regs[reg2];
break;
case 4:
printf("multiply r%d r%d r%d\n", reg1, reg2, reg3);
regs[reg3] = regs[reg1] * regs[reg2];
break;
case 5:
printf("subtract r%d r%d r%d\n", reg1, reg2, reg3);
regs[reg3] = regs[reg1] - regs[reg2];
break;
case 6:
printf("or r%d r%d r%d\n", reg1, reg2, reg3);
regs[reg3] = regs[reg1] | regs[reg2];
break;
case 7:
switch(br_op)
{
case 0: // branchifless
if(regs[reg2] < regs[reg3]){
pc += 2*br1;
}
break;
case 1: //branch if less or equal
if(regs[reg2] <= regs[reg3]){
pc += 2*br1;
}
break;
case 2: // branch if equal
if(regs[reg2] == regs[reg3]){
pc += 2*br1;
}
break;
case 3: // branch if not equal
if(regs[reg2] != regs[reg3]){
pc += 2*br1;
}
break;
case 4: // branch if greater then
if(regs[reg2] > regs[reg3]){
pc += 2*br1;
}
break;
case 5: // branch if greater than or equal
if(regs[reg2] >= regs[reg3]){
pc += 2*br2;
}
break;
case 6: // call & return
printf("Call %d\n", br2);
regs[15] = pc + 2;
//printf("Reg 15 is %02x\n", regs[15]);
Call = true;
pc += 2*br2;
break;
case 7: // jump X
printf("Jump %d\n", br1);
pc += 2*br2;
}
break;
case 8: // load
//printf("sp is at start of load %d\n", sp);
sp;
int loaded = sp + (regs[reg3] + (imm * 2));
//printf("Loaded is %d\n", loaded);
regs[reg1] = memory[loaded];
printf("Loaded value in r%d is %d\n", reg1, regs[reg1]);
break;
case 9: // store
sp += sp++;
stored = sp + (regs[reg3] + (imm * 2));
//printf("Stored is %d\n", stored);
//sp += stored;
//printf("sp after add with stored is %d\n", sp);
//printf("sp is %d\n", sp);
memory[stored] = regs[reg1];
printf("Stored value is %d\n", memory[stored]);
break;
case 10: // pop/push/return
switch(stack_op){
case 0:
switch(stack_op2){
case 0:// return
printf("Return to instruction following call\n");
pc = regs[15];
break;
case 1:// push
sp = sp - 4;
memory[sp] = regs[reg1];
printf("Pushing value of %d to stack\n", regs[reg1]);
break;
}
break;
case 1: // pop
regs[reg1] = memory[sp];
printf("popping value of %d from stack into r%d\n", memory[sp], regs[reg1]-1);
sp = sp + 4;
break;
}
break;
case 12: // interrupt
switch(br_op){
case 0:
printf("Interrupt 0, showing registers\n");
showRegs();
exit(0);
break;
case 1:
printf("Interrupt 1, showing memory\n");
printStack();
exit(0);
break;
}
break;
}
}
void showRegs() {
int i;
for (i=0; i< NUM_REGS; i++){
printf("register %d is %d", i, regs[i] );
printf("\n");
}
}
void printStack() {
//printf("Values in memory? %d\n", memory[sp]);
for(int i = 0; i < MAXMEM; i++) {
printf("0x%02x ", memory[i]);
if((i + 1) %4 == 0) {
printf("\n");
}
}
if(sp != 0) {
printf("\n");
}
}
void run(){
while(running){
fetch();
decode();
eval();
}
//showRegs();
}
int main(int argc, char **argv) {
if(argc <= 1){
printf("No File Found\n");
return -1;
}
char *filename = argv[1];
loads(filename);
run();
}