#include "language.h"
#include <dirent.h>
#define PC memory.sys_start[0]
#define SP memory.sys_start[1]
#define RSP memory.sys_start[2]
#define JUMP_OFF memory.sys_start[3]
int stack_frames[256];
int stack_frame_sizes[256];
int stack_frames_index = 0;
//this stores free regions as start, end, size
int heap_list[2048][3];
int heap_length = 1;
double total_time = 0.0;
int number_of_steps = 0;
struct Memory {
short *memory;
short *sys_start;
short *rom_start;
short *stack_start;
short *return_stack_start;
short *heap_start;
};
int find_available_heap(int size)
{
for(int x = 0; x < 2048; x++)
{
if( heap_list[x][2] > size )
{
int found = heap_list[x][0];
heap_list[x][0] = heap_list[x][0] + size;
heap_list[x][2] = heap_list[x][2] - size;
return found;
}
}
}
void free_heap(int start, int size)
{
heap_list[++heap_length][0] = start;
heap_list[heap_length][1] = start + size;
heap_list[heap_length][2] = size;
for(int x = 0; x < heap_length - 1; x++)
{
if((heap_list[x][0] == (heap_list[heap_length][1])))
{
heap_list[x][0] -= size;
heap_list[x][2] += size;
heap_length--;
}
else if(heap_list[x][1] == (heap_list[heap_length][0]))
{
heap_list[x][1] += size;
heap_list[x][2] += size;
heap_length--;
}
}
}
int POP_S(int amount, struct Memory* memory)
{
int data = memory->stack_start[memory->sys_start[1]-1];
memory->sys_start[1] -= amount;
if(memory->sys_start[1] < 0) memory->sys_start[1] = 0;
return data;
}
void Q_POP_S(int amount, struct Memory* memory)
{
memory->sys_start[1] -= amount;
if(memory->sys_start[1] < 0) memory->sys_start[1] = 0;
}
void out_char(int output_format, int output_value)
{
if(output_format == 'I') printf("%i",output_value);
if(output_format == 'C') printf("%c",output_value);
if(output_format == 'X') printf("%x",output_value);
if(output_format == 'B'){
while (output_value){
if (output_value & 1) printf("1");
else printf("0");
output_value >>= 1;
}
}
}
void main(int argc, char *argv[])
{
struct Memory memory;
memory.memory = malloc(256*256*sizeof(short));
memory.sys_start = &memory.memory[0];
memory.rom_start = &memory.memory[255];
memory.stack_start = &memory.memory[256*5-1];
memory.heap_start = &memory.memory[256*6-1];
memory.return_stack_start = &memory.memory[256*6-1];
heap_list[0][0] = 256*7-1;
heap_list[0][1] = 256*256;
heap_list[0][2] = 256*256 - 256*7-1;
stack_frames[0] = RSP + 256*6-1;
PC = 255;
JUMP_OFF = 0;
int requested_number_of_steps = 100000000;
if( argc > 2) requested_number_of_steps = atoi(argv[2]);
if( argc > 3) memory.sys_start[4] = (short) atoi(argv[3]);
if( argc > 4) memory.sys_start[5] = (short) atoi(argv[4]);
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) printf("ROM could not be loaded\n");
fread(memory.rom_start, sizeof(short)*256*4, 1, fp);
fclose(fp);
int running = 1;
while(running){
int redraw = 0;
short datum = memory.memory[PC];
memcpy(memory.stack_start+SP, memory.memory+PC, sizeof(short));
int address;
int output_length, output_address, output_mode, output_format, output_value;
int compare_mode;
short load_value;
switch( datum ){
case LIT: PC++;memory.stack_start[SP] = memory.memory[PC];SP++;break;
case DUP: memory.stack_start[SP] = memory.stack_start[SP - 1];SP++; break;
case POP: Q_POP_S(1, &memory); break;
case FHA:
output_length = POP_S(1, &memory);
output_address = POP_S(1, &memory);
free_heap(output_address, output_length);
break;
case NFH:
output_length = POP_S(1, &memory);
output_address = find_available_heap(output_length);
memory.stack_start[SP] = output_address;
SP++;
break;
case STA: address = POP_S(1, &memory);memory.memory[address] = POP_S(1, &memory); break;
case LFA: address = POP_S(1, &memory);memory.stack_start[SP] = memory.memory[address];SP++;
break;
case JMP: PC = POP_S(1, &memory) - 1 + JUMP_OFF; break;
case JMR:
memory.return_stack_start[++RSP] = PC;
PC = POP_S(1, &memory) - 1 + JUMP_OFF;
stack_frames_index++;
stack_frame_sizes[stack_frames_index] = 1;
stack_frames[stack_frames_index] = RSP + 256*6-1;
break;
case JCC:
RSP -= stack_frame_sizes[stack_frames_index]-1;
PC = memory.return_stack_start[RSP--];
stack_frames_index--;
break;
case JEQ:
if( memory.stack_start[SP-2] == memory.stack_start[SP-3]){
PC = POP_S(3, &memory) - 1 + JUMP_OFF;
}
else Q_POP_S(3, &memory);
break;
case JNE:
if( memory.stack_start[SP-2] != memory.stack_start[SP-3]){
PC = POP_S(3, &memory) - 1 + JUMP_OFF;
}
else Q_POP_S(3, &memory);
break;
case JER:
if( memory.stack_start[SP-2] == memory.stack_start[SP-3]){
memory.return_stack_start[++RSP] = PC;
PC = POP_S(3, &memory) - 1 + JUMP_OFF;
stack_frames_index++;
stack_frame_sizes[stack_frames_index] = 1;
stack_frames[stack_frames_index] = RSP + 256*6-1;
}
else Q_POP_S(3, &memory);
break;
case JNR:
if( memory.stack_start[SP-2] != memory.stack_start[SP-3]){
memory.return_stack_start[++RSP] = PC;
PC = POP_S(3, &memory) - 1 + JUMP_OFF;
stack_frames_index++;
stack_frame_sizes[stack_frames_index] = 1;
stack_frames[stack_frames_index] = RSP + 256*6-1;
}
else Q_POP_S(3, &memory);
break;
case SWP: memory.stack_start[SP] = memory.stack_start[SP-2];memory.stack_start[SP-2] =
memory.stack_
start[SP-1];memory.stack_start[SP-1] = memory.stack_start[SP]; break;
case OVR: memory.stack_start[SP] = memory.stack_start[SP-2];SP++; break;
//case DIV: memory.stack_start[SP-2] = floor(memory.stack_start[SP-2] /
memory.stack_start[SP-1]);Q_
POP_S(1, &memory); break;
case MUL: memory.stack_start[SP-2] = memory.stack_start[SP-2] *
memory.stack_start[SP-1];Q_POP_S(1,
&memory); break;
case SUB: memory.stack_start[SP-2] = memory.stack_start[SP-2] -
memory.stack_start[SP-1];Q_POP_S(1,
&memory); break;
case ADD: memory.stack_start[SP-2] = memory.stack_start[SP-2] +
memory.stack_start[SP-1];Q_POP_S(1,
&memory); break;
case LSL: memory.stack_start[SP-1] = (memory.stack_start[SP-1] << 1) |
(memory.stack_start[SP-1] >>
(15)) & (0x7F >> (15)); break;
case AND:
memory.stack_start[SP-2] = memory.stack_start[SP-2] & memory.stack_start[SP-1];
Q_POP_S(1, &memory);
break;
case LOR: memory.stack_start[SP-2] = memory.stack_start[SP-2] |
memory.stack_start[SP-1];Q_POP_S(1,
&memory); break;
case CMP:
compare_mode = memory.stack_start[SP-1];
switch (compare_mode){
case 0: memory.stack_start[SP-3] = memory.stack_start[SP-3] <
memory.stack_start[SP-2];Q_POP
_S(2, &memory); break;
case 1: memory.stack_start[SP-3] = memory.stack_start[SP-3] >
memory.stack_start[SP-2];Q_POP
_S(2, &memory); break;
case 2: memory.stack_start[SP-3] = memory.stack_start[SP-3] <=
memory.stack_start[SP-2];Q_PO
P_S(2, &memory); break;
case 3: memory.stack_start[SP-3] = memory.stack_start[SP-3] >=
memory.stack_start[SP-2];Q_PO
P_S(2, &memory); break;
case 4: memory.stack_start[SP-3] = memory.stack_start[SP-3] ==
memory.stack_start[SP-2];Q_PO
P_S(2, &memory); break;
case 5: memory.stack_start[SP-3] = memory.stack_start[SP-3] !=
memory.stack_start[SP-2];Q_PO
P_S(2, &memory); break;
case 6: memory.stack_start[SP-2] = memory.stack_start[SP-2] > 0;Q_POP_S(1, &memory);
break;
case 7: memory.stack_start[SP-2] = memory.stack_start[SP-2] < 0;Q_POP_S(1, &memory);
break;
}
break;
case OUT:
output_format = POP_S(1, &memory);
output_length = POP_S(1, &memory);
output_mode = POP_S(1, &memory);
if(output_mode == 0) output_address = POP_S(1, &memory);
if(output_length == ((short)555)) output_length = 60000;
for(int x=0; x < output_length; x++){
if(output_mode == 0){
output_value = memory.memory[output_address+x];
out_char(output_format,output_value);
}
else{
memory.memory[5000-x] = memory.stack_start[SP-1];
output_value = POP_S(1, &memory);
}
if((output_value == 0) && (output_length == 60000)){
output_length = x;
break;
}
}
if(output_mode == 1){
for(int x=1; x <= output_length; x++){
out_char(output_format, memory.memory[5000-output_length+x]);
}
}
break;
case LFR:
load_value = stack_frames[stack_frames_index]+POP_S(1, &memory);
memory.stack_start[SP++] = load_value;
break;
case PRS:
memory.return_stack_start[++RSP] = POP_S(1, &memory);
stack_frame_sizes[stack_frames_index]++;
break;
case STV:
output_length = POP_S(1, &memory);
output_address = POP_S(1, &memory);
for(int x=1; x < output_length; x++){
memory.memory[output_address+output_length-x-1] = POP_S(1, &memory);
}
memory.memory[output_address+output_length-1] = POP_S(1, &memory);
break;
case STZ:
output_length = POP_S(1, &memory);
output_address = POP_S(1, &memory);
for(int x=0; x < output_length; x++){
memory.memory[output_address+x] = 0;
}
break;
case RIN:
output_length = POP_S(1, &memory);
output_address = POP_S(1, &memory);
char format[24];
sprintf(format, " %%n%%%i[^\n]%%n", output_length);
int n1, n2;
char test[255];
scanf(format, &n1, &test, &n2);
memory.memory[16] = (short)n2-n1;
for(int x=0; x < n2-n1; x++){
memory.memory[output_address+x] = (short)test[x];
}
break;
case END: running = 0; break;
default: break;
}
if( memory.sys_start[48] > 0 ){
char path[255];
short path_address = memory.sys_start[49];
short path_len = memory.sys_start[50];
short result_address = memory.sys_start[51];
short request_options = memory.sys_start[52];
if((request_options & ((short)-32768)) == ((short)-32768));//local path
for(int p = 0; p < path_len; p++){
printf("%c",memory.memory[path_address+p]);
path[p] = memory.memory[path_address+p];
}
printf("\n");
path[path_len] = '\0';
short last_len = 0;
if((request_options & ((short)2048)) == ((short)2048)){
//list
struct dirent *directory;
DIR *dr = opendir(path);
if (dr == NULL){
memory.sys_start[48] = 0;
printf("Could not open current directory\n");
break;
}
while ((directory = readdir(dr)) != NULL){
short p[255];
for(int i=0;i<strlen(directory->d_name);i++){
p[i] = directory->d_name[i];
}
p[strlen(directory->d_name)] = 10;
memcpy(&memory.memory[result_address + last_len], p, 2*strlen(directory->d_name)+1);
last_len += strlen(directory->d_name)+1;
}
memory.memory[result_address + last_len] = 3;
memory.sys_start[53] = last_len;
closedir(dr);
}
if((request_options & ((short)16384)) == ((short)16384)){
//read
FILE *file_fp = fopen(path, "r");
if (file_fp == NULL) printf("ROM could not be loaded\n");
fread(&memory.memory[result_address], sizeof(short)*256*4, 1, file_fp);
memory.sys_start[53] = 256;
fclose(file_fp);
}
if((request_options & ((short)8192)) == ((short)8192));//write
if((request_options & ((short)4096)) == ((short)4096));//execute
memory.sys_start[48] = 0;
}
PC++;
number_of_steps++;
if (number_of_steps >= requested_number_of_steps){
int scanned = 0;
while(scanned != 1){
scanf("%d", &scanned);
if(scanned == 2){
printf("SYS:\n");
for(int x = 0; x < 255*6; x++){
if(x%30==0) printf("\n");
printf(" %04x", memory.sys_start[x]);
}
printf("\n");
}
}
}
}
}