218 lines
4.6 KiB
C
218 lines
4.6 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "gui.h"
|
|
#include "simdata.h"
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include "assembly.h"
|
|
#include "cpu.h"
|
|
#include <unistd.h>
|
|
|
|
void help(char* progname){
|
|
printf("Usage: %s -i <file> \n", 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;
|
|
int opt;
|
|
while ((opt = getopt(argc, argd, "hi:a:")) != -1) {
|
|
switch (opt) {
|
|
case 'h':
|
|
help(argd[0]);
|
|
return 0;
|
|
break;
|
|
case 'i':
|
|
infile=optarg;
|
|
break;
|
|
case 'a':
|
|
assemble=optarg;
|
|
break;
|
|
default:
|
|
help(argd[0]);
|
|
return 1;
|
|
break;
|
|
}
|
|
}
|
|
if (infile==NULL){
|
|
help(argd[0]);
|
|
return 1;
|
|
}
|
|
|
|
/// READ INPUT FILE ///
|
|
FILE* rom=fopen(infile,"r");
|
|
|
|
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(sizeof(struct assembler_context_t));
|
|
|
|
for (int i=0;i<ADDR_SIZE;i++)
|
|
simdata->RAM[i]=0;
|
|
int linec=0;
|
|
if (rom != NULL) {
|
|
char line [1000];
|
|
uint32_t opcode;
|
|
uint32_t addr=0;
|
|
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>0xFFFFFFF1){
|
|
printf("Error assembling %s:%d\n", infile,linec+1);
|
|
fclose(rom);
|
|
free_assembler_context(assembler_context);
|
|
free_simdata(simdata);
|
|
return 1;
|
|
}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()){
|
|
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;
|
|
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;
|
|
}
|