Files
pcem/src/mem.c
2013-04-21 14:54:35 +01:00

1359 lines
47 KiB
C

/*MESS ROM notes :
- pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM)
- pc2386 video BIOS is underdumped (16k instead of 24k)
- c386sx16 BIOS fails checksum
*/
#include <stdlib.h>
#include <string.h>
#include "ibm.h"
#include "mem.h"
#include "video.h"
#include "x86.h"
#include "cpu.h"
static uint8_t (*_mem_read_b[0x20000])(uint32_t addr);
static uint16_t (*_mem_read_w[0x20000])(uint32_t addr);
static uint32_t (*_mem_read_l[0x20000])(uint32_t addr);
static void (*_mem_write_b[0x20000])(uint32_t addr, uint8_t val);
static void (*_mem_write_w[0x20000])(uint32_t addr, uint16_t val);
static void (*_mem_write_l[0x20000])(uint32_t addr, uint32_t val);
int shadowbios,shadowbios_write;
uint32_t oldpc;
extern uint8_t opcode2;
unsigned char isram[0x10000];
extern int ins;
extern int timetolive;
int mem_size;
int cache=4;
uint32_t biosmask;
int readlnum=0,writelnum=0;
int cachesize=256;
uint8_t *ram,*rom,*vram,*vrom;
uint8_t romext[32768];
FILE *romfopen(char *fn, char *mode)
{
char s[512];
pclog("romfopen %s\n", fn);
strcpy(s,pcempath);
pclog("s = %s\n", s);
put_backslash(s);
pclog("s = %s\n", s);
pclog("strcat %s %s\n", s, fn);
strcat(s,fn);
pclog("s = %s\n", s);
return fopen(s,mode);
}
static void mem_load_xtide_bios()
{
FILE *f;
f=romfopen("roms/ide_xt.bin","rb");
// is486=0;
if (f)
{
fread(romext,16384,1,f);
fclose(f);
}
}
static void mem_load_atide_bios()
{
FILE *f;
f=romfopen("roms/ide_at.bin","rb");
// is486=0;
if (f)
{
fread(romext,16384,1,f);
fclose(f);
}
}
int loadbios()
{
FILE *f=NULL,*ff=NULL;
int c;
loadfont("mda.rom", 0);
memset(vrom,0x63,0x8000);
// printf("Loadrom - VGA %i\n",VGA);
if (VID_EGA)
{
f=romfopen("roms/ibm_6277356_ega_card_u44_27128.bin","rb");
if (f)
{
pclog("Read EGA ROM!\n");
fread(vrom,16384,1,f);
if (vrom[0x3FFE]==0xAA && vrom[0x3FFF]==0x55)
{
pclog("Read EGA ROM in reverse\n");
fseek(f,0,SEEK_SET);
for (c=0x3FFF;c>=0;c--)
vrom[c]=getc(f);
}
fclose(f);
}
}
if (VGA)
{
f=romfopen("roms/trident.bin","rb");
if (f)
{
fread(vrom,32768,1,f);
fclose(f);
}
}
if (ET4000)
{
f=romfopen("roms/et4000.bin","rb");
if (f)
{
fread(vrom,32768,1,f);
fclose(f);
}
}
if (ET4000W32)
{
f=romfopen("roms/et4000w32.bin","rb");
if (f)
{
fread(vrom,32768,1,f);
fclose(f);
}
}
if (gfxcard == GFX_BAHAMAS64)
{
f=romfopen("roms/bahamas64.bin","rb");
if (f)
{
fread(vrom,32768,1,f);
fclose(f);
}
}
if (gfxcard == GFX_N9_9FX)
{
f=romfopen("roms/s3_764.bin","rb");
if (f)
{
fread(vrom,32768,1,f);
fclose(f);
}
}
if (gfxcard == GFX_STEALTH64)
{
f=romfopen("roms/TRIO64 (Ver. 1.5-07) [VGA] (S3 Incorporated).bin","rb");
if (f)
{
fread(vrom,32768,1,f);
fclose(f);
}
}
memset(romext,0x63,0x8000);
biosmask = 0xffff;
pclog("Starting with romset %i\n", romset);
switch (romset)
{
case ROM_PC1512:
f=romfopen("roms/pc1512/40043.v1","rb");
ff=romfopen("roms/pc1512/40044.v1","rb");
if (!f || !ff) break;
for (c=0xC000;c<0x10000;c+=2)
{
rom[c]=getc(f);
rom[c+1]=getc(ff);
}
fclose(ff);
fclose(f);
memset(vrom,0x63,0x8000);
mem_load_xtide_bios();
loadfont("roms/pc1512/40078.ic127", 2);
return 1;
case ROM_PC1640:
f=romfopen("roms/pc1640/40044.v3","rb");
ff=romfopen("roms/pc1640/40043.v3","rb");
if (!f || !ff) break;
for (c=0xC000;c<0x10000;c+=2)
{
rom[c]=getc(f);
rom[c+1]=getc(ff);
}
fclose(ff);
fclose(f);
f=romfopen("roms/pc1640/40100","rb");
if (!f) break;
fread(vrom,0x8000,1,f);
fclose(f);
mem_load_xtide_bios();
return 1;
case ROM_PC200:
f=romfopen("roms/pc200/pc20v2.1","rb");
ff=romfopen("roms/pc200/pc20v2.0","rb");
if (!f || !ff) break;
for (c=0xC000;c<0x10000;c+=2)
{
rom[c]=getc(f);
rom[c+1]=getc(ff);
}
fclose(ff);
fclose(f);
memset(vrom,0x63,0x8000);
mem_load_xtide_bios();
loadfont("roms/pc200/40109.bin", 1);
return 1;
case ROM_TANDY:
f=romfopen("roms/tandy/tandy1t1.020","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
memset(vrom,0x63,0x8000);
mem_load_xtide_bios();
return 1;
/* case ROM_IBMPCJR:
f=fopen("pcjr/bios.rom","rb");
fread(rom+0xE000,8192,1,f);
fclose(f);
f=fopen("pcjr/basic.rom","rb");
fread(rom+0x6000,32768,1,f);
fclose(f);
break;*/
case ROM_IBMXT:
f=romfopen("roms/ibmxt/xt.rom","rb");
if (!f)
{
f=romfopen("roms/ibmxt/xt050986.0","rb");
ff=romfopen("roms/ibmxt/xt050986.1","rb");
if (!f || !ff) break;
for (c=0x0000;c<0x10000;c+=2)
{
rom[c]=getc(f);
rom[c+1]=getc(ff);
}
fclose(ff);
fclose(f);
mem_load_xtide_bios();
return 1;
}
else
{
fread(rom,65536,1,f);
fclose(f);
mem_load_xtide_bios();
return 1;
}
break;
case ROM_GENXT:
f=romfopen("roms/genxt/pcxt.rom","rb");
if (!f) break;
fread(rom+0xE000,8192,1,f);
fclose(f);
mem_load_xtide_bios();
return 1;
case ROM_DTKXT:
f=romfopen("roms/dtk/DTK_ERSO_2.42_2764.bin","rb");
if (!f) break;
fread(rom+0xE000,8192,1,f);
fclose(f);
mem_load_xtide_bios();
return 1;
case ROM_OLIM24:
f = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_low.bin" ,"rb");
ff = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_high.bin","rb");
if (!f || !ff) break;
for (c = 0x0000; c < 0x4000; c += 2)
{
rom[c + 0xc000] = getc(f);
rom[c + 0xc001] = getc(ff);
}
fclose(ff);
fclose(f);
mem_load_xtide_bios();
return 1;
case ROM_PC2086:
f = romfopen("roms/pc2086/40179.ic129" ,"rb");
ff = romfopen("roms/pc2086/40180.ic132","rb");
if (!f || !ff) break;
pclog("Loading BIOS\n");
for (c = 0x0000; c < 0x4000; c += 2)
{
rom[c + 0x0000] = getc(f);
rom[c + 0x0001] = getc(ff);
}
pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]);
fclose(ff);
fclose(f);
f = romfopen("roms/pc2086/40186.ic171", "rb");
if (!f) break;
pclog("Loading VBIOS\n");
fread(vrom, 32768, 1, f);
fclose(f);
mem_load_xtide_bios();
pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]);
biosmask = 0x3fff;
return 1;
case ROM_PC3086:
f = romfopen("roms/pc3086/fc00.bin" ,"rb");
if (!f) break;
fread(rom, 0x4000, 1, f);
fclose(f);
f = romfopen("roms/pc3086/c000.bin", "rb");
if (!f) break;
pclog("Loading VBIOS\n");
fread(vrom, 32768, 1, f);
fclose(f);
mem_load_xtide_bios();
pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]);
biosmask = 0x3fff;
return 1;
case ROM_IBMAT:
/* f=romfopen("roms/AMIC206.BIN","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
return 1;*/
case ROM_IBMAT386:
f=romfopen("roms/ibmat/at111585.0","rb");
ff=romfopen("roms/ibmat/at111585.1","rb");
if (!f || !ff) break;
for (c=0x0000;c<0x10000;c+=2)
{
rom[c]=getc(f);
rom[c+1]=getc(ff);
}
fclose(ff);
fclose(f);
mem_load_atide_bios();
return 1;
case ROM_CMDPC30:
f = romfopen("roms/cmdpc30/commodore pc 30 iii even.bin", "rb");
ff = romfopen("roms/cmdpc30/commodore pc 30 iii odd.bin", "rb");
if (!f || !ff) break;
for (c = 0x0000; c < 0x8000; c += 2)
{
rom[c] = getc(f);
rom[c + 1] = getc(ff);
}
fclose(ff);
fclose(f);
biosmask = 0x7fff;
mem_load_atide_bios();
return 1;
case ROM_DELL200:
f=romfopen("roms/dells200/dell0.bin","rb");
ff=romfopen("roms/dells200/dell1.bin","rb");
if (!f || !ff) break;
for (c=0x0000;c<0x10000;c+=2)
{
rom[c]=getc(f);
rom[c+1]=getc(ff);
}
fclose(ff);
fclose(f);
return 1;
/* case ROM_IBMAT386:
f=romfopen("roms/at386/at386.bin","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
return 1;*/
case ROM_AMI386: /*This uses the OPTi 82C495 chipset*/
// f=romfopen("roms/at386/at386.bin","rb");
f=romfopen("roms/ami386/ami386.bin","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
return 1;
case ROM_ACER386:
f=romfopen("roms/acer386/acer386.bin","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
rom[0xB0]=0xB0-0x51;
rom[0x40d4]=0x51; /*PUSH CX*/
f=romfopen("roms/acer386/oti067.bin","rb");
if (!f) break;
fread(vrom,0x8000,1,f);
fclose(f);
vrom[0x5D]=0x74;
return 1;
case ROM_AMI286:
f=romfopen("roms/ami286/amic206.bin","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
// memset(romext,0x63,0x8000);
return 1;
case ROM_EUROPC:
// return 0;
f=romfopen("roms/europc/50145","rb");
if (!f) break;
fread(rom+0x8000,32768,1,f);
fclose(f);
// memset(romext,0x63,0x8000);
return 1;
case ROM_IBMPC:
f=romfopen("roms/ibmpc/pc102782.bin","rb");
if (!f) break;
// f=fopen("pc081682.bin","rb");
fread(rom+0xE000,8192,1,f);
fclose(f);
f=romfopen("roms/ibmpc/basicc11.f6","rb");
if (!f) return 1; /*I don't really care if BASIC is there or not*/
fread(rom+0x6000,8192,1,f);
fclose(f);
f=romfopen("roms/ibmpc/basicc11.f8","rb");
if (!f) break; /*But if some of it is there, then all of it must be*/
fread(rom+0x8000,8192,1,f);
fclose(f);
f=romfopen("roms/ibmpc/basicc11.fa","rb");
if (!f) break;
fread(rom+0xA000,8192,1,f);
fclose(f);
f=romfopen("roms/ibmpc/basicc11.fc","rb");
if (!f) break;
fread(rom+0xC000,8192,1,f);
fclose(f);
mem_load_xtide_bios();
return 1;
case ROM_MEGAPC:
pclog("Loading MegaPC\n");
f = romfopen("roms/megapc/41651-bios lo.u18", "rb");
ff = romfopen("roms/megapc/211253-bios hi.u19", "rb");
if (!f || !ff) break;
for (c = 0x0000; c < 0x8000; c+=2)
{
vrom[c]=getc(f);
vrom[c+1]=getc(ff);
}
fseek(f, 0x8000, SEEK_SET);
fseek(ff, 0x8000, SEEK_SET);
for (c = 0x0000; c < 0x10000; c+=2)
{
rom[c]=getc(f);
rom[c+1]=getc(ff);
}
fclose(ff);
fclose(f);
return 1;
case ROM_AMI486:
f=romfopen("roms/ami486/ami486.BIN","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
//is486=1;
return 1;
case ROM_WIN486:
// f=romfopen("roms/win486/win486.bin","rb");
f=romfopen("roms/win486/ALI1429G.AMW","rb");
if (!f) break;
fread(rom,65536,1,f);
fclose(f);
//is486=1;
return 1;
case ROM_PCI486:
f=romfopen("roms/hot-433/hot-433.ami","rb");
if (!f) break;
fread(rom, 0x20000, 1, f);
fclose(f);
biosmask = 0x1ffff;
//is486=1;
return 1;
}
printf("Failed to load ROM!\n");
if (f) fclose(f);
if (ff) fclose(ff);
return 0;
}
uint32_t mmucache[0x100000];
int mmucaches[64];
int mmunext=0;
int abrt=0;
void initmmucache()
{
int c;
// if (output) pclog("initmmucache\n");
memset(mmucache,0xFF,sizeof(mmucache));
for (c=0;c<64;c++) mmucaches[c]=0xFFFFFFFF;
mmunext=0;
}
void resetreadlookup()
{
int c;
// /*if (output) */pclog("resetreadlookup\n");
memset(readlookup2,0xFF,1024*1024*4);
for (c=0;c<256;c++) readlookup[c]=0xFFFFFFFF;
readlnext=0;
memset(writelookup2,0xFF,1024*1024*4);
for (c=0;c<256;c++) writelookup[c]=0xFFFFFFFF;
writelnext=0;
pccache=0xFFFFFFFF;
// readlnum=writelnum=0;
}
int mmuflush=0;
int mmu_perm=4;
void flushmmucache()
{
int c;
// /*if (output) */pclog("flushmmucache\n");
/* for (c=0;c<16;c++)
{
if ( readlookup2[0xE0+c]!=0xFFFFFFFF) pclog("RL2 %02X = %08X\n",0xE0+c, readlookup2[0xE0+c]);
if (writelookup2[0xE0+c]!=0xFFFFFFFF) pclog("WL2 %02X = %08X\n",0xE0+c,writelookup2[0xE0+c]);
}*/
for (c=0;c<256;c++)
{
if (readlookup[c]!=0xFFFFFFFF)
{
readlookup2[readlookup[c]]=0xFFFFFFFF;
readlookup[c]=0xFFFFFFFF;
}
if (writelookup[c]!=0xFFFFFFFF)
{
writelookup2[writelookup[c]]=0xFFFFFFFF;
writelookup[c]=0xFFFFFFFF;
}
}
mmuflush++;
// readlnum=writelnum=0;
pccache=(uint32_t)0xFFFFFFFF;
pccache2=(uint8_t *)0xFFFFFFFF;
// memset(readlookup,0xFF,sizeof(readlookup));
// memset(readlookup2,0xFF,1024*1024*4);
// memset(writelookup,0xFF,sizeof(writelookup));
// memset(writelookup2,0xFF,1024*1024*4);
/* if (!(cr0>>31)) return;*/
for (c=0;c<64;c++)
{
if (mmucaches[c]!=0xFFFFFFFF)
{
mmucache[mmucaches[c]]=0xFFFFFFFF;
mmucaches[c]=0xFFFFFFFF;
}
}
// pclog("Flush MMU cache\n");
/* for (c = 0; c < 1024*1024; c++)
{
if (readlookup2[c] != 0xFFFFFFFF)
{
pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]);
dumpregs();
exit(-1);
}
if (writelookup2[c] != 0xFFFFFFFF)
{
pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]);
dumpregs();
exit(-1);
}
}*/
}
void flushmmucache_nopc()
{
int c;
for (c=0;c<256;c++)
{
if (readlookup[c]!=0xFFFFFFFF)
{
readlookup2[readlookup[c]]=0xFFFFFFFF;
readlookup[c]=0xFFFFFFFF;
}
if (writelookup[c]!=0xFFFFFFFF)
{
writelookup2[writelookup[c]]=0xFFFFFFFF;
writelookup[c]=0xFFFFFFFF;
}
}
mmuflush++;
for (c=0;c<64;c++)
{
if (mmucaches[c]!=0xFFFFFFFF)
{
mmucache[mmucaches[c]]=0xFFFFFFFF;
mmucaches[c]=0xFFFFFFFF;
}
}
}
void flushmmucache_cr3()
{
int c;
// /*if (output) */pclog("flushmmucache_cr3\n");
for (c=0;c<256;c++)
{
if (readlookup[c]!=0xFFFFFFFF)// && !readlookupp[c])
{
readlookup2[readlookup[c]]=0xFFFFFFFF;
readlookup[c]=0xFFFFFFFF;
}
if (writelookup[c]!=0xFFFFFFFF)// && !writelookupp[c])
{
writelookup2[writelookup[c]]=0xFFFFFFFF;
writelookup[c]=0xFFFFFFFF;
}
}
for (c=0;c<64;c++)
{
if (mmucaches[c]!=0xFFFFFFFF)
{
mmucache[mmucaches[c]]=0xFFFFFFFF;
mmucaches[c]=0xFFFFFFFF;
}
}
/* for (c = 0; c < 1024*1024; c++)
{
if (readlookup2[c] != 0xFFFFFFFF)
{
pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]);
dumpregs();
exit(-1);
}
if (writelookup2[c] != 0xFFFFFFFF)
{
pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]);
dumpregs();
exit(-1);
}
}*/
}
extern int output;
#define mmutranslate(addr,rw) mmutranslatereal(addr,rw)
//#define mmutranslate(addr,rw) ((mmucache[addr>>12]!=0xFFFFFFFF)?(mmucache[addr>>12]+(addr&0xFFF)):mmutranslatereal(addr,rw))
int pctrans=0;
extern uint32_t testr[9];
uint32_t mmutranslatereal(uint32_t addr, int rw)
{
int mmuout=0;
uint32_t addr2;
uint32_t temp,temp2,temp3;
if (abrt) return -1;
/* if ((addr&~0xFFFFF)==0x77f00000) pclog("Do translate %08X %i %08X %08X\n",addr,rw,EAX,pc);
if (addr==0x77f61000) output = 3;
if (addr==0x77f62000) { dumpregs(); exit(-1); }
if (addr==0x77f9a000) { dumpregs(); exit(-1); }*/
addr2=(cr3+((addr>>20)&0xFFC));
temp=temp2=((uint32_t *)ram)[addr2>>2];
// pclog("Do translate %08X %i %08X\n", addr, rw, temp);
if (!(temp&1))// || (CPL==3 && !(temp&4) && !cpl_override) || (rw && !(temp&2) && (CPL==3 || cr0&WP_FLAG)))
{
// if (/*output==3 && */!nopageerrors) pclog("Section not present! %08X %08X %02X %04X:%08X %i %i\n",addr,temp,opcode,CS,pc,CPL,rw);
cr2=addr;
temp&=1;
if (CPL==3) temp|=4;
if (rw) temp|=2;
abrt = ABRT_PF;
abrt_error = temp;
/* if (addr == 0x70046D)
{
dumpregs();
exit(-1);
}*/
return -1;
}
temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2];
temp3=temp&temp2;
// pclog("Do translate %08X %08X\n", temp, temp3);
if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG)))
{
// if (!nopageerrors) pclog("Page not present! %08X %08X %02X %02X %04X:%08X %04X:%08X %i %i %i\n",addr,temp,opcode,opcode2,CS,pc,SS,ESP,ins,CPL,rw);
// if (addr == 0x815F6E90) output = 3;
/* if (addr == 0x10ADE020) output = 3;
if (addr == 0x10000008)
{
dumpregs();
exit(-1);
}*/
cr2=addr;
temp&=1;
if (CPL==3) temp|=4;
if (rw) temp|=2;
abrt = ABRT_PF;
abrt_error = temp;
// pclog("%04X\n",abrt);
return -1;
}
mmu_perm=temp&4;
((uint32_t *)ram)[addr2>>2]|=0x20;
((uint32_t *)ram)[((temp2&~0xFFF)+((addr>>10)&0xFFC))>>2]|=(rw?0x60:0x20);
// /*if (output) */pclog("Translate %08X %08X %08X %08X:%08X %08X\n",addr,(temp&~0xFFF)+(addr&0xFFF),temp,cs,pc,EDI);
return (temp&~0xFFF)+(addr&0xFFF);
}
void mmu_invalidate(uint32_t addr)
{
// readlookup2[addr >> 12] = writelookup2[addr >> 12] = 0xFFFFFFFF;
flushmmucache_cr3();
}
int memspeed[11]={256,320,384,512,640,768,1024,1152,1280,1536,1920};
int memwaitstate;
static int cachelookup[256];
static uint8_t *cachelookup2;
static int cachelnext;
void addreadlookup(uint32_t virt, uint32_t phys)
{
// return;
// printf("Addreadlookup %08X %08X %08X %08X %08X %08X %02X %08X\n",virt,phys,cs,ds,es,ss,opcode,pc);
if (readlookup2[virt>>12]!=0xFFFFFFFF)
{
/* if (readlookup2[virt>>12] != phys&~0xfff)
{
pclog("addreadlookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12);
dumpregs();
exit(-1);
}*/
return;
}
if (!cachelookup2[phys >> 12])
{
readlnum++;
cycles-=memwaitstate;
if (cachelookup[cachelnext] != 0xffffffff)
cachelookup2[cachelookup[cachelnext]] = 0;
cachelookup[cachelnext] = phys >> 12;
cachelookup2[phys >> 12] = 1;
cachelnext = (cachelnext + 1) & (cachesize - 1);
}
if (readlookup[readlnext]!=0xFFFFFFFF)
{
readlookup2[readlookup[readlnext]]=0xFFFFFFFF;
// readlnum--;
}
readlookup2[virt>>12]=phys&~0xFFF;
readlookupp[readlnext]=mmu_perm;
readlookup[readlnext++]=virt>>12;
readlnext&=(cachesize-1);
}
void addwritelookup(uint32_t virt, uint32_t phys)
{
// return;
// printf("Addwritelookup %08X %08X\n",virt,phys);
if (writelookup2[virt>>12]!=0xFFFFFFFF)
{
/* if (writelookup2[virt>>12] != phys&~0xfff)
{
pclog("addwritelookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12);
dumpregs();
exit(-1);
}*/
return;
}
if (!cachelookup2[phys >> 12])
{
writelnum++;
cycles-=memwaitstate;
if (cachelookup[cachelnext] != 0xffffffff)
cachelookup2[cachelookup[cachelnext]] = 0;
cachelookup[cachelnext] = phys >> 12;
cachelookup2[phys >> 12] = 1;
cachelnext = (cachelnext + 1) & (cachesize - 1);
}
cycles-=memwaitstate;
if (writelookup[writelnext]!=0xFFFFFFFF)
{
writelookup2[writelookup[writelnext]]=0xFFFFFFFF;
// writelnum--;
}
writelookup2[virt>>12]=phys&~0xFFF;
writelookupp[writelnext]=mmu_perm;
writelookup[writelnext++]=virt>>12;
writelnext&=(cachesize-1);
}
#undef printf
uint8_t *getpccache(uint32_t a)
{
// int logit=(a>0xFFFFF);
uint32_t a2=a;
if (readlookup2[a>>12]!=0xFFFFFFFF) return &ram[(uint8_t *)readlookup2[a>>12] - (uint8_t *)(a&~0xFFF)];
if (cr0>>31)
{
// if (output==3) pclog("Translate GetPCCache %08X\n",a);
pctrans=1;
a=mmutranslate(a,0);
pctrans=0;
// if (output==3) pclog("GetPCCache output %08X\n",a);
if (a==0xFFFFFFFF) return ram;
/* {
printf("Bad getpccache %08X\n",a);
dumpregs();
exit(-1);
}*/
}
a&=rammask;
//if (output==3) pclog("Getpccache %08X %i\n",a,shadowbios);
if (isram[a>>16])
{
//if (readlookup2[a>>12]!=0xFFFFFFFF) return &ram[readlookup2[a>>12]];
if ((a>>16)!=0xF || shadowbios)
addreadlookup(a2,a);
// if (a > 0xc0000000)
// printf("%016X %016X %016X\n", ((long)a&0xFFFFF000), ((long)a2&~0xFFF), (uint8_t *)(a&0xFFFFF000) - (uint8_t *)(a2&~0xFFF));
return &ram[(uint8_t *)(a&0xFFFFF000) - (uint8_t *)(a2&~0xFFF)];
}
// if (logit) printf("PCCACHE - %08X -> %08X\n",a2,a);
switch (a>>16)
{
case 0xC: if (a&0x8000) return &romext[(uint8_t *)(a&0x7000) - (uint8_t *)(a2&~0xFFF)];
return &vrom[(uint8_t *)(a&0x7000) - (uint8_t *)(a2&~0xFFF)];
case 0xE: if (shadowbios) return &ram[(uint8_t *)(a&0xFFF000) - (uint8_t *)(a2&~0xFFF)];
return &rom[(uint8_t *)((a & biosmask) & ~ 0xfff) - (uint8_t *)(a2 & ~0xFFF)];
case 0xF: if (shadowbios) return &ram[(uint8_t *)(a&0xFFF000) - (uint8_t *)(a2&~0xFFF)];
return &rom[(uint8_t *)((a & biosmask) & ~ 0xfff) - (uint8_t *)(a2 & ~0xFFF)];
}
return &rom[(long)(a&0xF000) - (long)(a2&~0xFFF)];
/*printf("Bad getpccache %08X\n",a);
dumpregs();
exit(-1);*/
}
#define printf pclog
static uint32_t mem_logical_addr;
uint8_t readmembl(uint32_t addr)
{
mem_logical_addr = addr;
if (cr0 >> 31)
{
addr = mmutranslate(addr, 0);
if (addr == 0xFFFFFFFF) return 0xFF;
}
addr &= rammask;
switch (addr>>16)
{
case 13: if (romset==ROM_AMI286) return neat_readems(addr); return 0xFF;
// case 14: pclog("Read %06X\n", addr); if (shadowbios) { /*printf("Read shadow RAM %08X %02X\n",addr,ram[addr]);*/ return ram[addr]; }
}
if (_mem_read_b[addr >> 15]) return _mem_read_b[addr >> 15](addr);
return 0xFF;
}
void writemembl(uint32_t addr, uint8_t val)
{
mem_logical_addr = addr;
if (cr0 >> 31)
{
addr = mmutranslate(addr,1);
if (addr == 0xFFFFFFFF) return;
}
addr &= rammask;
switch (addr>>16)
{
case 13: if (romset==ROM_AMI286) neat_writeems(addr,val); return;
// case 14: printf("Write %08X %02X\n",addr,val); //ram[addr]=val;
// if (isram[(addr>>16)&0xFF]) ram[addr]=val;
// return;
}
if (_mem_write_b[addr >> 15]) _mem_write_b[addr >> 15](addr, val);
// else pclog("Bad write %08X %02X\n", addr, val);
}
uint8_t readmemb386l(uint32_t seg, uint32_t addr)
{
if (seg==-1)
{
x86gpf("NULL segment", 0);
printf("NULL segment! rb %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
return -1;
}
mem_logical_addr = addr = addr + seg;
if (readlookup2[mem_logical_addr >> 12] != 0xFFFFFFFF)
{
return ram[readlookup2[mem_logical_addr >> 12] + (mem_logical_addr & 0xFFF)];
}
if (cr0 >> 31)
{
addr = mmutranslate(addr, 0);
if (addr == 0xFFFFFFFF) return 0xFF;
}
addr &= rammask;
if (_mem_read_b[addr >> 15]) return _mem_read_b[addr >> 15](addr);
return 0xFF;
}
void writememb386l(uint32_t seg, uint32_t addr, uint8_t val)
{
if (seg==-1)
{
x86gpf("NULL segment", 0);
printf("NULL segment! wb %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
return;
}
mem_logical_addr = addr = addr + seg;
if (cr0 >> 31)
{
addr = mmutranslate(addr, 1);
if (addr == 0xFFFFFFFF) return;
}
addr &= rammask;
if (_mem_write_b[addr >> 15]) _mem_write_b[addr >> 15](addr, val);
// else pclog("Bad write %08X %02X\n", addr, val);
}
uint16_t readmemwl(uint32_t seg, uint32_t addr)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if ((addr2&0xFFF)>0xFFE)
{
if (cr0>>31)
{
if (mmutranslate(addr2, 0) == 0xffffffff) return;
if (mmutranslate(addr2+1, 0) == 0xffffffff) return;
}
if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8);
else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8);
}
if (seg==-1)
{
x86gpf("NULL segment", 0);
printf("NULL segment! rw %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
return -1;
}
if (cr0>>31)
{
addr2=mmutranslate(addr2,0);
if (addr2==0xFFFFFFFF) return 0xFFFF;
}
addr2 &= rammask;
if (_mem_read_w[addr2 >> 15]) return _mem_read_w[addr2 >> 15](addr2);
if (_mem_read_b[addr2 >> 15])
{
if (AT) return _mem_read_b[addr2 >> 15](addr2) | (_mem_read_b[(addr2 + 1) >> 15](addr2 + 1) << 8);
else return _mem_read_b[addr2 >> 15](addr2) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 15](seg + ((addr + 1) & 0xffff)) << 8);
}
return 0xffff;
}
void writememwl(uint32_t seg, uint32_t addr, uint16_t val)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if ((addr2&0xFFF)>0xFFE)
{
if (cr0>>31)
{
if (mmutranslate(addr2, 1) == 0xffffffff) return;
if (mmutranslate(addr2+1, 1) == 0xffffffff) return;
}
if (is386)
{
writememb386l(seg,addr,val);
writememb386l(seg,addr+1,val>>8);
}
else
{
writemembl(seg+addr,val);
writemembl(seg+addr+1,val>>8);
}
return;
}
if (seg==-1)
{
x86gpf("NULL segment", 0);
printf("NULL segment! ww %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
return;
}
if (cr0>>31)
{
addr2=mmutranslate(addr2,1);
if (addr2==0xFFFFFFFF) return;
}
addr2 &= rammask;
if (_mem_write_w[addr2 >> 15])
{
_mem_write_w[addr2 >> 15](addr2, val);
return;
}
if (_mem_write_b[addr2 >> 15])
{
_mem_write_b[addr2 >> 15](addr2, val);
_mem_write_b[(addr2 + 1) >> 15](addr2 + 1, val >> 8);
// if (AT) _
// else _mem_write_b[(seg + ((addr + 1) & 0xffff)) >> 15](seg + ((addr + 1) & 0xffff), val >> 8);
return;
}
// pclog("Bad write %08X %04X\n", addr, val);
}
uint32_t readmemll(uint32_t seg, uint32_t addr)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if ((addr2&0xFFF)>0xFFC)
{
if (cr0>>31)
{
if (mmutranslate(addr2, 0) == 0xffffffff) return;
if (mmutranslate(addr2+3, 0) == 0xffffffff) return;
}
return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16);
}
if (seg==-1)
{
x86gpf("NULL segment", 0);
printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
return -1;
}
if (cr0>>31)
{
addr2=mmutranslate(addr2,0);
if (addr2==0xFFFFFFFF) return 0xFFFFFFFF;
}
addr2&=rammask;
if (_mem_read_l[addr2 >> 15]) return _mem_read_l[addr2 >> 15](addr2);
if (_mem_read_w[addr2 >> 15]) return _mem_read_w[addr2 >> 15](addr2) | (_mem_read_w[addr2 >> 15](addr2 + 2) << 16);
if (_mem_read_b[addr2 >> 15]) return _mem_read_b[addr2 >> 15](addr2) | (_mem_read_b[addr2 >> 15](addr2 + 1) << 8) | (_mem_read_b[addr2 >> 15](addr2 + 2) << 16) | (_mem_read_b[addr2 >> 15](addr2 + 3) << 24);
return 0xffffffff;
}
void writememll(uint32_t seg, uint32_t addr, uint32_t val)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if ((addr2&0xFFF)>0xFFC)
{
if (cr0>>31)
{
if (mmutranslate(addr2, 1) == 0xffffffff) return;
if (mmutranslate(addr2+3, 1) == 0xffffffff) return;
}
writememwl(seg,addr,val);
writememwl(seg,addr+2,val>>16);
return;
}
if (seg==-1)
{
x86gpf("NULL segment", 0);
printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr);
return;
}
if (cr0>>31)
{
addr2=mmutranslate(addr2,1);
if (addr2==0xFFFFFFFF) return;
}
addr2&=rammask;
if (_mem_write_l[addr2 >> 15])
{
_mem_write_l[addr2 >> 15](addr2, val);
return;
}
if (_mem_write_w[addr2 >> 15])
{
_mem_write_w[addr2 >> 15](addr2, val);
_mem_write_w[addr2 >> 15](addr2 + 2, val >> 16);
return;
}
if (_mem_write_b[addr2 >> 15])
{
_mem_write_b[addr2 >> 15](addr2, val);
_mem_write_b[addr2 >> 15](addr2 + 1, val >> 8);
_mem_write_b[addr2 >> 15](addr2 + 2, val >> 16);
_mem_write_b[addr2 >> 15](addr2 + 3, val >> 24);
return;
}
// pclog("Bad write %08X %08X\n", addr, val);
}
uint8_t mem_read_ram(uint32_t addr)
{
// if (addr < 0xa0000) pclog("Read RAMb %08X\n", addr);
addreadlookup(mem_logical_addr, addr);
return ram[addr];
}
uint16_t mem_read_ramw(uint32_t addr)
{
// if (addr < 0xa0000) pclog("Read RAMw %08X\n", addr);
addreadlookup(mem_logical_addr, addr);
return *(uint16_t *)&ram[addr];
}
uint32_t mem_read_raml(uint32_t addr)
{
// if (addr < 0xa0000) pclog("Read RAMl %08X\n", addr);
addreadlookup(mem_logical_addr, addr);
return *(uint32_t *)&ram[addr];
}
void mem_write_ram(uint32_t addr, uint8_t val)
{
addwritelookup(mem_logical_addr, addr);
ram[addr] = val;
// if (addr >= 0xe0000 && addr < 0x100000) pclog("Write RAMb %08X\n", addr);
}
void mem_write_ramw(uint32_t addr, uint16_t val)
{
addwritelookup(mem_logical_addr, addr);
*(uint16_t *)&ram[addr] = val;
// if (addr >= 0xe0000 && addr < 0x100000) pclog("Write RAMw %08X %04X:%04X\n", addr, CS, pc);
}
void mem_write_raml(uint32_t addr, uint32_t val)
{
addwritelookup(mem_logical_addr, addr);
*(uint32_t *)&ram[addr] = val;
// if (addr >= 0xe0000 && addr < 0x100000) pclog("Write RAMl %08X %04X:%04X %04X:%04X %04X:%04X\n", addr, CS, pc, DS,SI, ES,DI);
}
uint8_t mem_read_bios(uint32_t addr)
{
if (AMIBIOS && (addr&0xFFFFF)==0xF8281) /*This is read constantly during AMIBIOS POST, but is never written to. It's clearly a status register of some kind, but for what?*/
{
// pclog("Read magic addr %04X(%06X):%04X\n",CS,cs,pc);
// if (pc==0x547D) output=3;
return 0x40;
}
// if (output) pclog("Read BIOS %08X %02X %04X:%04X\n", addr, rom[addr & biosmask], CS, pc);
return rom[addr & biosmask];
}
uint16_t mem_read_biosw(uint32_t addr)
{
// if (output) pclog("Read BIOS %08X %04X %04X:%04X\n", addr, *(uint16_t *)&rom[addr & biosmask], CS, pc);
return *(uint16_t *)&rom[addr & biosmask];
}
uint32_t mem_read_biosl(uint32_t addr)
{
// if (output) pclog("Read BIOS %08X %02X %04X:%04X\n", addr, *(uint32_t *)&rom[addr & biosmask], CS, pc);
return *(uint32_t *)&rom[addr & biosmask];
}
uint8_t mem_read_vrom(uint32_t addr)
{
return vrom[addr & 0x7fff];
}
uint16_t mem_read_vromw(uint32_t addr)
{
return *(uint16_t *)&vrom[addr & 0x7fff];
}
uint32_t mem_read_vroml(uint32_t addr)
{
return *(uint32_t *)&vrom[addr & 0x7fff];
}
uint8_t mem_read_romext(uint32_t addr)
{
return romext[addr & 0x7fff];
}
uint16_t mem_read_romextw(uint32_t addr)
{
return *(uint16_t *)&romext[addr & 0x7fff];
}
uint32_t mem_read_romextl(uint32_t addr)
{
return *(uint32_t *)&romext[addr & 0x7fff];
}
void mem_init()
{
int c;
ram=malloc(mem_size*1024*1024);
rom=malloc(0x20000);
vram=malloc(0x800000);
vrom=malloc(0x8000);
readlookup2=malloc(1024*1024*4);
writelookup2=malloc(1024*1024*4);
cachelookup2=malloc(1024*1024);
biosmask=65535;
makeznptable();
memset(ram,0,mem_size*1024*1024);
for (c = 0; c < 0x10000; c++) isram[c] = 0;
for (c=0;c<(mem_size*16);c++)
{
isram[c]=1;
if (c >= 0xa && c<=0xF) isram[c]=0;
}
for (c = 0; c < 0x20000; c++)
_mem_read_b[c] = _mem_read_w[c] = _mem_read_l[c] = _mem_write_b[c] = _mem_write_w[c] = _mem_write_l[c] = NULL;
mem_sethandler(0x00000, 0xa0000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml);
if (mem_size > 1)
mem_sethandler(0x100000, (mem_size - 1) * 1024 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml);
mem_sethandler(0xc0000, 0x08000, mem_read_vrom, mem_read_vromw, mem_read_vroml, NULL, NULL, NULL);
mem_sethandler(0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL);
mem_sethandler(0xe0000, 0x20000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml);
// pclog("Mem resize %i %i\n",mem_size,c);
}
void mem_resize()
{
int c;
free(ram);
ram=malloc(mem_size*1024*1024);
memset(ram,0,mem_size*1024*1024);
for (c = 0; c < 0x10000; c++) isram[c] = 0;
for (c=0;c<(mem_size*16);c++)
{
isram[c]=1;
if (c >= 0xa && c<=0xF) isram[c]=0;
}
for (c = 0; c < 0x20000; c++)
_mem_read_b[c] = _mem_read_w[c] = _mem_read_l[c] = _mem_write_b[c] = _mem_write_w[c] = _mem_write_l[c] = NULL;
mem_sethandler(0x00000, 0xa0000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml);
if (mem_size > 1)
mem_sethandler(0x100000, (mem_size - 1) * 1024 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml);
mem_sethandler(0xc0000, 0x8000, mem_read_vrom, mem_read_vromw, mem_read_vroml, NULL, NULL, NULL);
mem_sethandler(0xc8000, 0x8000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL);
mem_sethandler(0xe0000, 0x20000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml);
// pclog("Mem resize %i %i\n",mem_size,c);
}
void mem_updatecache()
{
flushmmucache();
if (!is386)
{
cachesize=256;
memwaitstate=0;
return;
}
if (cpu_16bitbus)
memwaitstate = 512 * cpu_multi;
else
memwaitstate = 384 * cpu_multi; //memspeed[cpuspeed];
switch (cache)
{
case 0: cachesize=32; break;
case 1: cachesize=64; break;
case 2: cachesize=128; break;
case 3: cachesize=256; break;
case 4: cachesize=256; memwaitstate=0; break;
}
}
void mem_sethandler(uint32_t base, uint32_t size,
uint8_t (*read_b)(uint32_t addr),
uint16_t (*read_w)(uint32_t addr),
uint32_t (*read_l)(uint32_t addr),
void (*write_b)(uint32_t addr, uint8_t val),
void (*write_w)(uint32_t addr, uint16_t val),
void (*write_l)(uint32_t addr, uint32_t val))
{
uint32_t c;
for (c = base; c < base + size; c += 0x8000)
{
_mem_read_b[ c >> 15] = read_b;
_mem_read_w[ c >> 15] = read_w;
_mem_read_l[ c >> 15] = read_l;
_mem_write_b[c >> 15] = write_b;
_mem_write_w[c >> 15] = write_w;
_mem_write_l[c >> 15] = write_l;
}
}
void mem_removehandler(uint32_t base, uint32_t size,
uint8_t (*read_b)(uint32_t addr),
uint16_t (*read_w)(uint32_t addr),
uint32_t (*read_l)(uint32_t addr),
void (*write_b)(uint32_t addr, uint8_t val),
void (*write_w)(uint32_t addr, uint16_t val),
void (*write_l)(uint32_t addr, uint32_t val))
{
uint32_t c;
if ((base + size) > 0xffff8000)
size = 0xffff0000 - base;
for (c = base; c < base + size; c += 0x8000)
{
if ( _mem_read_b[c >> 15] == read_b) _mem_read_b[c >> 15] = NULL;
if ( _mem_read_w[c >> 15] == read_w) _mem_read_w[c >> 15] = NULL;
if ( _mem_read_l[c >> 15] == read_l) _mem_read_l[c >> 15] = NULL;
if (_mem_write_b[c >> 15] == write_b) _mem_write_b[c >> 15] = NULL;
if (_mem_write_w[c >> 15] == write_w) _mem_write_w[c >> 15] = NULL;
if (_mem_write_l[c >> 15] == write_l) _mem_write_l[c >> 15] = NULL;
}
}
int mem_a20_key = 0, mem_a20_alt = 0;
static int mem_a20_state = 0;
void mem_a20_recalc()
{
int state = mem_a20_key | mem_a20_alt;
pclog("A20 recalc %i %i\n", state, mem_a20_state);
if (state && !mem_a20_state)
{
rammask = 0xffffffff;
flushmmucache();
}
else if (!state && mem_a20_state)
{
rammask = 0xffefffff;
flushmmucache();
}
pclog("rammask now %08X\n", rammask);
mem_a20_state = state;
}