This repository has been archived on 2025-05-24. You can view files and clone it, but cannot push or open issues or pull requests.
Files
VARCem/src/mem.c
waltje 30b903c744 Many small fixes here and there.
Devices now have a 'path' member, which usually points to a ROM file, or loader script.
No more 'available' functions unless one is needed for special cases.
Machines now can be 'configured' for mainboard settings etc.
Machines are now devices as well (root devices).
Regular devices now get a pointer to a 'parent' device.
The machines table has been reduced to just a lookup table, machine info is now inside the machine file.
Machine-specific CPU lists are now inside the machine file.
Chipset implementations are now devices, and were moved to devices/chipsets/
Much work on individual machines done.
All COMPAQ machines moved to dev-branch.
Zenith SupersPORT moved to dev-branch.
The i686-based machines (Tyan) released from dev-branch and cleaned up.
Several new MFM and RLL disk controllers for XT, in dev-branch for now.
2019-04-21 16:09:56 -05:00

1738 lines
42 KiB
C

/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
*
* This file is part of the VARCem Project.
*
* Memory handling and MMU.
*
* Version: @(#)mem.c 1.0.29 2019/04/20
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017-2019 Fred N. van Kempen.
* Copyright 2016-2019 Miran Grca.
* Copyright 2008-2018 Sarah Walker.
*
* 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 2 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, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include "emu.h"
#include "cpu/cpu.h"
#include "cpu/x86_ops.h"
#include "cpu/x86.h"
#include "machines/machine.h"
#include "config.h"
#include "io.h"
#include "mem.h"
#include "rom.h"
#ifdef USE_DYNAREC
# include "cpu/codegen.h"
#else
# define PAGE_MASK_INDEX_MASK 3
# define PAGE_MASK_INDEX_SHIFT 10
# define PAGE_MASK_MASK 63
# define PAGE_MASK_SHIFT 4
#endif
uint8_t *ram; /* the virtual RAM */
uint32_t rammask;
mem_map_t base_mapping,
ram_low_mapping, /* 0..640K mapping */
ram_mid_mapping,
ram_remapped_mapping, /* 640..1024K mapping */
ram_high_mapping; /* 1024K+ mapping */
page_t *pages, /* RAM page table */
**page_lookup; /* pagetable lookup */
uint32_t pages_sz = 0; /* #pages in table */
uint32_t pccache;
uint8_t *pccache2;
int readlnext;
int readlookup[256],
readlookupp[256];
uintptr_t *readlookup2;
int writelnext;
int writelookup[256],
writelookupp[256];
uintptr_t *writelookup2;
uint32_t mem_logical_addr;
int pctrans = 0;
int cachesize = 256;
uint32_t ram_mapped_addr[64];
uint32_t get_phys_virt,
get_phys_phys;
int mem_a20_key = 0,
mem_a20_alt = 0,
mem_a20_state = 0;
int mmuflush = 0;
int mmu_perm = 4;
/* FIXME: re-do this with a 'mem_ops' struct. */
static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv);
static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv);
static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv);
static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv);
static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv);
static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv);
static uint8_t *_mem_exec[0x40000];
static void *_mem_priv_r[0x40000];
static void *_mem_priv_w[0x40000];
static mem_map_t *_mem_map_r[0x40000];
static mem_map_t *_mem_map_w[0x40000];
static int _mem_state[0x40000];
static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff };
static int port_92_reg = 0;
void
resetreadlookup(void)
{
int c;
/* Initialize the page lookup table. */
memset(page_lookup, 0x00, (1<<20)*sizeof(page_t *));
/* Initialize the tables for lower (<= 1024K) RAM. */
for (c = 0; c < 256; c++) {
readlookup[c] = 0xffffffff;
writelookup[c] = 0xffffffff;
}
/* Initialize the tables for high (> 1024K) RAM. */
memset(readlookup2, 0xff, (1<<20)*sizeof(uintptr_t));
memset(writelookup2, 0xff, (1<<20)*sizeof(uintptr_t));
readlnext = 0;
writelnext = 0;
pccache = 0xffffffff;
}
void
flushmmucache(void)
{
int c;
for (c = 0; c < 256; c++) {
if (readlookup[c] != (int)0xffffffff) {
readlookup2[readlookup[c]] = -1;
readlookup[c] = 0xffffffff;
}
if (writelookup[c] != (int)0xffffffff) {
page_lookup[writelookup[c]] = NULL;
writelookup2[writelookup[c]] = -1;
writelookup[c] = 0xffffffff;
}
}
mmuflush++;
pccache = (uint32_t)0xffffffff;
#ifdef _MSC_VER
pccache2 = (uint8_t *)0xffffffffffffffff;
#else
pccache2 = (uint8_t *)0xffffffff;
#endif
#ifdef USE_DYNAREC
codegen_flush();
#endif
}
void
flushmmucache_nopc(void)
{
int c;
for (c = 0; c < 256; c++) {
if (readlookup[c] != (int)0xffffffff) {
readlookup2[readlookup[c]] = -1;
readlookup[c] = 0xffffffff;
}
if (writelookup[c] != (int)0xffffffff) {
page_lookup[writelookup[c]] = NULL;
writelookup2[writelookup[c]] = -1;
writelookup[c] = 0xffffffff;
}
}
}
void
flushmmucache_cr3(void)
{
int c;
for (c = 0; c < 256; c++) {
if (readlookup[c] != (int)0xffffffff) {
readlookup2[readlookup[c]] = -1;
readlookup[c] = 0xffffffff;
}
if (writelookup[c] != (int)0xffffffff) {
page_lookup[writelookup[c]] = NULL;
writelookup2[writelookup[c]] = -1;
writelookup[c] = 0xffffffff;
}
}
}
void
mem_flush_write_page(uint32_t addr, uint32_t virt)
{
page_t *page_target = &pages[addr >> 12];
int c;
for (c = 0; c < 256; c++) {
if (writelookup[c] != (int)0xffffffff) {
uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)];
if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) {
writelookup2[writelookup[c]] = -1;
page_lookup[writelookup[c]] = NULL;
writelookup[c] = 0xffffffff;
}
}
}
}
#define mmutranslate_read(addr) mmutranslatereal(addr,0)
#define mmutranslate_write(addr) mmutranslatereal(addr,1)
#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> 14]))[((x) >> 2) & 0xfff]
uint32_t
mmutranslatereal(uint32_t addr, int rw)
{
uint32_t temp,temp2,temp3;
uint32_t addr2;
if (cpu_state.abrt) return -1;
addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc));
temp = temp2 = rammap(addr2);
if (! (temp&1)) {
cr2 = addr;
temp &= 1;
if (CPL == 3) temp |= 4;
if (rw) temp |= 2;
cpu_state.abrt = ABRT_PF;
abrt_error = temp;
return -1;
}
if ((temp & 0x80) && (cr4 & CR4_PSE)) {
/*4MB page*/
if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3 && !cpl_override) || cr0 & WP_FLAG))) {
cr2 = addr;
temp &= 1;
if (CPL == 3)
temp |= 4;
if (rw)
temp |= 2;
cpu_state.abrt = ABRT_PF;
abrt_error = temp;
return -1;
}
mmu_perm = temp & 4;
rammap(addr2) |= 0x20;
return (temp & ~0x3fffff) + (addr & 0x3fffff);
}
temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc));
temp3 = temp & temp2;
if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || cr0&WP_FLAG))) {
cr2 = addr;
temp &= 1;
if (CPL == 3) temp |= 4;
if (rw) temp |= 2;
cpu_state.abrt = ABRT_PF;
abrt_error = temp;
return -1;
}
mmu_perm = temp & 4;
rammap(addr2) |= 0x20;
rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw?0x60:0x20);
return (temp&~0xfff)+(addr&0xfff);
}
uint32_t
mmutranslate_noabrt(uint32_t addr, int rw)
{
uint32_t temp,temp2,temp3;
uint32_t addr2;
if (cpu_state.abrt)
return -1;
addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc));
temp = temp2 = rammap(addr2);
if (! (temp & 1))
return -1;
if ((temp & 0x80) && (cr4 & CR4_PSE)) {
/*4MB page*/
if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (CPL == 3 || cr0 & WP_FLAG)))
return -1;
return (temp & ~0x3fffff) + (addr & 0x3fffff);
}
temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc));
temp3 = temp & temp2;
if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG)))
return -1;
return (temp & ~0xfff) + (addr & 0xfff);
}
void
mmu_invalidate(uint32_t addr)
{
flushmmucache_cr3();
}
uint8_t
mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len)
{
if (addr < start)
return 0;
else if (addr >= (start + len))
return 0;
else
return 1;
}
uint32_t
mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len)
{
uint32_t mask = len - 1;
return chunk_start + (addr & mask);
}
void
addreadlookup(uint32_t virt, uint32_t phys)
{
if (virt == 0xffffffff) return;
if (readlookup2[virt>>12] != (uintptr_t)-1) return;
if (readlookup[readlnext] != (int)0xffffffff)
readlookup2[readlookup[readlnext]] = -1;
readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)];
readlookupp[readlnext] = mmu_perm;
readlookup[readlnext++] = virt >> 12;
readlnext &= (cachesize-1);
cycles -= 9;
}
void
addwritelookup(uint32_t virt, uint32_t phys)
{
if (virt == 0xffffffff) return;
if (page_lookup[virt >> 12]) return;
if (writelookup[writelnext] != -1) {
page_lookup[writelookup[writelnext]] = NULL;
writelookup2[writelookup[writelnext]] = -1;
}
#ifdef USE_DYNAREC
if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page)
#else
if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3])
#endif
page_lookup[virt >> 12] = &pages[phys >> 12];
else
writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)];
writelookupp[writelnext] = mmu_perm;
writelookup[writelnext++] = virt >> 12;
writelnext &= (cachesize - 1);
cycles -= 9;
}
uint8_t *
getpccache(uint32_t a)
{
uint32_t a2;
a2 = a;
if (a2 < 0x100000 && ram_mapped_addr[a2 >> 14]) {
a = (ram_mapped_addr[a2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? a2 : (ram_mapped_addr[a2 >> 14] & ~0x3FFF) + (a2 & 0x3FFF);
return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)];
}
a2 = a;
if (cr0 >> 31) {
pctrans = 1;
a = mmutranslate_read(a);
pctrans = 0;
if (a == 0xffffffff) return ram;
}
a &= rammask;
if (_mem_exec[a >> 14]) {
if (is286) {
if (_mem_map_r[a >> 14]->flags & MEM_MAPPING_ROM)
cpu_prefetch_cycles = cpu_rom_prefetch_cycles;
else
cpu_prefetch_cycles = cpu_mem_prefetch_cycles;
}
return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xfff)];
}
ERRLOG("Bad getpccache %08X\n", a);
return (uint8_t *)&ff_pccache;
}
uint8_t
readmembl(uint32_t addr)
{
mem_logical_addr = addr;
if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) {
addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size)) return ram[addr];
return 0xff;
}
if (cr0 >> 31) {
addr = mmutranslate_read(addr);
if (addr == 0xffffffff) return 0xff;
}
addr &= rammask;
if (_mem_read_b[addr >> 14])
return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]);
return 0xff;
}
void
writemembl(uint32_t addr, uint8_t val)
{
mem_logical_addr = addr;
if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) {
addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
ram[addr] = val;
return;
}
if (page_lookup[addr>>12]) {
page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]);
return;
}
if (cr0 >> 31) {
addr = mmutranslate_write(addr);
if (addr == 0xffffffff) return;
}
addr &= rammask;
if (_mem_write_b[addr >> 14])
_mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
}
uint8_t
readmemb386l(uint32_t seg, uint32_t addr)
{
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return 0xff;
}
mem_logical_addr = addr = addr + seg;
if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) {
addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
return ram[addr];
return 0xff;
}
if (cr0 >> 31) {
addr = mmutranslate_read(addr);
if (addr == 0xffffffff)
return 0xff;
}
addr &= rammask;
if (_mem_read_b[addr >> 14])
return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]);
return 0xff;
}
void
writememb386l(uint32_t seg, uint32_t addr, uint8_t val)
{
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return;
}
mem_logical_addr = addr = addr + seg;
if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) {
addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
ram[addr] = val;
return;
}
if (page_lookup[addr>>12]) {
page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]);
return;
}
if (cr0 >> 31) {
addr = mmutranslate_write(addr);
if (addr == 0xffffffff) return;
}
addr &= rammask;
if (_mem_write_b[addr >> 14])
_mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
}
uint16_t
readmemwl(uint32_t seg, uint32_t addr)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return 0xffff;
}
if (addr2 & 1) {
if (!cpu_cyrix_alignment || (addr2 & 7) == 7)
cycles -= timing_misaligned;
if ((addr2 & 0xFFF) > 0xffe) {
if (cr0 >> 31) {
if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff;
if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff;
}
if (is386) return readmemb386l(seg,addr)|((uint16_t)(readmemb386l(seg,addr+1))<<8);
else return readmembl(seg+addr)|((uint16_t)(readmembl(seg+addr+1))<<8);
}
else if (readlookup2[addr2 >> 12] != (uintptr_t)-1)
return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2);
}
if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) {
addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
return *((uint16_t *)&ram[addr]);
return 0xffff;
}
if (cr0 >> 31) {
addr2 = mmutranslate_read(addr2);
if (addr2 == 0xffffffff)
return 0xFFFF;
}
addr2 &= rammask;
if (_mem_read_w[addr2 >> 14])
return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]);
if (_mem_read_b[addr2 >> 14]) {
if (AT)
return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) |
((uint16_t)(_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8);
else
return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) |
((uint16_t)(_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14])) << 8);
}
return 0xffff;
}
void
writememwl(uint32_t seg, uint32_t addr, uint16_t val)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return;
}
if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) {
addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
*((uint16_t *)&ram[addr]) = val;
return;
}
if (addr2 & 1) {
if (!cpu_cyrix_alignment || (addr2 & 7) == 7)
cycles -= timing_misaligned;
if ((addr2 & 0xFFF) > 0xffe) {
if (cr0 >> 31) {
if (mmutranslate_write(addr2) == 0xffffffff) return;
if (mmutranslate_write(addr2+1) == 0xffffffff) return;
}
if (is386) {
writememb386l(seg,addr,(uint8_t)(val&0xff));
writememb386l(seg,addr+1,(uint8_t)(val>>8));
} else {
writemembl(seg+addr,(uint8_t)(val&0xff));
writemembl(seg+addr+1,(uint8_t)(val>>8));
}
return;
} else if (writelookup2[addr2 >> 12] != (uintptr_t)-1) {
*(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val;
return;
}
}
if (page_lookup[addr2>>12]) {
page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]);
return;
}
if (cr0 >> 31) {
addr2 = mmutranslate_write(addr2);
if (addr2 == 0xffffffff) return;
}
addr2 &= rammask;
if (_mem_write_w[addr2 >> 14]) {
_mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]);
return;
}
if (_mem_write_b[addr2 >> 14]) {
_mem_write_b[addr2 >> 14](addr2, (uint8_t)(val&0xff), _mem_priv_w[addr2 >> 14]);
_mem_write_b[(addr2 + 1) >> 14](addr2 + 1, (uint8_t)(val>>8), _mem_priv_w[addr2 >> 14]);
return;
}
}
uint32_t
readmemll(uint32_t seg, uint32_t addr)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return -1;
}
if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) {
addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
return *((uint32_t *)&ram[addr]);
return 0xffffffff;
}
if (addr2 & 3) {
if (!cpu_cyrix_alignment || (addr2 & 7) > 4)
cycles -= timing_misaligned;
if ((addr2 & 0xfff) > 0xffc) {
if (cr0 >> 31) {
if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff;
if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff;
}
return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16);
} else if (readlookup2[addr2 >> 12] != (uintptr_t)-1)
return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2);
}
if (cr0 >> 31) {
addr2 = mmutranslate_read(addr2);
if (addr2 == 0xffffffff)
return 0xffffffff;
}
addr2 &= rammask;
if (_mem_read_l[addr2 >> 14])
return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]);
if (_mem_read_w[addr2 >> 14])
return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) |
((uint32_t)(_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16);
if (_mem_read_b[addr2 >> 14])
return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) |
((uint32_t)(_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8) |
((uint32_t)(_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16)) |
((uint32_t)(_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14])) << 24);
return 0xffffffff;
}
void
writememll(uint32_t seg, uint32_t addr, uint32_t val)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return;
}
if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) {
addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
*((uint32_t *)&ram[addr]) = val;
return;
}
if (addr2 & 3) {
if (!cpu_cyrix_alignment || (addr2 & 7) > 4)
cycles -= timing_misaligned;
if ((addr2 & 0xfff) > 0xffc) {
if (cr0 >> 31) {
if (mmutranslate_write(addr2) == 0xffffffff) return;
if (mmutranslate_write(addr2+3) == 0xffffffff) return;
}
writememwl(seg,addr,val);
writememwl(seg,addr+2,val>>16);
return;
} else if (writelookup2[addr2 >> 12] != (uintptr_t)-1) {
*(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val;
return;
}
}
if (page_lookup[addr2>>12]) {
page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]);
return;
}
if (cr0 >> 31) {
addr2 = mmutranslate_write(addr2);
if (addr2 == 0xffffffff) return;
}
addr2 &= rammask;
if (_mem_write_l[addr2 >> 14]) {
_mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]);
return;
}
if (_mem_write_w[addr2 >> 14]) {
_mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]);
_mem_write_w[addr2 >> 14](addr2+2, val >> 16, _mem_priv_w[addr2 >> 14]);
return;
}
if (_mem_write_b[addr2 >> 14]) {
_mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+1, val >> 8, _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+2, val >> 16, _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+3, val >> 24, _mem_priv_w[addr2 >> 14]);
return;
}
}
uint64_t
readmemql(uint32_t seg, uint32_t addr)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return -1;
}
if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) {
addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
return *((uint64_t *)&ram[addr]);
return -1;
}
if (addr2 & 7) {
cycles -= timing_misaligned;
if ((addr2 & 0xfff) > 0xff8) {
if (cr0 >> 31) {
if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff;
if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff;
}
return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32);
} else if (readlookup2[addr2 >> 12] != (uintptr_t)-1)
return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2);
}
if (cr0 >> 31) {
addr2 = mmutranslate_read(addr2);
if (addr2 == 0xffffffff)
return -1;
}
addr2 &= rammask;
if (_mem_read_l[addr2 >> 14])
return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) |
((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32);
return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32);
}
void
writememql(uint32_t seg, uint32_t addr, uint64_t val)
{
uint32_t addr2 = mem_logical_addr = seg + addr;
if (seg == (uint32_t)-1) {
x86gpf("NULL segment", 0);
return;
}
if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) {
addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff);
if (addr < (uint32_t)(1024UL * mem_size))
*((uint64_t *)&ram[addr]) = val;
return;
}
if (addr2 & 7) {
cycles -= timing_misaligned;
if ((addr2 & 0xfff) > 0xff8) {
if (cr0 >> 31) {
if (mmutranslate_write(addr2) == 0xffffffff) return;
if (mmutranslate_write(addr2+7) == 0xffffffff) return;
}
writememll(seg, addr, (uint32_t)(val&0xffffffff));
writememll(seg, addr+4, (uint32_t)(val>>32));
return;
} else if (writelookup2[addr2 >> 12] != (uintptr_t)-1) {
*(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val;
return;
}
}
if (page_lookup[addr2>>12]) {
page_lookup[addr2>>12]->write_l(addr2, (uint32_t)(val&0xffffffff), page_lookup[addr2>>12]);
page_lookup[addr2>>12]->write_l(addr2 + 4, (uint32_t)(val>>32), page_lookup[addr2>>12]);
return;
}
if (cr0 >> 31) {
addr2 = mmutranslate_write(addr2);
if (addr2 == 0xffffffff) return;
}
addr2 &= rammask;
if (_mem_write_l[addr2 >> 14]) {
_mem_write_l[addr2 >> 14](addr2, (uint32_t)(val&0xffffffff), _mem_priv_w[addr2 >> 14]);
_mem_write_l[addr2 >> 14](addr2+4, (uint32_t)(val>>32), _mem_priv_w[addr2 >> 14]);
return;
}
if (_mem_write_w[addr2 >> 14]) {
_mem_write_w[addr2 >> 14](addr2, (uint16_t)(val&0xffff), _mem_priv_w[addr2 >> 14]);
_mem_write_w[addr2 >> 14](addr2+2, (uint16_t)(val>>16), _mem_priv_w[addr2 >> 14]);
_mem_write_w[addr2 >> 14](addr2+4, (uint16_t)(val>>32), _mem_priv_w[addr2 >> 14]);
_mem_write_w[addr2 >> 14](addr2+6, (uint16_t)(val>>48), _mem_priv_w[addr2 >> 14]);
return;
}
if (_mem_write_b[addr2 >> 14]) {
_mem_write_b[addr2 >> 14](addr2, (uint8_t)(val&0xff), _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+1, (uint8_t)(val>>8), _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+2, (uint8_t)(val>>16), _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+3, (uint8_t)(val>>24), _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+4, (uint8_t)(val>>32), _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+5, (uint8_t)(val>>40), _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+6, (uint8_t)(val>>48), _mem_priv_w[addr2 >> 14]);
_mem_write_b[addr2 >> 14](addr2+7, (uint8_t)(val>>56), _mem_priv_w[addr2 >> 14]);
return;
}
}
uint8_t
mem_readb_phys(uint32_t addr)
{
if (_mem_exec[addr >> 14])
return _mem_exec[addr >> 14][addr & 0x3fff];
else if (_mem_read_b[addr >> 14])
return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]);
else
return 0xff;
}
uint16_t
mem_readw_phys(uint32_t addr)
{
uint16_t temp;
if (_mem_exec[addr >> 14])
return ((uint16_t *) _mem_exec[addr >> 14])[(addr >> 1) & 0x1fff];
else if (_mem_read_w[addr >> 14])
return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]);
else {
temp = mem_readb_phys(addr + 1) << 8;
temp |= mem_readb_phys(addr);
}
return temp;
}
void
mem_writeb_phys(uint32_t addr, uint8_t val)
{
if (_mem_exec[addr >> 14])
_mem_exec[addr >> 14][addr & 0x3fff] = val;
else if (_mem_write_b[addr >> 14])
_mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]);
}
uint8_t
mem_read_ram(uint32_t addr, void *priv)
{
addreadlookup(mem_logical_addr, addr);
return ram[addr];
}
uint16_t
mem_read_ramw(uint32_t addr, void *priv)
{
addreadlookup(mem_logical_addr, addr);
return *(uint16_t *)&ram[addr];
}
uint32_t
mem_read_raml(uint32_t addr, void *priv)
{
addreadlookup(mem_logical_addr, addr);
return *(uint32_t *)&ram[addr];
}
void
mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p)
{
#ifdef USE_DYNAREC
if (val != p->mem[addr & 0xfff] || codegen_in_recompile) {
#else
if (val != p->mem[addr & 0xfff]) {
#endif
uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
p->mem[addr & 0xfff] = val;
}
}
void
mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p)
{
#ifdef USE_DYNAREC
if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) {
#else
if (val != *(uint16_t *)&p->mem[addr & 0xfff]) {
#endif
uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
if ((addr & 0xf) == 0xf)
mask |= (mask << 1);
p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
*(uint16_t *)&p->mem[addr & 0xfff] = val;
}
}
void
mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p)
{
#ifdef USE_DYNAREC
if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) {
#else
if (val != *(uint32_t *)&p->mem[addr & 0xfff]) {
#endif
uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
if ((addr & 0xf) >= 0xd)
mask |= (mask << 1);
p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
*(uint32_t *)&p->mem[addr & 0xfff] = val;
}
}
void
mem_write_ram(uint32_t addr, uint8_t val, void *priv)
{
addwritelookup(mem_logical_addr, addr);
mem_write_ramb_page(addr, val, &pages[addr >> 12]);
}
void
mem_write_ramw(uint32_t addr, uint16_t val, void *priv)
{
addwritelookup(mem_logical_addr, addr);
mem_write_ramw_page(addr, val, &pages[addr >> 12]);
}
void
mem_write_raml(uint32_t addr, uint32_t val, void *priv)
{
addwritelookup(mem_logical_addr, addr);
mem_write_raml_page(addr, val, &pages[addr >> 12]);
}
static uint8_t
mem_read_remapped(uint32_t addr, void *priv)
{
if (addr >= (1024UL * mem_size) && addr < (1024UL * (mem_size + 384)))
addr = 0xA0000 + (addr - (mem_size * 1024));
addreadlookup(mem_logical_addr, addr);
return ram[addr];
}
static uint16_t
mem_read_remappedw(uint32_t addr, void *priv)
{
if ((addr >= (1024UL * mem_size)) && (addr < (1024UL * (mem_size + 384))))
addr = 0xA0000 + (addr - (mem_size * 1024));
addreadlookup(mem_logical_addr, addr);
return *(uint16_t *)&ram[addr];
}
static uint32_t
mem_read_remappedl(uint32_t addr, void *priv)
{
if ((addr >= (1024UL * mem_size)) && (addr < (1024UL * (mem_size + 384))))
addr = 0xA0000 + (addr - (mem_size * 1024));
addreadlookup(mem_logical_addr, addr);
return *(uint32_t *)&ram[addr];
}
static void
mem_write_remapped(uint32_t addr, uint8_t val, void *priv)
{
uint32_t oldaddr = addr;
if ((addr >= (1024UL * mem_size)) && (addr < (1024UL * (mem_size + 384))))
addr = 0xA0000 + (addr - (mem_size * 1024));
addwritelookup(mem_logical_addr, addr);
mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]);
}
static void
mem_write_remappedw(uint32_t addr, uint16_t val, void *priv)
{
uint32_t oldaddr = addr;
if ((addr >= (1024UL * mem_size)) && (addr < (1024UL * (mem_size + 384))))
addr = 0xA0000 + (addr - (mem_size * 1024));
addwritelookup(mem_logical_addr, addr);
mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]);
}
static void
mem_write_remappedl(uint32_t addr, uint32_t val, void *priv)
{
uint32_t oldaddr = addr;
if ((addr >= (1024UL * mem_size)) && (addr < (1024UL * (mem_size + 384))))
addr = 0xA0000 + (addr - (mem_size * 1024));
addwritelookup(mem_logical_addr, addr);
mem_write_raml_page(addr, val, &pages[oldaddr >> 12]);
}
void
mem_write_null(uint32_t addr, uint8_t val, void *p)
{
}
void
mem_write_nullw(uint32_t addr, uint16_t val, void *p)
{
}
void
mem_write_nulll(uint32_t addr, uint32_t val, void *p)
{
}
void
mem_invalidate_range(uint32_t start_addr, uint32_t end_addr)
{
uint32_t cur_addr;
start_addr &= ~PAGE_MASK_MASK;
end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK;
for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) {
uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK);
/*
* Do nothing if the pages array is empty or DMA reads/writes
* to/from PCI device memory addresses may crash the emulator.
*/
cur_addr = (start_addr >> 12);
if (cur_addr < pages_sz)
pages[cur_addr].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask;
}
}
static __inline int
mem_map_read_allowed(uint32_t fl, int state)
{
switch (state & MEM_READ_MASK) {
case MEM_READ_ANY:
return 1;
case MEM_READ_EXTERNAL:
return !(fl & MEM_MAPPING_INTERNAL);
case MEM_READ_INTERNAL:
return !(fl & MEM_MAPPING_EXTERNAL);
default:
fatal("mem_map_read_allowed : bad state %x\n", state);
}
return 0;
}
static __inline int
mem_map_write_allowed(uint32_t fl, int state)
{
switch (state & MEM_WRITE_MASK) {
case MEM_WRITE_DISABLED:
return 0;
case MEM_WRITE_ANY:
return 1;
case MEM_WRITE_EXTERNAL:
return !(fl & MEM_MAPPING_INTERNAL);
case MEM_WRITE_INTERNAL:
return !(fl & MEM_MAPPING_EXTERNAL);
default:
fatal("mem_map_write_allowed : bad state %x\n", state);
}
return 0;
}
static void
mem_map_recalc(uint64_t base, uint64_t size)
{
mem_map_t *map = base_mapping.next;
uint64_t c;
if (! size) return;
/* Clear out old mappings. */
for (c = base; c < base + size; c += 0x4000) {
_mem_read_b[c >> 14] = NULL;
_mem_read_w[c >> 14] = NULL;
_mem_read_l[c >> 14] = NULL;
_mem_exec[c >> 14] = NULL;
_mem_priv_r[c >> 14] = NULL;
_mem_map_r[c >> 14] = NULL;
_mem_write_b[c >> 14] = NULL;
_mem_write_w[c >> 14] = NULL;
_mem_write_l[c >> 14] = NULL;
_mem_priv_w[c >> 14] = NULL;
_mem_map_w[c >> 14] = NULL;
}
/* Walk mapping list. */
while (map != NULL) {
/*In range?*/
if (map->enable && (uint64_t)map->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)map->base + (uint64_t)map->size) > (uint64_t)base) {
uint64_t start = (map->base < base) ? map->base : base;
uint64_t end = (((uint64_t)map->base + (uint64_t)map->size) < (base + size)) ? ((uint64_t)map->base + (uint64_t)map->size) : (base + size);
if (start < map->base)
start = map->base;
for (c = start; c < end; c += 0x4000) {
if ((map->read_b || map->read_w || map->read_l) &&
mem_map_read_allowed(map->flags, _mem_state[c >> 14])) {
_mem_read_b[c >> 14] = map->read_b;
_mem_read_w[c >> 14] = map->read_w;
_mem_read_l[c >> 14] = map->read_l;
if (map->exec)
_mem_exec[c >> 14] = map->exec + (c - map->base);
else
_mem_exec[c >> 14] = NULL;
_mem_priv_r[c >> 14] = map->p;
_mem_map_r[c >> 14] = map;
}
if ((map->write_b || map->write_w || map->write_l) &&
mem_map_write_allowed(map->flags, _mem_state[c >> 14])) {
_mem_write_b[c >> 14] = map->write_b;
_mem_write_w[c >> 14] = map->write_w;
_mem_write_l[c >> 14] = map->write_l;
_mem_priv_w[c >> 14] = map->p;
_mem_map_w[c >> 14] = map;
}
}
}
map = map->next;
}
flushmmucache_cr3();
}
void
mem_map_del(mem_map_t *map)
{
mem_map_t *ptr;
/* Disable the entry. */
mem_map_disable(map);
/* Zap it from the list. */
for (ptr = &base_mapping; ptr->next != NULL; ptr = ptr->next) {
if (ptr->next == map) {
ptr->next = map->next;
break;
}
}
}
void
mem_map_add(mem_map_t *map, uint32_t base, uint32_t size,
uint8_t (*read_b)(uint32_t addr, void *p),
uint16_t (*read_w)(uint32_t addr, void *p),
uint32_t (*read_l)(uint32_t addr, void *p),
void (*write_b)(uint32_t addr, uint8_t val, void *p),
void (*write_w)(uint32_t addr, uint16_t val, void *p),
void (*write_l)(uint32_t addr, uint32_t val, void *p),
uint8_t *exec, uint32_t fl, void *p)
{
mem_map_t *dest = &base_mapping;
/* Add mapping to the end of the list.*/
while (dest->next)
dest = dest->next;
dest->next = map;
map->prev = dest;
if (size)
map->enable = 1;
else
map->enable = 0;
map->base = base;
map->size = size;
map->read_b = read_b;
map->read_w = read_w;
map->read_l = read_l;
map->write_b = write_b;
map->write_w = write_w;
map->write_l = write_l;
map->exec = exec;
map->flags = fl;
map->p = p;
map->p2 = NULL;
map->dev = NULL;
map->next = NULL;
mem_map_recalc(map->base, map->size);
}
void
mem_map_set_handler(mem_map_t *map,
uint8_t (*read_b)(uint32_t addr, void *p),
uint16_t (*read_w)(uint32_t addr, void *p),
uint32_t (*read_l)(uint32_t addr, void *p),
void (*write_b)(uint32_t addr, uint8_t val, void *p),
void (*write_w)(uint32_t addr, uint16_t val, void *p),
void (*write_l)(uint32_t addr, uint32_t val, void *p))
{
map->read_b = read_b;
map->read_w = read_w;
map->read_l = read_l;
map->write_b = write_b;
map->write_w = write_w;
map->write_l = write_l;
mem_map_recalc(map->base, map->size);
}
void
mem_map_set_addr(mem_map_t *map, uint32_t base, uint32_t size)
{
/* Remove old mapping. */
map->enable = 0;
mem_map_recalc(map->base, map->size);
/* Set new mapping. */
map->enable = 1;
map->base = base;
map->size = size;
mem_map_recalc(map->base, map->size);
}
void
mem_map_set_exec(mem_map_t *map, uint8_t *exec)
{
map->exec = exec;
mem_map_recalc(map->base, map->size);
}
void
mem_map_set_p(mem_map_t *map, void *p)
{
map->p = p;
}
void
mem_map_set_p2(mem_map_t *map, void *p)
{
map->p2 = p;
}
void
mem_map_set_dev(mem_map_t *map, void *p)
{
map->dev = p;
}
void
mem_map_disable(mem_map_t *map)
{
map->enable = 0;
mem_map_recalc(map->base, map->size);
}
void
mem_map_enable(mem_map_t *map)
{
map->enable = 1;
mem_map_recalc(map->base, map->size);
}
void
mem_set_mem_state(uint32_t base, uint32_t size, int state)
{
uint32_t c;
for (c = 0; c < size; c += 0x4000)
_mem_state[(c + base) >> 14] = state;
mem_map_recalc(base, size);
}
void
mem_a20_init(void)
{
if (AT) {
rammask = cpu_16bitbus ? 0xefffff : 0xffefffff;
flushmmucache();
mem_a20_state = mem_a20_key | mem_a20_alt;
} else {
rammask = 0xfffff;
flushmmucache();
mem_a20_key = mem_a20_alt = mem_a20_state = 0;
}
}
/* Reset the memory state. */
void
mem_reset(void)
{
uint32_t c, m;
/*
* Make sure the configured amount of RAM does not
* exceed the physical limit of the machine to avoid
* nasty crashes all over the place.
*/
m = mem_size;
c = machine->max_ram;
if (AT)
c <<= 10; /* make KB */
if (m > c) {
INFO("MEM: %luKB exceeds machine limit (%luKB), adjusted!\n", m, c);
mem_size = c;
}
m = 1024UL * mem_size;
if (ram != NULL)
free(ram);
ram = (uint8_t *)mem_alloc(m); /* allocate and clear the RAM block */
memset(ram, 0x00, m);
/*
* Allocate the page table based on how much RAM we have.
* We re-allocate the table on each (hard) reset, as the
* memory amount could have changed.
*/
if (AT) {
if (cpu_16bitbus) {
/* 80186/286; maximum address space is 16MB. */
m = 4096;
} else {
/* 80386+; maximum address space is 4GB. */
m = (mem_size + 384) >> 2;
if ((m << 2) < ((uint32_t)mem_size + 384))
m++;
if (m < 4096)
m = 4096;
}
} else {
/* 8088/86; maximum address space is 1MB. */
m = 256;
}
/*
* Allocate and initialize the (new) page table.
* We only do this if the size of the page table has changed.
*/
if (pages_sz != m || pages_sz == 0) {
pages_sz = m;
free(pages);
pages = (page_t *)mem_alloc(m * sizeof(page_t));
memset(pages, 0x00, m * sizeof(page_t));
}
/* Initialize the page table. */
for (c = 0; c < m; c++) {
pages[c].mem = &ram[c << 12];
pages[c].write_b = mem_write_ramb_page;
pages[c].write_w = mem_write_ramw_page;
pages[c].write_l = mem_write_raml_page;
}
/* Initialize the tables. */
resetreadlookup();
memset(_mem_read_b, 0x00, sizeof(_mem_read_b));
memset(_mem_read_w, 0x00, sizeof(_mem_read_w));
memset(_mem_read_l, 0x00, sizeof(_mem_read_l));
memset(_mem_write_b, 0x00, sizeof(_mem_write_b));
memset(_mem_write_w, 0x00, sizeof(_mem_write_w));
memset(_mem_write_l, 0x00, sizeof(_mem_write_l));
memset(_mem_exec, 0x00, sizeof(_mem_exec));
memset(&base_mapping, 0x00, sizeof(base_mapping));
memset(_mem_state, 0x00, sizeof(_mem_state));
mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024,
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
mem_set_mem_state(0x0c0000, 0x40000,
MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
mem_map_add(&ram_low_mapping, 0x00000,
(mem_size > 640) ? 0xa0000 : mem_size * 1024,
mem_read_ram,mem_read_ramw,mem_read_raml,
mem_write_ram,mem_write_ramw,mem_write_raml,
ram, MEM_MAPPING_INTERNAL, NULL);
if (mem_size > 1024) {
if (cpu_16bitbus && mem_size > 16256) {
mem_set_mem_state(0x100000, (16256 - 1024) * 1024,
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
mem_map_add(&ram_high_mapping, 0x100000,
((16256 - 1024) * 1024),
mem_read_ram,mem_read_ramw,mem_read_raml,
mem_write_ram,mem_write_ramw,mem_write_raml,
ram + 0x100000, MEM_MAPPING_INTERNAL, NULL);
} else {
mem_set_mem_state(0x100000, (mem_size - 1024) * 1024,
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
mem_map_add(&ram_high_mapping, 0x100000,
((mem_size - 1024) * 1024),
mem_read_ram,mem_read_ramw,mem_read_raml,
mem_write_ram,mem_write_ramw,mem_write_raml,
ram + 0x100000, MEM_MAPPING_INTERNAL, NULL);
}
}
if (mem_size > 768)
mem_map_add(&ram_mid_mapping, 0xc0000, 0x40000,
mem_read_ram,mem_read_ramw,mem_read_raml,
mem_write_ram,mem_write_ramw,mem_write_raml,
ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL);
mem_map_add(&ram_remapped_mapping, mem_size * 1024, 256 * 1024,
mem_read_remapped,mem_read_remappedw,mem_read_remappedl,
mem_write_remapped,mem_write_remappedw,mem_write_remappedl,
ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL);
mem_map_disable(&ram_remapped_mapping);
mem_a20_init();
}
/* Perform a one-time memory initialization. */
void
mem_init(void)
{
/* Perform a one-time init. */
ram = NULL;
pages = NULL;
pages_sz = 0;
/* Allocate the lookup tables. */
page_lookup = (page_t **)mem_alloc((1<<20)*sizeof(page_t *));
readlookup2 = (uintptr_t *)mem_alloc((1<<20)*sizeof(uintptr_t));
writelookup2 = (uintptr_t *)mem_alloc((1<<20)*sizeof(uintptr_t));
memset(ram_mapped_addr, 0x00, 64 * sizeof(uint32_t));
}
void
mem_remap_top(int kb)
{
uint32_t start = (mem_size >= 1024) ? mem_size : 1024;
int size = mem_size - 640;
uint32_t i;
INFO("MEM: remapping top %iKB (mem=%i)\n", kb, mem_size);
if (mem_size <= 640) return;
if (kb == 0) {
/* Called to disable the mapping. */
mem_map_disable(&ram_remapped_mapping);
return;
}
if (size > kb)
size = kb;
for (i = ((start * 1024) >> 12); i < (((start + size) * 1024) >> 12); i++) {
pages[i].mem = &ram[0xA0000 + ((i - ((start * 1024) >> 12)) << 12)];
pages[i].write_b = mem_write_ramb_page;
pages[i].write_w = mem_write_ramw_page;
pages[i].write_l = mem_write_raml_page;
}
mem_set_mem_state(start * 1024, size * 1024,
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
mem_map_set_addr(&ram_remapped_mapping, start * 1024, size * 1024);
mem_map_set_exec(&ram_remapped_mapping, ram + (start * 1024));
flushmmucache();
}
void
mem_reset_page_blocks(void)
{
uint32_t c;
if (pages == NULL) return;
for (c = 0; c < pages_sz; c++) {
pages[c].write_b = mem_write_ramb_page;
pages[c].write_w = mem_write_ramw_page;
pages[c].write_l = mem_write_raml_page;
pages[c].block[0] = pages[c].block[1] =
pages[c].block[2] = pages[c].block[3] = NULL;
pages[c].block_2[0] = pages[c].block_2[1] =
pages[c].block_2[2] = pages[c].block_2[3] = NULL;
}
}
void
mem_a20_recalc(void)
{
int state;
if (! AT) {
rammask = 0xfffff;
flushmmucache();
mem_a20_key = mem_a20_alt = mem_a20_state = 0;
return;
}
state = mem_a20_key | mem_a20_alt;
if (state && !mem_a20_state) {
rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff;
flushmmucache();
} else if (!state && mem_a20_state) {
rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff;
flushmmucache();
}
mem_a20_state = state;
}
uint8_t
port_92_read(uint16_t port, void *priv)
{
return port_92_reg;
}
void
port_92_write(uint16_t port, uint8_t val, void *priv)
{
if ((mem_a20_alt ^ val) & 2) {
mem_a20_alt = (val & 2);
mem_a20_recalc();
}
if ((~port_92_reg & val) & 1) {
cpu_reset(0);
cpu_set_edx();
}
port_92_reg = val;
}
void
port_92_clear_reset(void)
{
port_92_reg &= 2;
}
void
port_92_add(void)
{
io_sethandler(0x0092, 1,
port_92_read,NULL,NULL, port_92_write, NULL,NULL,NULL);
}
void
port_92_remove(void)
{
io_removehandler(0x0092, 1,
port_92_read,NULL,NULL, port_92_write,NULL,NULL, NULL);
}
void
port_92_reset(void)
{
port_92_reg = 0;
mem_a20_alt = 0;
mem_a20_recalc();
flushmmucache();
}