/* 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 . */ #include "config.h" #include #include #include "gui.h" #include "gui_display.h" #include "simdata.h" #include #include #include "assembly.h" #include "cpu.h" #include #include 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" #ifdef USE_AALIB " 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;iRAM+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; } } #ifndef USE_AALIB 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;iRAM[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; }