65/rom.c
2020-02-03 15:10:29 -06:00

124 lines
3.3 KiB
C

#include"65.h"
#include"rom.h"
#include"ram.h"
// Load ROM into host machine memory
// To be mapped into 6502 RAM later
void rom_load_file(rom_t*rom,const char*filepath)
{
// Open specified file
rom->filepath=filepath;
int fd=open(filepath,O_RDONLY);
size_t len=0;
if(fd<0)
{
puterr("%s: Failed to load ROM file \"%s\"\n",__func__,filepath);
return;
}
// Determine ROM size
len=lseek(fd,0,SEEK_END);
if(len<=16)
{
puterr("%s: ROM size was less than 16 bytes\n",__func__);
return;
}
len-=16;
rom->data_len=len;
// Allocate memory for ROM data
rom->rom=malloc(len);
if(!rom->rom)
{
puterr("%s: Error allocating ROM memory for file data (\"%s\")\n",__func__,filepath);
return;
}
// Read ROM data into rom_t struct
lseek(fd,0,SEEK_SET);
read(fd,rom->header,16); // iNes header
// Verify valid NES header
if(strncmp("NES",rom->header,3)!=0)
{
puterr("%s: \"%s\" is not a valid NES file\n",__func__,filepath);
return;
}
// Read trainer section of iNes file if it exists
if(rom->header[6]&0x3) // .nes file contains trainer section
{
read(fd,rom->trainer,512);
//printw("has trainer!");
}
//lseek(fd,16,SEEK_SET);
//printw("data_len: %d\n",rom->data_len);
read(fd,rom->rom,len); // ROM data
//printw("success reading rom \"%s\" (%u B)\n",filepath,len);
close(fd);
}
void rom_print_header_info(rom_t*rom)
{
attron(COLOR_PAIR(3));
printw("ROM info:\n");
printw("Reading ROM file \"%s\"\n",rom->filepath);
printw("ROM banks (16k): %u\n",rom->header[4]);
printw("VROM banks (8k): %u\n",rom->header[5]);
printw("Vertical mirroring: %s\n",rom->header[6]&0x01?"true":"false");
printw("Battery-backed RAM at $6000-$7FFF: %s\n",rom->header[6]&0x01?"true":"false");
printw("Contains trainer section: %s\n",rom->header[6]&0x03?"true":"false");
printw("Four-screen VRAM: %s\n",rom->header[6]&0x04?"true":"false");
printw("VS System cartridge: %s\n",rom->header[7]&0x01?"true":"false");
printw("ROM Mapper type: %u\n",rom->header[6]&0xf0|rom->header[7]&0x0f);
printw("RAM banks (8k): %u (if 0, counted as 1)\n",rom->header[8]);
printw("Cartridge: %s\n",(rom->header[9]&0x1)==1?"PAL":"NTSC");
printw("Rom data length: %d\n",rom->data_len);
attron(COLOR_PAIR(1));
printw("_______________\n");
}
// Map ROM information into CPU RAM for fetch-decode-execute
// offset used to determine where in RAM said ROM data will be mapped
void rom_map(rom_t*rom,ram_t*ram,size_t offset)
{
if(!rom || !rom->rom)
{
puterr("%s: Attempting to map NULL ROM data into RAM memory\n",__func__);
return;
}
if(!ram || !ram->ram)
{
puterr("%s: Attempting to map ROM data into NULL RAM memory\n",__func__);
return;
}
// Copy rom data into ram memory
// Put NES file header parsing here <---
//printw("copying %u bytes into RAM from ROM\n",rom->data_len);
// NOTE: Substitution of copying entire data_len with copying
// a smaller 'chunk' at a time was necessary on ArchLinux to prevent
// SIGSEGV crashing the program
const size_t DATA_CHUNK=2048;
for(size_t len=rom->data_len;len>0;len-=(len>DATA_CHUNK)?DATA_CHUNK:len)
memmove(ram->ram+offset,rom->rom,(len>DATA_CHUNK)?DATA_CHUNK:len);
//memmove(ram->ram,rom->rom,rom->data_len);
}
// Free memory allocated to ROM object
void rom_del(rom_t*rom)
{
if(!rom->rom)
{
puterr("%s: Attempting to free NULL memory\n",__func__);
return;
}
free(rom->rom);
}