First/main.c

291 lines
6.3 KiB
C

/* main.c
This file is part of the "First" CPU simulator project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include "gui.h"
#include "gui_display.h"
#include "simdata.h"
#include <unistd.h>
#include <errno.h>
#include "assembly.h"
#include "cpu.h"
#include <unistd.h>
#include <string.h>
void help(char* progname){
printf(
"Usage: %s [options] -i < in file > \n"\
"Options:\n"
" -a < out rom file > Assemble in file to out rom file\n"
" -r < framebuffer driver > Use one of the following for writing the framebuffer\n"
#if USE_AALIB==1
" aalib, braille\n"
#else
" braille\n"
#endif
, progname);
}
#define ADDR_SIZE 16777216
int dump_rom(char* filename, struct simdata_t *simdata){
FILE* outfile=fopen(filename,"w");
for(int i=0;i<ADDR_SIZE;i++)
fputc(*(simdata->RAM+i),outfile);
fclose(outfile);
return 0;
}
int main(int argc, char* argd[] ){
/// PARSE COMMAND LINE ///
char *infile = NULL;
char *assemble = NULL;
enum FB_DRIVER_t fb_driver=FB_BRAILLE;
int opt;
while ((opt = getopt(argc, argd, "hi:a:r:")) != -1) {
switch (opt) {
case 'h':
help(argd[0]);
return 0;
break;
case 'i':
infile=optarg;
break;
case 'a':
assemble=optarg;
break;
case 'r':
if(optarg==NULL){
help(argd[0]);
return 1;
}
if(strcmp(optarg,"aalib")==0)
fb_driver=FB_AALIB;
else if(strcmp(optarg,"braille")==0)
fb_driver=FB_BRAILLE;
else{
help(argd[0]);
return 1;
}
break;
default:
help(argd[0]);
return 1;
}
}
#if USE_AALIB==0
if(fb_driver==FB_AALIB){
printf("ERROR:Project wasn't compiled with aalib support.\n");
help(argd[0]);
return 1;
}
#endif
if (infile==NULL){
help(argd[0]);
return 1;
}
/// READ INPUT FILE ///
FILE* rom=fopen(infile,"r");
if(!rom){
printf("Couldn't open input file %s\n",infile);
return 1;
}
struct simdata_t *simdata = init_simdata();
if(!simdata){
printf("Couldn't allocate memory\n");
return 1;
}
if ( assemble != NULL ){
/* RUN ASSEMBLER */
struct assembler_context_t *assembler_context=malloc_assembler_context();
for (int i=0;i<ADDR_SIZE;i++)
simdata->RAM[i]=0;
int linec=0;
if (rom != NULL) {
char line [1000];
int64_t opcode;
uint32_t addr=0;
//--------------- Build assembler context --------------------
while(fgets(line,sizeof(line),rom)!= NULL){
for(int i=0;line[i];i++)
if(line[i]==0x0a)
line[i]=0;
switch(assembler_context_process(line,assembler_context)){
case 0: break;
default:
printf("Error in getting assembler context at %s:%d\n", infile,linec+1);
fclose(rom);
free_assembler_context(assembler_context);
free_simdata(simdata);
return 1;
}
linec++;
}
fseek(rom, 0, SEEK_SET);
linec=0;
//---------------------- Assembler ---------------------------
while(fgets(line,sizeof(line),rom)!= NULL){
for(int i=0;line[i];i++)
if(line[i]==0x0a)
line[i]=0;
opcode=assemble_line(line,assembler_context);
if(opcode<-1){
if(opcode==-3)
printf("Error label not found %s:%d\n", infile,linec+1);
else
printf("Error assembling %s:%d\n", infile,linec+1);
fclose(rom);
free_assembler_context(assembler_context);
free_simdata(simdata);
return 1;
}else if(opcode==-1){
;/*it was empty, comment or label*/
}else{
simdata->RAM[addr]=(0xFF000000&opcode)>>24;
addr++;
simdata->RAM[addr]=(0xFF0000&opcode)>>16;
addr++;
simdata->RAM[addr]=(0xFF00&opcode)>>8;
addr++;
simdata->RAM[addr]=(0xFF&opcode);
addr++;
}
linec++;
}
}
free_assembler_context(assembler_context);
dump_rom(assemble,simdata);
free_simdata(simdata);
}else{
/* RUN SIMULATOR */
if (rom == NULL) {
printf("ERROR: Couldn't open rom file\n");
perror(infile);
fclose(rom);
free_simdata(simdata);
return 1;
}
fseek(rom, 0, SEEK_END);
if(ftell(rom)!=ADDR_SIZE){
printf("ERROR: ROM file isn't 16MiB\n");
fclose(rom);
free_simdata(simdata);
return 1;
}
fseek(rom, 0, SEEK_SET);
if(!simdata){
gui_error("failed to initialise simdata\n");
fclose(rom);
free_simdata(simdata);
return 1;
}
if(fread(simdata->RAM, ADDR_SIZE, 1, rom)==0){
printf("ERROR: failed to read input file\n");
free_simdata(simdata);
fclose(rom);
return 1;
}
fclose(rom);
/// INITIALISE GUI ///
if(start_gui(fb_driver)){
printf("Failed on start_gui()\n");
cpu_simdata_free(simdata);
free_simdata(simdata);
return 1;
}
cpu_simdata_malloc(simdata);
while(1){
update_gui(simdata);
int ret_code;
if((ret_code=gui_continue_request(simdata))){
if(ret_code==2)
break;
end_gui();
printf("Failed on gui_continue_request()\n");
cpu_simdata_free(simdata);
free_simdata(simdata);
return 1;
}
if(simdata->cpu_state==CPU_RUNNING){
int ret;
if((ret=cpu_cycle_clock(simdata))){
cpu_simdata_free(simdata);
free_simdata(simdata);
end_gui();
switch(ret){
case 1:
printf("Failed to execute instruction\n");
break;
case 2:
printf("Failed to decode instruction\n");
break;
case 3:
printf("Failed to fetch instruction\n");
break;
case 4:
printf("Internal simulator error\n");
break;
default:
printf("Unkown CPU failure\n");
}
return 1;
}
}else
usleep(100000);
}
if(end_gui()){
printf("Failed on end_gui()\n");
cpu_simdata_free(simdata);
free_simdata(simdata);
return 1;
}
cpu_simdata_free(simdata);
free_simdata(simdata);
}
return 0;
}