mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
2279 lines
61 KiB
C++
2279 lines
61 KiB
C++
/*
|
|
* UAE - The Un*x Amiga Emulator
|
|
*
|
|
* PCI Bridge board emulation
|
|
*
|
|
* Copyright 2015-2020 Toni Wilen
|
|
* Hardware information by Radoslaw Kujawa
|
|
*
|
|
*/
|
|
|
|
#define PCI_DEBUG_IO 0
|
|
#define PCI_DEBUG_MEMORY 0
|
|
#define PCI_DEBUG_CONFIG 1
|
|
#define PCI_DEBUG_BRIDGE 0
|
|
#define PCI_DEBUG_IO_MISS 0
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
|
|
#include "options.h"
|
|
#include "custom.h"
|
|
#include "memory.h"
|
|
#include "debug.h"
|
|
#include "pci_hw.h"
|
|
#include "pci.h"
|
|
#include "ncr_scsi.h"
|
|
#include "newcpu.h"
|
|
#include "uae.h"
|
|
#include "rommgr.h"
|
|
#include "cpuboard.h"
|
|
#include "autoconf.h"
|
|
#include "devices.h"
|
|
|
|
#include "qemuvga/qemuuaeglue.h"
|
|
#include "qemuvga/queue.h"
|
|
#include "qemuvga/scsi/scsi.h"
|
|
|
|
#define PCI_BRIDGE_WILDFIRE 0
|
|
#define PCI_BRIDGE_GREX (PCI_BRIDGE_WILDFIRE + 1)
|
|
#define PCI_BRIDGE_XVISION (PCI_BRIDGE_GREX + 1)
|
|
#define PCI_BRIDGE_PROMETHEUS (PCI_BRIDGE_XVISION + 1)
|
|
#define PCI_BRIDGE_MEDIATOR (PCI_BRIDGE_PROMETHEUS + MAX_DUPLICATE_EXPANSION_BOARDS)
|
|
#define PCI_BRIDGE_MAX (PCI_BRIDGE_MEDIATOR + MAX_DUPLICATE_EXPANSION_BOARDS + 1)
|
|
|
|
static struct pci_bridge *bridges[PCI_BRIDGE_MAX + 1];
|
|
static int last_bridge_index;
|
|
static struct pci_board_state *hsyncs[MAX_PCI_BOARDS + 1];
|
|
|
|
extern addrbank pci_config_bank, pci_io_bank, pci_mem_bank, pci_bridge_bank;
|
|
|
|
static void pci_board_free(struct pci_board_state *pcibs)
|
|
{
|
|
if (!pcibs || !pcibs->board)
|
|
return;
|
|
if (pcibs->board->free)
|
|
pcibs->board->free(pcibs);
|
|
}
|
|
|
|
static struct pci_bridge *pci_bridge_alloc(void)
|
|
{
|
|
struct pci_bridge *pcib = xcalloc(struct pci_bridge, 1);
|
|
last_bridge_index = 0;
|
|
return pcib;
|
|
};
|
|
|
|
static struct pci_bridge *pci_bridge_get_zorro(struct romconfig *rc)
|
|
{
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
if (bridges[i] && bridges[i]->rc == rc) {
|
|
return bridges[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static struct pci_bridge *pci_bridge_alloc_zorro(int offset, struct romconfig *rc)
|
|
{
|
|
struct pci_bridge *pcib = pci_bridge_alloc();
|
|
for (int i = 0; i < MAX_DUPLICATE_EXPANSION_BOARDS; i++) {
|
|
if (bridges[i + offset] == NULL) {
|
|
bridges[i + offset] = pcib;
|
|
pcib->rc = rc;
|
|
pcib->type = offset;
|
|
return pcib;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
struct pci_bridge *pci_bridge_get(void)
|
|
{
|
|
// FIXME!
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
if (bridges[i])
|
|
return bridges[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void pci_bridge_free(struct pci_bridge *pcib)
|
|
{
|
|
if (!pcib)
|
|
return;
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
pci_board_free(&pcib->boards[i]);
|
|
}
|
|
last_bridge_index = 0;
|
|
xfree(pcib->data);
|
|
xfree(pcib);
|
|
}
|
|
|
|
static struct pci_board *pci_board_alloc(struct pci_config *config)
|
|
{
|
|
struct pci_board *pci = xcalloc(struct pci_board, 1);
|
|
pci->config = config;
|
|
return pci;
|
|
}
|
|
|
|
struct pci_board_state *pci_board_add(struct pci_bridge *pcib, const struct pci_board *pci, int slot, int func, struct autoconfig_info *aci, void *userdata)
|
|
{
|
|
struct pci_board_state *pcibs = &pcib->boards[pcib->log_slot_cnt];
|
|
pcib->log_slot_cnt++;
|
|
if (!func)
|
|
pcib->phys_slot_cnt++;
|
|
pcibs->board = pci;
|
|
pcibs->slot = slot < 0 ? pcib->phys_slot_cnt : slot;
|
|
pcibs->func = func;
|
|
pcibs->bridge = pcib;
|
|
pcibs->irq_callback = pci_irq_callback;
|
|
pcibs->userdata = userdata;
|
|
memset(pcibs->config_data, 0, sizeof pcibs->config_data);
|
|
if (pci->pci_get_config) {
|
|
struct pci_config *config = &pcibs->dynamic_config;
|
|
config->vendor = (pci->pci_get_config(1) << 8) | pci->pci_get_config(0);
|
|
config->device = (pci->pci_get_config(3) << 8) | pci->pci_get_config(2);
|
|
config->deviceclass = (pci->pci_get_config(10) << 16) | (pci->pci_get_config(9) << 8) | pci->pci_get_config(8);
|
|
config->revision = pci->pci_get_config(11);
|
|
config->subsystem = (pci->pci_get_config(0x2d) << 8) | pci->pci_get_config(0x2c);
|
|
config->subsystenvendor = (pci->pci_get_config(0x2f) << 8) | pci->pci_get_config(0x2e);
|
|
config->max_latency = pci->pci_get_config(0x3f);
|
|
config->min_grant = pci->pci_get_config(0x3e);
|
|
config->interruptpin = pci->pci_get_config(0x3d);
|
|
} else {
|
|
memcpy(&pcibs->dynamic_config, pci->config, sizeof(struct pci_config));
|
|
}
|
|
for (int i = 0; i < MAX_PCI_BARS; i++) {
|
|
pcibs->bar_size[i] = pcibs->dynamic_config.bars[i];
|
|
}
|
|
if (pci->init)
|
|
pci->init(pcibs, aci);
|
|
if (pci->hsync) {
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
if (hsyncs[i] == NULL) {
|
|
hsyncs[i] = pcibs;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return pcibs;
|
|
}
|
|
|
|
static void pci_free(void)
|
|
{
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
pci_bridge_free(bridges[i]);
|
|
bridges[i] = NULL;
|
|
}
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
hsyncs[i] = NULL;
|
|
}
|
|
}
|
|
static void pci_reset(int hardreset)
|
|
{
|
|
pci_free();
|
|
}
|
|
|
|
static void pci_hsync(void)
|
|
{
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
if (hsyncs[i])
|
|
hsyncs[i]->board->hsync(hsyncs[i]);
|
|
}
|
|
}
|
|
|
|
static void pci_rethink(void)
|
|
{
|
|
static int bridgenum;
|
|
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
struct pci_bridge *pcib = bridges[(i + bridgenum) % PCI_BRIDGE_MAX];
|
|
if (!pcib)
|
|
continue;
|
|
pcib->irq = 0;
|
|
bridgenum = i;
|
|
for (int j = 0; j < MAX_PCI_BOARDS; j++) {
|
|
struct pci_board_state *pcibs = &pcib->boards[j];
|
|
if (pcibs->board) {
|
|
const struct pci_config *c = &pcibs->dynamic_config;
|
|
if (c->interruptpin) {
|
|
if ((pcibs->config_data[5] & (1 << 3)) && !(pcibs->config_data[6] & (1 << (10 - 8)))) {
|
|
uae_u8 pin = (c->interruptpin - 1 + pcibs->slot) & 3;
|
|
uae_u8 irq = 1 << pin;
|
|
pcib->irq |= irq;
|
|
if (irq & pcib->intena) {
|
|
//write_log(_T("%02x %02x %s\n"), pin, pcib->irq, pcibs->board->label);
|
|
safe_interrupt_set(IRQ_SOURCE_PCI, i, (pcib->intreq_mask & 0x2000) != 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void set_pci_irq(struct pci_bridge *pcib, struct pci_board_state *pcibs, bool active)
|
|
{
|
|
pcibs->config_data[5] &= ~(1 << 3);
|
|
if (active)
|
|
pcibs->config_data[5] |= (1 << 3);
|
|
devices_rethink_all(pci_rethink);
|
|
}
|
|
|
|
static void create_config_data(struct pci_board_state *s)
|
|
{
|
|
uae_u8 *d = s->config_data;
|
|
const struct pci_config *c = &s->dynamic_config;
|
|
|
|
// big endian, get/put functions will swap if needed.
|
|
d[0] = c->device >> 8;
|
|
d[1] = (uae_u8)c->device;
|
|
d[2] = c->vendor >> 8;
|
|
d[3] = (uae_u8)c->vendor;
|
|
|
|
d[8] = c->deviceclass >> 16;
|
|
d[9] = c->deviceclass >> 8;
|
|
d[10] = c->deviceclass;
|
|
d[11] = c->revision;
|
|
|
|
d[13] = c->header;
|
|
|
|
for (int i = 0; i < MAX_PCI_BARS; i++) {
|
|
int off = i == MAX_PCI_BARS - 1 ? 0x30 : 0x10 + i * 4;
|
|
d[off + 0] = s->bar[i] >> 24;
|
|
d[off + 1] = s->bar[i] >> 16;
|
|
d[off + 2] = s->bar[i] >> 8;
|
|
d[off + 3] = s->bar[i] >> 0;
|
|
}
|
|
|
|
d[0x2c] = c->subsystem >> 8;
|
|
d[0x2d] = (uae_u8)c->subsystem;
|
|
d[0x2e] = c->subsystenvendor >> 8;
|
|
d[0x2f] = (uae_u8)c->subsystenvendor;
|
|
|
|
d[0x3c] = c->max_latency;
|
|
d[0x3d] = c->min_grant;
|
|
d[0x3e] = c->interruptpin;
|
|
}
|
|
|
|
static struct pci_bridge *get_pci_bridge(uaecptr addr)
|
|
{
|
|
if (addr < 0x10000 || (addr & 0xffff0000) == AUTOCONFIG_Z2 || (addr & 0xff000000) == AUTOCONFIG_Z3) {
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
struct pci_bridge *pcib = bridges[i];
|
|
if (pcib && pcib->configured == 0) {
|
|
return pcib;
|
|
}
|
|
}
|
|
}
|
|
struct pci_bridge *pcib = bridges[last_bridge_index];
|
|
if (pcib) {
|
|
if (addr >= pcib->baseaddress && addr < pcib->baseaddress_end)
|
|
return pcib;
|
|
if (pcib->configured_2 && addr >= pcib->baseaddress_2 && addr < pcib->baseaddress_end_2)
|
|
return pcib;
|
|
}
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
struct pci_bridge *pcib = bridges[i];
|
|
if (pcib) {
|
|
if ((addr >= pcib->baseaddress && addr < pcib->baseaddress_end) ||
|
|
(pcib->configured_2 && addr >= pcib->baseaddress_2 && addr < pcib->baseaddress_end_2)) {
|
|
last_bridge_index = i;
|
|
return pcib;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static struct pci_bridge *get_pci_bridge_2(uaecptr addr)
|
|
{
|
|
if (addr < 0x10000 || (addr & 0xffff0000) == AUTOCONFIG_Z2 || (addr & 0xff000000) == AUTOCONFIG_Z3) {
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
struct pci_bridge *pcib = bridges[i];
|
|
if (pcib && pcib->configured_2 == 0) {
|
|
return pcib;
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
struct pci_bridge *pcib = bridges[i];
|
|
if (pcib && pcib->configured_2) {
|
|
if (addr >= pcib->baseaddress_2 && addr < pcib->baseaddress_end_2) {
|
|
last_bridge_index = i;
|
|
return pcib;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static struct pci_board_state *get_pci_board_state_config(struct pci_bridge *pcib, uaecptr addr)
|
|
{
|
|
if (!pcib)
|
|
return NULL;
|
|
// get slot
|
|
int idx = pcib->get_index(addr);
|
|
if (idx < 0)
|
|
return NULL;
|
|
int slot = idx & 0xff;
|
|
int func = (idx >> 8) & 0xff;
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
struct pci_board_state *pcibs = &pcib->boards[i];
|
|
if (pcibs->slot == slot && pcibs->func == func && pcibs->board)
|
|
return pcibs;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int stored_board, stored_bar;
|
|
|
|
static struct pci_board_state *get_pci_board_state(struct pci_bridge *pcib, uaecptr addr, bool io, int *bar)
|
|
{
|
|
uaecptr addr2 = addr;
|
|
if (io) {
|
|
addr2 -= pcib->io_offset;
|
|
} else {
|
|
addr2 -= pcib->memory_start_offset;
|
|
}
|
|
struct pci_board_state *pcibs2 = &pcib->boards[stored_board];
|
|
if (pcibs2 && stored_bar < MAX_PCI_BARS) {
|
|
if (pcibs2->bar_enabled[stored_bar] && addr2 >= pcibs2->bar_start[stored_bar] && addr2 <= pcibs2->bar_end[stored_bar]) {
|
|
*bar = stored_bar;
|
|
return pcibs2;
|
|
}
|
|
}
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
struct pci_board_state *pcibs = &pcib->boards[i];
|
|
for (int j = 0; j < MAX_PCI_BARS; j++) {
|
|
if (pcibs->bar_enabled[j] && addr2 >= pcibs->bar_start[j] && addr2 <= pcibs->bar_end[j]) {
|
|
*bar = j;
|
|
stored_board = i;
|
|
stored_bar = j;
|
|
return pcibs;
|
|
}
|
|
}
|
|
}
|
|
if (io && addr2 < 0x400) {
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
struct pci_board_state *pcibs = &pcib->boards[i];
|
|
if (pcibs->board->bars[MAX_PCI_BARS].bget) {
|
|
stored_board = i;
|
|
stored_bar = MAX_PCI_BARS;
|
|
*bar = stored_bar;
|
|
return pcibs;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static const pci_addrbank *get_pci_io(uaecptr *addrp, struct pci_board_state **pcibsp, int *endianswap, int size)
|
|
{
|
|
uaecptr addr = *addrp;
|
|
int bar;
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return NULL;
|
|
struct pci_board_state *pcibs = get_pci_board_state(pcib, addr, true, &bar);
|
|
if (!pcibs)
|
|
return NULL;
|
|
*pcibsp = pcibs;
|
|
pcibs->selected_bar = bar;
|
|
*endianswap = pcib->endian_swap_io;
|
|
addr -= pcib->io_offset;
|
|
if (!pcibs->board->dont_mask_io && bar < MAX_PCI_BARS) {
|
|
addr &= (pcibs->bar_size[bar] & ~1) - 1;
|
|
}
|
|
#if PCI_DEBUG_IO
|
|
write_log(_T("get_pci_io %08x=%08x %c:%d PC=%08x\n"), *addrp, addr, size < 0 ? 'W' : 'R', size < 0 ? -size : size, M68K_GETPC);
|
|
#endif
|
|
*addrp = addr;
|
|
return &pcibs->board->bars[bar];
|
|
}
|
|
|
|
static const pci_addrbank *get_pci_mem(uaecptr *addrp, struct pci_board_state **pcibsp, int *endianswap)
|
|
{
|
|
uaecptr addr = *addrp;
|
|
int bar;
|
|
#if PCI_DEBUG_MEMORY
|
|
write_log(_T("get_pci_mem %08x %08x\n"), addr, M68K_GETPC);
|
|
#endif
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return NULL;
|
|
struct pci_board_state *pcibs = get_pci_board_state(pcib, addr, false, &bar);
|
|
if (!pcibs)
|
|
return NULL;
|
|
*pcibsp = pcibs;
|
|
pcibs->selected_bar = bar;
|
|
*endianswap = pcib->endian_swap_memory;
|
|
addr -= pcibs->bridge->memory_start_offset;
|
|
*addrp = addr;
|
|
return &pcibs->board->bars[bar];
|
|
}
|
|
|
|
static uae_u8 *get_pci_config(uaecptr addr, int size, uae_u32 v, int *endianswap)
|
|
{
|
|
#if PCI_DEBUG_CONFIG
|
|
if (size < 0) {
|
|
size = -size;
|
|
write_log(_T("PCI Config Space %s READ %08x PC=%08x\n"),
|
|
size == 4 ? _T("LONG") : (size == 2 ? _T("WORD") : _T("BYTE")), addr, M68K_GETPC);
|
|
} else {
|
|
write_log(_T("PCI Config Space %s WRITE %08x = %08x PC=%08x\n"),
|
|
size == 4 ? _T("LONG") : (size == 2 ? _T("WORD") : _T("BYTE")), addr, v, M68K_GETPC);
|
|
}
|
|
#endif
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return NULL;
|
|
struct pci_board_state *pcibs = get_pci_board_state_config(pcib, addr);
|
|
if (!pcibs)
|
|
return NULL;
|
|
*endianswap = pcib->endian_swap_config;
|
|
#if PCI_DEBUG_CONFIG
|
|
write_log(_T("- Board %d/%d (%s)\n"), pcibs->slot, pcibs->func, pcibs->board->label);
|
|
#endif
|
|
if (pcibs->board->pci_get_config) {
|
|
int off = addr & 0xff;
|
|
uae_u8 *c = pcibs->config_data;
|
|
if (size == 4 || size == -4) {
|
|
c[off + 3] = pcibs->board->pci_get_config(off + 0);
|
|
c[off + 2] = pcibs->board->pci_get_config(off + 1);
|
|
c[off + 1] = pcibs->board->pci_get_config(off + 2);
|
|
c[off + 0] = pcibs->board->pci_get_config(off + 3);
|
|
} else if (size == 2 || size == -2) {
|
|
if (pcib->endian_swap_config < 0) {
|
|
c[(off ^ 2) + 0] = pcibs->board->pci_get_config(off + 0);
|
|
c[(off ^ 2) + 1] = pcibs->board->pci_get_config(off + 1);
|
|
} else if (pcib->endian_swap_config > 0) {
|
|
c[off + 0] = pcibs->board->pci_get_config(off + 0);
|
|
c[off + 1] = pcibs->board->pci_get_config(off + 1);
|
|
} else {
|
|
c[off + 1] = pcibs->board->pci_get_config((off ^ 2) + 0);
|
|
c[off + 0] = pcibs->board->pci_get_config((off ^ 2) + 1);
|
|
}
|
|
*endianswap = 0;
|
|
} else {
|
|
c[off] = pcibs->board->pci_get_config(off ^ 3);
|
|
*endianswap = 0;
|
|
}
|
|
} else {
|
|
create_config_data(pcibs);
|
|
}
|
|
return pcibs->config_data;
|
|
}
|
|
|
|
static void map_pci_banks(struct pci_board_state *pcibs, int type, bool enable)
|
|
{
|
|
const struct pci_board *pci = pcibs->board;
|
|
uae_u32 mask = type ? 3 : 15;
|
|
for (int i = 0; i < MAX_PCI_BARS; i++) {
|
|
if (pcibs->bar_size[i] == 0)
|
|
continue;
|
|
if ((pcibs->bar_size[i] & 1) != type)
|
|
continue;
|
|
pcibs->bar_start[i] = (pcibs->bar[i] & ~mask) + pcibs->bridge->baseaddress_offset;
|
|
pcibs->bar_end[i] = pcibs->bar_start[i] + (pcibs->bar_size[i] & ~1) - 1;
|
|
if (enable && pcibs->bar[i] < 0xffff0000) {
|
|
pcibs->bar_enabled[i] = true;
|
|
#if PCI_DEBUG_CONFIG
|
|
if (pcibs->bar_old[i] != pcibs->bar_start[i]) {
|
|
write_log(_T("Board %d/%d ('%s') BAR%d: %08x-%08x\n"), pcibs->slot, pcibs->func, pci->label, i, pcibs->bar_start[i], pcibs->bar_end[i]);
|
|
}
|
|
#endif
|
|
} else {
|
|
pcibs->bar_enabled[i] = false;
|
|
#if PCI_DEBUG_CONFIG
|
|
if (pcibs->bar_old[i] != pcibs->bar_start[i]) {
|
|
write_log(_T("Board %d/%d ('%s') BAR%d: %08x-%08x\n"), pcibs->slot, pcibs->func, pci->label, i, pcibs->bar_start[i], pcibs->bar_end[i]);
|
|
}
|
|
#endif
|
|
}
|
|
pcibs->bar_old[i] = pcibs->bar_start[i];
|
|
}
|
|
}
|
|
|
|
static void update_pci_config(uaecptr addr, int size)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return;
|
|
struct pci_board_state *pcibs = get_pci_board_state_config(pcib, addr);
|
|
if (!pcibs)
|
|
return;
|
|
uae_u8 *d = pcibs->config_data;
|
|
bool config_changed = false;
|
|
for (int i = 0; i < MAX_PCI_BARS; i++) {
|
|
int off = i == MAX_PCI_BARS - 1 ? 0x30 : 0x10 + i * 4;
|
|
if (pcibs->bar_size[i]) {
|
|
uae_u32 obar = pcibs->bar[i];
|
|
pcibs->bar[i] = d[off + 0] << 24;
|
|
pcibs->bar[i] |= d[off + 1] << 16;
|
|
pcibs->bar[i] |= d[off + 2] << 8;
|
|
pcibs->bar[i] |= d[off + 3] << 0;
|
|
pcibs->bar[i] &= ~((pcibs->bar_size[i] & ~1) - 1);
|
|
pcibs->bar[i] |= (pcibs->bar_size[i] & 1);
|
|
if (pcibs->bar[i] != obar) {
|
|
if ((pcibs->io_map_active && (pcibs->bar[i] & 1)) || (pcibs->memory_map_active && !(pcibs->bar[i] & 1))) {
|
|
config_changed = true;
|
|
}
|
|
}
|
|
} else {
|
|
pcibs->bar[i] = 0;
|
|
}
|
|
}
|
|
if (pcibs->board->pci_put_config) {
|
|
int off = addr & 0xff;
|
|
if (size == 4) {
|
|
pcibs->board->pci_put_config(off + 3, d[off + 0]);
|
|
pcibs->board->pci_put_config(off + 2, d[off + 1]);
|
|
pcibs->board->pci_put_config(off + 1, d[off + 2]);
|
|
pcibs->board->pci_put_config(off + 0, d[off + 3]);
|
|
} else if (size == 2) {
|
|
if (pcib->endian_swap_config < 0) {
|
|
pcibs->board->pci_put_config((off ^ 2) + 0, d[off + 0]);
|
|
pcibs->board->pci_put_config((off ^ 2) + 1, d[off + 1]);
|
|
} else if (pcib->endian_swap_config > 0) {
|
|
pcibs->board->pci_put_config(off + 0, d[off + 0]);
|
|
pcibs->board->pci_put_config(off + 1, d[off + 1]);
|
|
} else {
|
|
pcibs->board->pci_put_config(off + 0, d[off + 0]);
|
|
pcibs->board->pci_put_config(off + 1, d[off + 1]);
|
|
}
|
|
} else {
|
|
pcibs->board->pci_put_config(off + 0, d[off + 0]);
|
|
}
|
|
if ((off >= 0x10 && off < 0x10 + (MAX_PCI_BARS - 1) * 4) || (off >= 0x30 && off < 0x34)) {
|
|
int index;
|
|
if (off >= 0x30) {
|
|
index = MAX_PCI_BARS - 1;
|
|
} else {
|
|
index = (off - 0x10) / 4;
|
|
}
|
|
uae_u32 obar = pcibs->bar[index];
|
|
pcibs->bar[index] = pcibs->board->pci_get_config(off + 3) << 24;
|
|
pcibs->bar[index] |= pcibs->board->pci_get_config(off + 2) << 16;
|
|
pcibs->bar[index] |= pcibs->board->pci_get_config(off + 1) << 8;
|
|
pcibs->bar[index] |= pcibs->board->pci_get_config(off + 0) << 0;
|
|
if (d[off + 0] == 0xff && d[off + 1] == 0xff && d[off + 2] == 0xff && (d[off + 3] & 0xfe) == 0xfe) {
|
|
pcibs->bar_size[index] = ~((pcibs->bar[index] & ~1) - 1);
|
|
if (pcibs->board->config->bars[index] & 1) {
|
|
pcibs->bar_size[index] |= 1;
|
|
}
|
|
}
|
|
if (pcibs->bar[index] != obar) {
|
|
if ((pcibs->io_map_active && (pcibs->bar[index] & 1)) || (pcibs->memory_map_active && !(pcibs->bar[index] & 1))) {
|
|
config_changed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
} else {
|
|
create_config_data(pcibs);
|
|
}
|
|
bool o_io = pcibs->io_map_active;
|
|
bool o_mm = pcibs->memory_map_active;
|
|
uae_u8 map;
|
|
if (pcibs->board->pci_get_config) {
|
|
map = pcibs->board->pci_get_config(7 ^ 3);
|
|
} else {
|
|
map = d[7];
|
|
}
|
|
pcibs->io_map_active = (map & 1) != 0;
|
|
pcibs->memory_map_active = (map & 2) != 0;
|
|
map_pci_banks(pcibs, 1, pcibs->io_map_active);
|
|
map_pci_banks(pcibs, 0, pcibs->memory_map_active);
|
|
if ((o_io != pcibs->io_map_active || o_mm != pcibs->memory_map_active || config_changed) && pcibs->board->pci_change_config) {
|
|
pcibs->board->pci_change_config(pcibs);
|
|
}
|
|
}
|
|
|
|
|
|
static uaecptr beswap(int endianswap, uaecptr addr)
|
|
{
|
|
if (endianswap > 0)
|
|
return addr ^ 3;
|
|
return addr;
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 pci_config_lget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xffffffff;
|
|
int endianswap;
|
|
uae_u8 *config = get_pci_config(addr, -4, 0, &endianswap);
|
|
if (config) {
|
|
uae_u32 offset = addr & 0xff;
|
|
if (!endianswap) {
|
|
v = config[offset + 0] << 24;
|
|
v |= config[offset + 1] << 16;
|
|
v |= config[offset + 2] << 8;
|
|
v |= config[offset + 3] << 0;
|
|
} else {
|
|
v = config[offset + 3] << 24;
|
|
v |= config[offset + 2] << 16;
|
|
v |= config[offset + 1] << 8;
|
|
v |= config[offset + 0] << 0;
|
|
}
|
|
#if PCI_DEBUG_CONFIG
|
|
write_log(_T("-> %08x\n"), v);
|
|
#endif
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_config_wget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xffff;
|
|
int endianswap;
|
|
uae_u8 *config = get_pci_config(addr, -2, 0, &endianswap);
|
|
if (config) {
|
|
uae_u32 offset = addr & 0xff;
|
|
if (!endianswap) {
|
|
v = config[offset + 0] << 8;
|
|
v |= config[offset + 1] << 0;
|
|
} else {
|
|
v = config[(offset ^ (endianswap > 0 ? 2 : 0)) + 1] << 8;
|
|
v |= config[(offset ^ (endianswap > 0 ? 2 : 0)) + 0] << 0;
|
|
}
|
|
#if PCI_DEBUG_CONFIG
|
|
write_log(_T("-> %04x\n"), v);
|
|
#endif
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_config_bget(uaecptr addr)
|
|
{
|
|
uae_u8 v = 0xff;
|
|
int endianswap;
|
|
uae_u8 *config = get_pci_config(addr, -1, 0, &endianswap);
|
|
if (config) {
|
|
uae_u32 offset = addr & 0xff;
|
|
if (!endianswap) {
|
|
v = config[offset + 0];
|
|
} else {
|
|
v = config[beswap(endianswap, offset)];
|
|
}
|
|
#if PCI_DEBUG_CONFIG
|
|
write_log(_T("-> %02x\n"), v);
|
|
#endif
|
|
}
|
|
return v;
|
|
}
|
|
static void REGPARAM2 pci_config_lput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
uae_u8 *config = get_pci_config(addr, 4, b, &endianswap);
|
|
if (config) {
|
|
uae_u32 offset = addr & 0xff;
|
|
if (!endianswap) {
|
|
config[offset + 0] = b >> 24;
|
|
config[offset + 1] = b >> 16;
|
|
config[offset + 2] = b >> 8;
|
|
config[offset + 3] = b >> 0;
|
|
} else {
|
|
config[offset + 3] = b >> 24;
|
|
config[offset + 2] = b >> 16;
|
|
config[offset + 1] = b >> 8;
|
|
config[offset + 0] = b >> 0;
|
|
}
|
|
update_pci_config(addr, 4);
|
|
}
|
|
}
|
|
static void REGPARAM2 pci_config_wput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
uae_u8 *config = get_pci_config(addr, 2, b, &endianswap);
|
|
if (config) {
|
|
uae_u32 offset = addr & 0xff;
|
|
if (!endianswap) {
|
|
config[offset + 0] = b >> 8;
|
|
config[offset + 1] = b >> 0;
|
|
} else {
|
|
config[(offset ^ (endianswap > 0 ? 2 : 0)) + 1] = b >> 8;
|
|
config[(offset ^ (endianswap > 0 ? 2 : 0)) + 0] = b >> 0;
|
|
}
|
|
update_pci_config(addr, 2);
|
|
}
|
|
}
|
|
static void REGPARAM2 pci_config_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
uae_u8 *config = get_pci_config(addr, 1, b, &endianswap);
|
|
if (config) {
|
|
uae_u32 offset = addr & 0xff;
|
|
if (!endianswap) {
|
|
config[offset] = b;
|
|
} else {
|
|
config[beswap(endianswap, offset)] = b;
|
|
}
|
|
update_pci_config(addr, 1);
|
|
}
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 pci_io_lget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xffffffff;
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_io(&addr, &pcibs, &endianswap, 4);
|
|
if (a && a->lget) {
|
|
v = a->lget(pcibs, addr);
|
|
#if PCI_DEBUG_IO
|
|
write_log(_T("-> %08x\n"), v);
|
|
#endif
|
|
if (endianswap)
|
|
v = do_byteswap_32(v);
|
|
#if PCI_DEBUG_IO
|
|
} else {
|
|
write_log(_T("-> X\n"), v);
|
|
#endif
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_io_wget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xffff;
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_io(&addr, &pcibs, &endianswap, 2);
|
|
if (a && a->wget) {
|
|
if (endianswap) {
|
|
v = a->wget(pcibs, addr ^ (endianswap > 0 ? 2 : 0));
|
|
#if PCI_DEBUG_IO > 1
|
|
write_log(_T("-> %04x\n"), v);
|
|
#endif
|
|
v = do_byteswap_16(v);
|
|
} else {
|
|
v = a->wget(pcibs, addr);
|
|
#if PCI_DEBUG_IO > 1
|
|
write_log(_T("-> %04x\n"), v);
|
|
#endif
|
|
}
|
|
#if PCI_DEBUG_IO
|
|
} else {
|
|
write_log(_T("!-> %02x\n"), v);
|
|
#endif
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_io_bget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xff;
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_io(&addr, &pcibs, &endianswap, 1);
|
|
if (a && a->bget) {
|
|
if (endianswap) {
|
|
v = a->bget(pcibs, beswap(endianswap, addr));
|
|
#if PCI_DEBUG_IO > 1
|
|
write_log(_T("-> %02x\n"), v);
|
|
#endif
|
|
} else {
|
|
v = a->bget(pcibs, addr);
|
|
#if PCI_DEBUG_IO > 1
|
|
write_log(_T("-> %02x\n"), v);
|
|
#endif
|
|
}
|
|
#if PCI_DEBUG_IO
|
|
} else {
|
|
write_log(_T("!-> %02x"), v);
|
|
#endif
|
|
}
|
|
return v;
|
|
}
|
|
static void REGPARAM2 pci_io_lput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
uaecptr addr2 = addr;
|
|
const pci_addrbank *a = get_pci_io(&addr, &pcibs, &endianswap, -4);
|
|
if (a) {
|
|
#if PCI_DEBUG_IO > 1
|
|
write_log(_T("pci_io_lput %08x = %08x = %08x\n"), addr, addr2, b);
|
|
#endif
|
|
if (a->lput) {
|
|
if (endianswap)
|
|
b = do_byteswap_32(b);
|
|
a->lput(pcibs, addr, b);
|
|
}
|
|
#if PCI_DEBUG_IO_MISS
|
|
} else {
|
|
write_log(_T("pci_io_lput %08x\n"), addr);
|
|
#endif
|
|
}
|
|
#if PCI_DEBUG_IO
|
|
write_log(_T("<- %08x\n"), b);
|
|
#endif
|
|
}
|
|
static void REGPARAM2 pci_io_wput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_io(&addr, &pcibs, &endianswap, -2);
|
|
if (a) {
|
|
if (a->wput) {
|
|
if (endianswap) {
|
|
b = do_byteswap_16(b);
|
|
a->wput(pcibs, addr ^ (endianswap > 0 ? 2 : 0), b);
|
|
} else {
|
|
a->wput(pcibs, addr, b);
|
|
}
|
|
}
|
|
#if PCI_DEBUG_IO_MISS
|
|
} else {
|
|
write_log(_T("pci_io_wput %08x\n"), addr);
|
|
#endif
|
|
}
|
|
#if PCI_DEBUG_IO
|
|
write_log(_T("<- %04x\n"), b);
|
|
#endif
|
|
}
|
|
static void REGPARAM2 pci_io_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_io(&addr, &pcibs, &endianswap, -1);
|
|
if (a) {
|
|
if (a->bput) {
|
|
if (endianswap) {
|
|
a->bput(pcibs, beswap(endianswap, addr), b);
|
|
} else {
|
|
a->bput(pcibs, addr, b);
|
|
}
|
|
}
|
|
#if PCI_DEBUG_IO_MISS
|
|
} else {
|
|
write_log(_T("pci_io_bput %08x\n"), addr);
|
|
#endif
|
|
}
|
|
#if PCI_DEBUG_IO
|
|
write_log(_T("<- %02x\n"), b);
|
|
#endif
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 pci_mem_lget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xffffffff;
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_mem(&addr, &pcibs, &endianswap);
|
|
if (a && a->lget) {
|
|
v = a->lget(pcibs, addr);
|
|
if (endianswap)
|
|
v = do_byteswap_32(v);
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_mem_wget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xffff;
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_mem(&addr, &pcibs, &endianswap);
|
|
if (a && a->wget) {
|
|
if (endianswap) {
|
|
v = a->wget(pcibs, addr ^ (endianswap > 0 ? 2 : 0));
|
|
v = do_byteswap_16(v);
|
|
} else {
|
|
v = a->wget(pcibs, addr);
|
|
}
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_mem_bget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xff;
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_mem(&addr, &pcibs, &endianswap);
|
|
if (a) {
|
|
if (a->bget) {
|
|
if (endianswap) {
|
|
v = a->bget(pcibs, beswap(endianswap, addr));
|
|
} else {
|
|
v = a->bget(pcibs, addr);
|
|
}
|
|
}
|
|
#if PCI_DEBUG_IO_MISS
|
|
} else {
|
|
write_log(_T("pci_mem_bget %08x\n", addr));
|
|
#endif
|
|
}
|
|
return v;
|
|
}
|
|
static void REGPARAM2 pci_mem_lput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
uaecptr addr2 = addr;
|
|
const pci_addrbank *a = get_pci_mem(&addr, &pcibs, &endianswap);
|
|
#if PCI_DEBUG_IO > 1
|
|
write_log(_T("pci_mem_lput %08x = %08x = %08x\n"), addr, addr2, b);
|
|
#endif
|
|
if (a) {
|
|
if (a->lput) {
|
|
if (endianswap)
|
|
b = do_byteswap_32(b);
|
|
a->lput(pcibs, addr, b);
|
|
}
|
|
#if PCI_DEBUG_IO_MISS
|
|
} else {
|
|
write_log(_T("pci_mem_lput %08x\n"), addr);
|
|
#endif
|
|
}
|
|
}
|
|
static void REGPARAM2 pci_mem_wput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_mem(&addr, &pcibs, &endianswap);
|
|
if (a) {
|
|
if (a->wput) {
|
|
if (endianswap) {
|
|
b = do_byteswap_16(b);
|
|
a->wput(pcibs, addr ^ (endianswap > 0 ? 2 : 0), b);
|
|
} else {
|
|
a->wput(pcibs, addr, b);
|
|
}
|
|
}
|
|
#if PCI_DEBUG_IO_MISS
|
|
} else {
|
|
write_log(_T("pci_mem_wput %08x\n"), addr);
|
|
#endif
|
|
}
|
|
}
|
|
static void REGPARAM2 pci_mem_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
int endianswap;
|
|
struct pci_board_state *pcibs;
|
|
const pci_addrbank *a = get_pci_mem(&addr, &pcibs, &endianswap);
|
|
if (a) {
|
|
if (a->bput) {
|
|
if (endianswap) {
|
|
a->bput(pcibs, beswap(endianswap, addr), b);
|
|
} else {
|
|
a->bput(pcibs, addr, b);
|
|
}
|
|
}
|
|
#if PCI_DEBUG_IO
|
|
} else {
|
|
write_log(_T("pci_mem_bput %08x\n"), addr);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 pci_bridge_lget(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0;
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return v;
|
|
if (pcib == bridges[PCI_BRIDGE_GREX] || pcib == bridges[PCI_BRIDGE_XVISION]) {
|
|
int reg = (addr & 0xf0) >> 4;
|
|
switch(reg)
|
|
{
|
|
case 0:
|
|
v = pcib->endian_swap_io ? 2 : 0;
|
|
v |= pcib->config[0];
|
|
if (pcib == bridges[PCI_BRIDGE_GREX])
|
|
v |= 0x02000000;
|
|
if (!pcib->irq)
|
|
v |= 0x80000000;
|
|
if (!pcib->intena)
|
|
v |= 0x00000020;
|
|
break;
|
|
case 1:
|
|
v = pcib->intena ? 1 : 0;
|
|
break;
|
|
case 2:
|
|
break;
|
|
case 3:
|
|
break;
|
|
case 4:
|
|
break;
|
|
}
|
|
}
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_lget %08x=%08x PC=%08x\n"), addr, v, M68K_GETPC);
|
|
#endif
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_bridge_wget(uaecptr addr)
|
|
{
|
|
uae_u16 v = 0;
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_wget %08x PC=%08x\n"), addr, M68K_GETPC);
|
|
#endif
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_bridge_bget(uaecptr addr)
|
|
{
|
|
uae_u8 v = 0;
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return v;
|
|
if (!pcib->configured) {
|
|
uaecptr offset = addr & 65535;
|
|
if (offset >= sizeof pcib->acmemory)
|
|
return 0;
|
|
return pcib->acmemory[offset];
|
|
|
|
} else if (pcib == bridges[PCI_BRIDGE_WILDFIRE]) {
|
|
int offset = addr & 15;
|
|
v = pcib->config[offset / 4];
|
|
}
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_bget %08x %02x PC=%08x\n"), addr, v, M68K_GETPC);
|
|
#endif
|
|
return v;
|
|
}
|
|
static void REGPARAM2 pci_bridge_lput(uaecptr addr, uae_u32 b)
|
|
{
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_lput %08x %08x PC=%08x\n"), addr, b, M68K_GETPC);
|
|
#endif
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return;
|
|
if (pcib == bridges[PCI_BRIDGE_GREX] || pcib == bridges[PCI_BRIDGE_XVISION]) {
|
|
int reg = (addr & 0xf0) >> 4;
|
|
switch (reg)
|
|
{
|
|
case 0:
|
|
pcib->endian_swap_memory = pcib->endian_swap_io = (b & 2) != 0 ? -1 : 0;
|
|
break;
|
|
case 1:
|
|
pcib->intena = (b & 1) ? 0xff : 0x00;
|
|
break;
|
|
case 3:
|
|
pcib->config[0] = b & 1;
|
|
pcib->endian_swap_memory = pcib->endian_swap_io = (b & 2) != 0 ? -1 : 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
static void REGPARAM2 pci_bridge_wput(uaecptr addr, uae_u32 b)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return;
|
|
if (!pcib->configured) {
|
|
uaecptr offset = addr & 65535;
|
|
if (pcib->bank_zorro == 3) {
|
|
switch (offset)
|
|
{
|
|
case 0x44:
|
|
if (pcib->type == PCI_BRIDGE_PROMETHEUS) {
|
|
if (validate_banks_z3(&pci_io_bank, (expamem_board_pointer) >> 16, expamem_board_size >> 16)) {
|
|
map_banks_z3(&pci_io_bank, (expamem_board_pointer) >> 16, 0xf0000 >> 16);
|
|
map_banks_z3(&pci_mem_bank, (expamem_board_pointer + 0x100000) >> 16, (511 * 1024 * 1024) >> 16);
|
|
map_banks_z3(&pci_config_bank, (expamem_board_pointer + 0xf0000) >> 16, 0x10000 >> 16);
|
|
}
|
|
pcib->baseaddress_offset = pcib->baseaddress;
|
|
pcib->io_offset = expamem_board_pointer;
|
|
pcib->memory_start_offset = expamem_board_pointer;
|
|
} else if (pcib->type == PCI_BRIDGE_MEDIATOR) {
|
|
map_banks_z3(&pci_mem_bank, expamem_board_pointer >> 16, expamem_board_size >> 16);
|
|
pcib->baseaddress_offset = 0;
|
|
}
|
|
pcib->baseaddress = expamem_board_pointer;
|
|
pcib->board_size = expamem_board_size;
|
|
pcib->baseaddress_end = pcib->baseaddress + pcib->board_size;
|
|
pcib->configured = 1;
|
|
expamem_next(pcib->bank, NULL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_wput %08x %04x PC=%08x\n"), addr, b & 0xffff, M68K_GETPC);
|
|
#endif
|
|
}
|
|
static void REGPARAM2 pci_bridge_bput(uaecptr addr, uae_u32 b)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return;
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_bput %08x %02x PC=%08x\n"), addr, b & 0xff, M68K_GETPC);
|
|
#endif
|
|
if (!pcib->configured) {
|
|
uaecptr offset = addr & 65535;
|
|
if (pcib->bank_zorro == 2) {
|
|
switch (offset)
|
|
{
|
|
case 0x48:
|
|
// Mediator 1200
|
|
map_banks_z2(&pci_mem_bank, b, expamem_board_size >> 16);
|
|
pcib->baseaddress = b << 16;
|
|
pcib->board_size = expamem_board_size;
|
|
pcib->baseaddress_end = pcib->baseaddress + pcib->board_size;
|
|
pcib->configured = 1;
|
|
expamem_next(pcib->bank, NULL);
|
|
break;
|
|
case 0x4c:
|
|
pcib->configured = -1;
|
|
expamem_shutup(pcib->bank);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (pcib == bridges[PCI_BRIDGE_WILDFIRE]) {
|
|
addr &= 15;
|
|
if (addr == 0) {
|
|
cpuboard_set_flash_unlocked((b & 4) != 0);
|
|
} else if (addr == 8) {
|
|
pcib->config[2] = b;
|
|
if (b & 1) {
|
|
write_log(_T("Wildfire fallback CPU mode!\n"));
|
|
cpu_fallback(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void mediator_set_window_offset(struct pci_bridge *pcib, uae_u16 v)
|
|
{
|
|
uae_u32 offset;
|
|
v = do_byteswap_16(v);
|
|
if (pcib->bank_2_zorro == 3) {
|
|
// 4000
|
|
uae_u8 mask = pcib->board_size == 256 * 1024 * 1024 ? 0xf0 : 0xe0;
|
|
pcib->window = v & mask;
|
|
pcib->memory_start_offset = pcib->window << 18;
|
|
offset = pcib->memory_start_offset;
|
|
} else {
|
|
// 1200
|
|
uae_u16 mask = pcib->board_size == 4 * 1024 * 1024 ? 0xffc0 : 0xff80;
|
|
pcib->window = v & mask;
|
|
pcib->memory_start_offset = pcib->window << 16;
|
|
offset = pcib->memory_start_offset;
|
|
pcib->memory_start_offset -= pcib->baseaddress;
|
|
pcib->memory_start_offset = 0 - pcib->memory_start_offset;
|
|
}
|
|
#if 0
|
|
write_log(_T"Mediator window: %08x %04x PC=%08x\n"), offset, v, M68K_GETPC);
|
|
#endif
|
|
}
|
|
|
|
static uae_u32 REGPARAM2 pci_bridge_bget_2(uaecptr addr)
|
|
{
|
|
uae_u8 v = 0xff;
|
|
struct pci_bridge *pcib = get_pci_bridge_2(addr);
|
|
if (!pcib)
|
|
return v;
|
|
if (!pcib->configured_2) {
|
|
uaecptr offset = addr & 65535;
|
|
if (offset >= sizeof pcib->acmemory_2)
|
|
return 0;
|
|
return pcib->acmemory_2[offset];
|
|
} else {
|
|
if (pcib->bank_2_zorro == 3) {
|
|
int offset = addr & 0x7fffff;
|
|
if (offset == 0) {
|
|
v = (uae_u8)pcib->window;
|
|
v |= 8; // id
|
|
}
|
|
if (offset == 4) {
|
|
v = pcib->irq | (pcib->intena << 4);
|
|
}
|
|
} else {
|
|
int offset = addr & 0x1f;
|
|
v = 0;
|
|
if (offset == 2) {
|
|
v = 0x20;
|
|
} else if (offset == 11) {
|
|
v = pcib->irq | (pcib->intena << 4);
|
|
}
|
|
}
|
|
}
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_bget_2 %08x %02x PC=%08x\n"), addr, v, M68K_GETPC);
|
|
#endif
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_bridge_wget_2(uaecptr addr)
|
|
{
|
|
uae_u16 v = 0xffff;
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_wget_2 %08x PC=%08x\n"), addr, M68K_GETPC);
|
|
#endif
|
|
struct pci_bridge *pcib = get_pci_bridge_2(addr);
|
|
if (!pcib)
|
|
return v;
|
|
if (pcib->configured_2) {
|
|
if (pcib->bank_2_zorro == 2) {
|
|
int offset = addr & 0x1f;
|
|
v = 0;
|
|
if (offset == 2) {
|
|
v = 0x2000 | do_byteswap_16(pcib->window); // id + window
|
|
} else if (offset == 10) {
|
|
v = pcib->irq | (pcib->intena << 4);
|
|
}
|
|
}
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 pci_bridge_lget_2(uaecptr addr)
|
|
{
|
|
uae_u32 v = 0xffffffff;
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_lget_2 %08x PC=%08x\n"), addr, M68K_GETPC);
|
|
#endif
|
|
struct pci_bridge *pcib = get_pci_bridge_2(addr);
|
|
if (!pcib)
|
|
return v;
|
|
v = pci_bridge_wget_2(addr + 0) << 16;
|
|
v |= pci_bridge_wget_2(addr + 2);
|
|
return v;
|
|
}
|
|
|
|
static void REGPARAM2 pci_bridge_bput_2(uaecptr addr, uae_u32 b)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge_2(addr);
|
|
if (!pcib)
|
|
return;
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_bput_2 %08x %02x PC=%08x\n"), addr, b & 0xff, M68K_GETPC);
|
|
#endif
|
|
if (!pcib->configured_2) {
|
|
uaecptr offset = addr & 65535;
|
|
if (pcib->bank_2_zorro == 2) {
|
|
switch (offset)
|
|
{
|
|
case 0x48:
|
|
// Mediator 1200 IO
|
|
pcib->baseaddress_2 = b << 16;
|
|
pcib->baseaddress_end_2 = (b << 16) + expamem_board_size;
|
|
map_banks_z2(pcib->bank_2, pcib->baseaddress_2 >> 16, 0x10000 >> 16);
|
|
map_banks_z2(&dummy_bank, (pcib->baseaddress_2 + 0x10000) >> 16, (expamem_board_size - 0x10000) >> 16);
|
|
pcib->configured_2 = 1;
|
|
pcib->io_offset = pcib->baseaddress_2 + 0x10000;
|
|
expamem_next(pcib->bank_2, NULL);
|
|
break;
|
|
case 0x4c:
|
|
pcib->configured_2 = -1;
|
|
expamem_shutup(pcib->bank_2);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (pcib->bank_2_zorro == 2) {
|
|
// Mediator 1200
|
|
int offset = addr & 0xffff;
|
|
if (offset == 7) {
|
|
// config/io mapping
|
|
if (b & 0x20) {
|
|
map_banks_z2(&dummy_bank, (pcib->baseaddress_2 + 0x10000) >> 16, 0x10000 >> 16);
|
|
if (b & 0x80) {
|
|
map_banks_z2(&pci_config_bank, (pcib->baseaddress_2 + 0x10000) >> 16, 0x10000 >> 16);
|
|
} else {
|
|
map_banks_z2(&pci_io_bank, (pcib->baseaddress_2 + 0x10000) >> 16, 0x10000 >> 16);
|
|
}
|
|
} else {
|
|
map_banks_z2(&dummy_bank, (pcib->baseaddress_2 + 0x10000) >> 16, 0x10000 >> 16);
|
|
}
|
|
memory_map_dump();
|
|
} else if (offset == 11) {
|
|
pcib->intena = b >> 4;
|
|
} else if (offset == 0x40) {
|
|
// power off
|
|
uae_quit();
|
|
}
|
|
}
|
|
if (pcib->bank_2_zorro == 3) {
|
|
// Mediator 4000 window
|
|
int offset = addr & 0x7fffff;
|
|
if (offset == 0) {
|
|
mediator_set_window_offset(pcib, b);
|
|
} else if (offset == 4) {
|
|
pcib->intena = b >> 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
static void REGPARAM2 pci_bridge_wput_2(uaecptr addr, uae_u32 b)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge_2(addr);
|
|
if (!pcib)
|
|
return;
|
|
if (!pcib->configured_2) {
|
|
uaecptr offset = addr & 65535;
|
|
if (pcib->bank_2_zorro == 3) {
|
|
switch (offset)
|
|
{
|
|
case 0x44:
|
|
// Mediator 4000 IO
|
|
if (validate_banks_z3(&pci_io_bank, expamem_board_pointer >> 16, expamem_board_size >> 16)) {
|
|
map_banks(pcib->bank_2, expamem_board_pointer >> 16, 0x800000 >> 16, 0);
|
|
map_banks(&pci_config_bank, (expamem_board_pointer + 0x800000) >> 16, 0x400000 >> 16, 0);
|
|
map_banks(&pci_io_bank, (expamem_board_pointer + 0xc00000) >> 16, 0x400000 >> 16, 0);
|
|
}
|
|
pcib->baseaddress_2 = expamem_board_pointer;
|
|
pcib->baseaddress_end_2 = expamem_board_pointer + expamem_board_size;
|
|
pcib->board_size_2 = expamem_board_size;
|
|
pcib->configured_2 = 1;
|
|
pcib->io_offset = (expamem_board_pointer + 0xc00000);
|
|
expamem_next(pcib->bank, NULL);
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
if (pcib->bank_2_zorro == 2) {
|
|
// Mediator 1200 window
|
|
int offset = addr & 0xffff;
|
|
if (offset == 2) {
|
|
mediator_set_window_offset(pcib, b);
|
|
}
|
|
}
|
|
}
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_wput_2 %08x %04x PC=%08x\n"), addr, b & 0xffff, M68K_GETPC);
|
|
#endif
|
|
}
|
|
static void REGPARAM2 pci_bridge_lput_2(uaecptr addr, uae_u32 b)
|
|
{
|
|
#if PCI_DEBUG_BRIDGE
|
|
write_log(_T("pci_bridge_lput_2 %08x %08x PC=%08x\n"), addr, b, M68K_GETPC);
|
|
#endif
|
|
struct pci_bridge *pcib = get_pci_bridge_2(addr);
|
|
if (!pcib)
|
|
return;
|
|
pci_bridge_wput_2(addr + 0, b >> 16);
|
|
pci_bridge_wput_2(addr + 2, b >> 0);
|
|
}
|
|
|
|
|
|
addrbank pci_config_bank = {
|
|
pci_config_lget, pci_config_wget, pci_config_bget,
|
|
pci_config_lput, pci_config_wput, pci_config_bput,
|
|
default_xlate, default_check, NULL, NULL, _T("PCI CONFIG"),
|
|
pci_config_lget, pci_config_wget,
|
|
ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
|
|
};
|
|
addrbank pci_io_bank = {
|
|
pci_io_lget, pci_io_wget, pci_io_bget,
|
|
pci_io_lput, pci_io_wput, pci_io_bput,
|
|
default_xlate, default_check, NULL, NULL, _T("PCI IO"),
|
|
pci_io_lget, pci_io_wget,
|
|
ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
|
|
};
|
|
addrbank pci_mem_bank = {
|
|
pci_mem_lget, pci_mem_wget, pci_mem_bget,
|
|
pci_mem_lput, pci_mem_wput, pci_mem_bput,
|
|
default_xlate, default_check, NULL, NULL, _T("PCI MEMORY"),
|
|
pci_mem_lget, pci_mem_wget,
|
|
ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
|
|
};
|
|
addrbank pci_bridge_bank = {
|
|
pci_bridge_lget, pci_bridge_wget, pci_bridge_bget,
|
|
pci_bridge_lput, pci_bridge_wput, pci_bridge_bput,
|
|
default_xlate, default_check, NULL, NULL, _T("PCI BRIDGE"),
|
|
pci_bridge_lget, pci_bridge_wget,
|
|
ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
|
|
};
|
|
addrbank pci_bridge_bank_2 = {
|
|
pci_bridge_lget_2, pci_bridge_wget_2, pci_bridge_bget_2,
|
|
pci_bridge_lput_2, pci_bridge_wput_2, pci_bridge_bput_2,
|
|
default_xlate, default_check, NULL, NULL, _T("PCI BRIDGE #2"),
|
|
pci_bridge_lget_2, pci_bridge_wget_2,
|
|
ABFLAG_IO | ABFLAG_SAFE, S_READ, S_WRITE
|
|
};
|
|
|
|
static int validate_dma_last_board;
|
|
static int validate_dma_last_bridge;
|
|
|
|
static bool validate_pci_dma(struct pci_board_state *pcibs, uaecptr addr, int size, struct pci_board_state **pcibsp, int *bar)
|
|
{
|
|
struct pci_bridge *pcib = pcibs->bridge;
|
|
if (pcib->pcipcidma) {
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
struct pci_bridge *pcib = bridges[(i + validate_dma_last_bridge) % PCI_BRIDGE_MAX];
|
|
if (!pcib)
|
|
continue;
|
|
for (int j = 0; j < MAX_PCI_BOARDS; j++) {
|
|
struct pci_board_state *pcibs = &pcib->boards[(j + validate_dma_last_board) % MAX_PCI_BOARDS];
|
|
if (pcibs->board) {
|
|
for (int k = 0; k < MAX_PCI_BARS - 1; k++) {
|
|
if (pcibs->bar_enabled[k] && addr >= pcibs->bar[k] && addr < pcibs->bar[k] + pcibs->bar_size[k] && !(pcibs->bar_size[k] & 1)) {
|
|
if (pcibs->board->bars[k].bget && pcibs->board->bars[k].bput) {
|
|
*bar = k;
|
|
*pcibsp = pcibs;
|
|
validate_dma_last_board = j;
|
|
validate_dma_last_bridge = i;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
addrbank *ab = &get_mem_bank(addr);
|
|
if (ab == &dummy_bank)
|
|
return false;
|
|
if (pcib->pcipcidma) {
|
|
if (ab == &pci_mem_bank && &get_mem_bank(addr + size - 1) == &pci_mem_bank)
|
|
return true;
|
|
}
|
|
if (pcib->amigapicdma) {
|
|
if ((ab->flags & ABFLAG_RAM) && ab->check(addr, size))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void pci_write_dma(struct pci_board_state *pcibs, uaecptr addr, uae_u8 *p, int size)
|
|
{
|
|
struct pci_board_state *pcibs2 = NULL;
|
|
int bar;
|
|
if (validate_pci_dma(pcibs, addr, size, &pcibs2, &bar)) {
|
|
if (pcibs2) {
|
|
while (size > 0) {
|
|
pcibs2->board->bars[bar].bput(pcibs2, addr, *p++);
|
|
addr++;
|
|
size--;
|
|
}
|
|
} else {
|
|
while (size > 0) {
|
|
put_byte(addr, *p++);
|
|
addr++;
|
|
size--;
|
|
}
|
|
}
|
|
} else {
|
|
write_log(_T("pci_write_dma invalid address %08x, size %d\n"), addr, size);
|
|
while (size > 0) {
|
|
put_byte(addr, uaerand());
|
|
addr++;
|
|
size--;
|
|
}
|
|
}
|
|
}
|
|
void pci_read_dma(struct pci_board_state *pcibs, uaecptr addr, uae_u8 *p, int size)
|
|
{
|
|
struct pci_board_state *pcibs2 = NULL;
|
|
int bar;
|
|
if (validate_pci_dma(pcibs, addr, size, &pcibs2, &bar)) {
|
|
if (pcibs2) {
|
|
while (size > 0) {
|
|
*p++ = pcibs2->board->bars[bar].bget(pcibs2, addr);
|
|
addr++;
|
|
size--;
|
|
}
|
|
} else {
|
|
while (size > 0) {
|
|
*p++ = get_byte(addr);
|
|
addr++;
|
|
size--;
|
|
}
|
|
}
|
|
} else {
|
|
write_log(_T("pci_read_dma invalid address %08x, size %d\n"), addr, size);
|
|
while (size > 0) {
|
|
*p++ = uaerand() >> 4;
|
|
addr++;
|
|
size--;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pci_dump_out(const TCHAR *txt, int log)
|
|
{
|
|
if (log > 0)
|
|
write_log(_T("%s"), txt);
|
|
else if (log == 0)
|
|
console_out(txt);
|
|
}
|
|
|
|
static void pci_dump_memio_region(struct pci_bridge *pcib, uaecptr start, uaecptr end, int type, int log)
|
|
{
|
|
for (int i = 0; i < MAX_PCI_BOARDS; i++) {
|
|
struct pci_board_state *pcibs = &pcib->boards[i];
|
|
for (int j = 0; j < MAX_PCI_BARS; j++) {
|
|
if (pcibs->bar_size[j] && (pcibs->bar_start[j] || pcibs->bar_end[j]) && (pcibs->bar_size[j] & 1) == type) {
|
|
TCHAR txt[256];
|
|
_stprintf(txt, _T(" - %08X - %08X: BAR%d %s\n"), pcibs->bar_start[j], pcibs->bar_end[j], j, pcibs->board->label);
|
|
pci_dump_out(txt, log);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void pci_dump_region(addrbank *bank, uaecptr *start, uaecptr *end)
|
|
{
|
|
*start = 0;
|
|
*end = 0;
|
|
for (int i = 0; i < 65536 + 1; i++) {
|
|
addrbank *a = i < 65536 ? mem_banks[i] : NULL;
|
|
if (*start == 0 && a == bank)
|
|
*start = i << 16;
|
|
if (*start && a != bank) {
|
|
*end = i << 16;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void pci_dump(int log)
|
|
{
|
|
for (int i = 0; i < PCI_BRIDGE_MAX; i++) {
|
|
TCHAR txt[256];
|
|
uaecptr start, end;
|
|
struct pci_bridge *pcib = bridges[i];
|
|
if (!pcib)
|
|
continue;
|
|
_stprintf(txt, _T("PCI bridge '%s'\n"), pcib->label);
|
|
pci_dump_out(txt, log);
|
|
pci_dump_region(&pci_config_bank, &start, &end);
|
|
if (start) {
|
|
struct pci_board_state *oldpcibs = NULL;
|
|
int previdx = -1;
|
|
_stprintf(txt, _T("%08X - %08X: Configuration space\n"), start, end - 1);
|
|
pci_dump_out(txt, log);
|
|
while (start < end) {
|
|
struct pci_board_state *pcibs = get_pci_board_state_config(pcib, start);
|
|
if (pcibs && pcibs != oldpcibs) {
|
|
const struct pci_board *pci = pcibs->board;
|
|
if (pcibs->board) {
|
|
const struct pci_config *cfg = &pcibs->dynamic_config;
|
|
_stprintf(txt, _T(" - %08x Card %d/%d: [%04X/%04X] %s IO=%d MEM=%d\n"),
|
|
start, pcibs->slot, pcibs->func, cfg->vendor, cfg->device, pci->label,
|
|
pcibs->io_map_active, pcibs->memory_map_active);
|
|
} else {
|
|
int idx = pcib->get_index(start);
|
|
_stprintf(txt, _T(" - Slot %d: <none>\n"), idx & 0xff);
|
|
}
|
|
pci_dump_out(txt, log);
|
|
oldpcibs = pcibs;
|
|
}
|
|
start += 256;
|
|
}
|
|
}
|
|
pci_dump_region(&pci_io_bank, &start, &end);
|
|
if (start) {
|
|
_stprintf(txt, _T("%08X - %08X: IO space\n"), start, end - 1);
|
|
pci_dump_out(txt, log);
|
|
pci_dump_memio_region(pcib, start, end, 1, log);
|
|
}
|
|
pci_dump_region(&pci_mem_bank, &start, &end);
|
|
if (start) {
|
|
_stprintf(txt, _T("%08X - %08X: Memory space\n"), start, end - 1);
|
|
pci_dump_out(txt, log);
|
|
pci_dump_memio_region(pcib, start, end, 0, log);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int countbit(int mask)
|
|
{
|
|
int found = -1;
|
|
for (int i = 0; i < 15; i++) {
|
|
if (mask & (1 << i)) {
|
|
if (found >= 0)
|
|
return -1;
|
|
found = i;
|
|
}
|
|
}
|
|
return found;
|
|
}
|
|
|
|
/* DKB Wildfire */
|
|
|
|
#define WILDFIRE_CONFIG_MASK 32767
|
|
|
|
static void REGPARAM2 wildfire_bput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
|
|
{
|
|
// BAR6 = "ROM"
|
|
if (pcibs->selected_bar == 6) {
|
|
bridges[PCI_BRIDGE_WILDFIRE]->data[addr & WILDFIRE_CONFIG_MASK] = b;
|
|
} else {
|
|
ncr815_io_bput_wildfire(addr, b);
|
|
}
|
|
}
|
|
static void REGPARAM2 wildfire_wput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
|
|
{
|
|
if (pcibs->selected_bar == 6) {
|
|
bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 0) & WILDFIRE_CONFIG_MASK] = b >> 8;
|
|
bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 1) & WILDFIRE_CONFIG_MASK] = b;
|
|
} else {
|
|
ncr815_io_bput_wildfire(addr + 1, b >> 0);
|
|
ncr815_io_bput_wildfire(addr + 0, b >> 8);
|
|
}
|
|
}
|
|
static void REGPARAM2 wildfire_lput(struct pci_board_state *pcibs, uaecptr addr, uae_u32 b)
|
|
{
|
|
if (pcibs->selected_bar == 6) {
|
|
bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 0) & WILDFIRE_CONFIG_MASK] = b >> 24;
|
|
bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 1) & WILDFIRE_CONFIG_MASK] = b >> 16;
|
|
bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 2) & WILDFIRE_CONFIG_MASK] = b >> 8;
|
|
bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 3) & WILDFIRE_CONFIG_MASK] = b >> 0;
|
|
} else {
|
|
ncr815_io_bput_wildfire(addr + 3, b >> 0);
|
|
ncr815_io_bput_wildfire(addr + 2, b >> 8);
|
|
ncr815_io_bput_wildfire(addr + 1, b >> 16);
|
|
ncr815_io_bput_wildfire(addr + 0, b >> 24);
|
|
}
|
|
}
|
|
static uae_u32 REGPARAM2 wildfire_bget(struct pci_board_state *pcibs, uaecptr addr)
|
|
{
|
|
uae_u32 v = 0;
|
|
if (pcibs->selected_bar == 6) {
|
|
v = bridges[PCI_BRIDGE_WILDFIRE]->data[addr & WILDFIRE_CONFIG_MASK];
|
|
} else {
|
|
v = ncr815_io_bget_wildfire(addr);
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 wildfire_wget(struct pci_board_state *pcibs, uaecptr addr)
|
|
{
|
|
uae_u32 v = 0;
|
|
if (pcibs->selected_bar == 6) {
|
|
v = bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 0) & WILDFIRE_CONFIG_MASK] << 8;
|
|
v |= bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 1) & WILDFIRE_CONFIG_MASK];
|
|
} else {
|
|
v = ncr815_io_bget_wildfire(addr + 1) << 0;
|
|
v |= ncr815_io_bget_wildfire(addr + 0) << 8;
|
|
}
|
|
return v;
|
|
}
|
|
static uae_u32 REGPARAM2 wildfire_lget(struct pci_board_state *pcibs, uaecptr addr)
|
|
{
|
|
uae_u32 v = 0;
|
|
if (pcibs->selected_bar == 6) {
|
|
v = bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 0) & WILDFIRE_CONFIG_MASK] << 24;
|
|
v |= bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 1) & WILDFIRE_CONFIG_MASK] << 16;
|
|
v |= bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 2) & WILDFIRE_CONFIG_MASK] << 8;
|
|
v |= bridges[PCI_BRIDGE_WILDFIRE]->data[(addr + 3) & WILDFIRE_CONFIG_MASK];
|
|
} else {
|
|
v = ncr815_io_bget_wildfire(addr + 3) << 0;
|
|
v |= ncr815_io_bget_wildfire(addr + 2) << 8;
|
|
v |= ncr815_io_bget_wildfire(addr + 1) << 16;
|
|
v |= ncr815_io_bget_wildfire(addr + 0) << 24;
|
|
}
|
|
return v;
|
|
}
|
|
|
|
static int dkb_wildfire_get_index(uaecptr addr)
|
|
{
|
|
int idx = 0;
|
|
int slot = -1;
|
|
for (int i = 0x0800; i <= 0x10000000; i <<= 1, idx++) {
|
|
if (addr & i) {
|
|
if (slot >= 0)
|
|
return -1;
|
|
slot = idx;
|
|
}
|
|
}
|
|
if (slot > 5)
|
|
slot = -1;
|
|
return slot;
|
|
}
|
|
|
|
void pci_irq_callback(struct pci_board_state *pcibs, bool irq)
|
|
{
|
|
set_pci_irq(pcibs->bridge, pcibs, irq);
|
|
}
|
|
|
|
static const struct pci_config ncr_53c815_pci_config =
|
|
{
|
|
0x1000, 0x0004, 0, 0, 0, 0x010000, 0, 0, 0, 1, 0, 0, { 256 | 1, 1024 | 0, 0, 0, 0, 0, 32768 | 0 }
|
|
};
|
|
static const struct pci_board ncr_53c815_pci_board =
|
|
{
|
|
_T("NCR53C815"),
|
|
&ncr_53c815_pci_config, NULL, NULL, NULL, NULL,
|
|
{
|
|
{ wildfire_lget, wildfire_wget, wildfire_bget, wildfire_lput, wildfire_wput, wildfire_bput },
|
|
{ wildfire_lget, wildfire_wget, wildfire_bget, wildfire_lput, wildfire_wput, wildfire_bput },
|
|
{ NULL },
|
|
{ NULL },
|
|
{ NULL },
|
|
{ NULL },
|
|
{ wildfire_lget, wildfire_wget, wildfire_bget, wildfire_lput, wildfire_wput, wildfire_bput }
|
|
}
|
|
};
|
|
|
|
bool pci_validate_address(uaecptr addr, uae_u32 size, bool io)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return false;
|
|
const pci_addrbank *ab1 = NULL, *ab2 = NULL;
|
|
int endianswap1, endianswap2;
|
|
struct pci_board_state* pcibs;
|
|
uaecptr addr1 = addr, addr2 = addr + size - 1;
|
|
if (io) {
|
|
ab1 = get_pci_io(&addr1, &pcibs, &endianswap1, 4);
|
|
ab2 = get_pci_io(&addr2, &pcibs, &endianswap2, 4);
|
|
} else {
|
|
ab1 = get_pci_mem(&addr1, &pcibs, &endianswap1);
|
|
ab2 = get_pci_mem(&addr2, &pcibs, &endianswap2);
|
|
}
|
|
if (!ab1 || !ab2)
|
|
return false;
|
|
if (ab1 != ab2)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
static void add_pci_devices(struct pci_bridge *pcib, struct autoconfig_info *aci)
|
|
{
|
|
int slot = 0;
|
|
|
|
if (is_device_rom(&currprefs, ROMTYPE_NE2KPCI, 0) >= 0) {
|
|
pci_board_add(pcib, &ne2000_pci_board, slot++, 0, aci, NULL);
|
|
}
|
|
|
|
if (is_device_rom(&currprefs, ROMTYPE_FM801, 0) >= 0) {
|
|
pci_board_add(pcib, &fm801_pci_board, slot, 0, aci, NULL);
|
|
pci_board_add(pcib, &fm801_pci_board_func1, slot, 1, aci, NULL);
|
|
slot++;
|
|
}
|
|
|
|
if (is_device_rom(&currprefs, ROMTYPE_ES1370, 0) >= 0) {
|
|
pci_board_add(pcib, &es1370_pci_board, slot++, 0, aci, NULL);
|
|
}
|
|
}
|
|
|
|
static void pci_init(void)
|
|
{
|
|
device_add_reset(pci_reset);
|
|
device_add_rethink(pci_rethink);
|
|
device_add_exit(pci_free);
|
|
device_add_hsync(pci_hsync);
|
|
}
|
|
|
|
// Wildfire
|
|
|
|
void wildfire_ncr815_irq(int id, int v)
|
|
{
|
|
struct pci_board_state *pcibs = &bridges[PCI_BRIDGE_WILDFIRE]->boards[0];
|
|
set_pci_irq(bridges[PCI_BRIDGE_WILDFIRE], pcibs, v != 0);
|
|
}
|
|
|
|
bool dkb_wildfire_pci_init(struct autoconfig_info *aci)
|
|
{
|
|
struct pci_bridge *pcib = pci_bridge_alloc();
|
|
|
|
device_add_reset(pci_reset);
|
|
if (!aci->doinit) {
|
|
return true;
|
|
}
|
|
|
|
bridges[PCI_BRIDGE_WILDFIRE] = pcib;
|
|
pcib->label = _T("Wildfire");
|
|
pcib->endian_swap_config = 0;
|
|
pcib->endian_swap_io = 0;
|
|
pcib->endian_swap_memory = 0;
|
|
pcib->intena = 0xff; // controlled by bridge config bits, bit unknown.
|
|
pcib->intreq_mask = 0x2000;
|
|
pcib->get_index = dkb_wildfire_get_index;
|
|
pcib->baseaddress = 0x80000000;
|
|
pcib->baseaddress_end = 0xffffffff;
|
|
pcib->configured = -1;
|
|
pcib->pcipcidma = true;
|
|
pcib->amigapicdma = true;
|
|
pci_board_add(pcib, &ncr_53c815_pci_board, 0, 0, aci, NULL);
|
|
map_banks(&pci_config_bank, 0x80000000 >> 16, 0x10000000 >> 16, 0);
|
|
map_banks(&pci_mem_bank, 0x90000000 >> 16, 0x30000000 >> 16, 0);
|
|
map_banks(&pci_io_bank, 0xc0000000 >> 16, 0x30000000 >> 16, 0);
|
|
map_banks(&pci_bridge_bank, 0xffff0000 >> 16, 0x10000 >> 16, 0);
|
|
pcib->data = xcalloc(uae_u8, 32768);
|
|
aci->addrbank = &expamem_null;
|
|
pci_init();
|
|
return true;
|
|
}
|
|
|
|
// Prometheus: 44359/1
|
|
|
|
static const uae_u8 prometheus_autoconfig[16] = { 0x85, 0x01, 0x30, 0x00, 0xad, 0x47, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
static void ew(uae_u8 *acmemory, int addr, uae_u8 value)
|
|
{
|
|
if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) {
|
|
acmemory[addr] = (value & 0xf0);
|
|
acmemory[addr + 2] = (value & 0x0f) << 4;
|
|
} else {
|
|
acmemory[addr] = ~(value & 0xf0);
|
|
acmemory[addr + 2] = ~((value & 0x0f) << 4);
|
|
}
|
|
}
|
|
|
|
static int prometheus_get_index(uaecptr addr)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
|
|
addr -= pcib->baseaddress;
|
|
if ((addr & 0xffff0f00) != 0x000f0000)
|
|
return -1;
|
|
int slot = (addr & 0xf000) >> 13;
|
|
if (slot > 3)
|
|
return -1;
|
|
slot |= ((addr >> 8) & 7) << 8;
|
|
return slot;
|
|
}
|
|
|
|
static bool prometheus_pci_init(struct autoconfig_info *aci)
|
|
{
|
|
device_add_reset(pci_reset);
|
|
if (!aci->doinit) {
|
|
for (int i = 0; i < sizeof prometheus_autoconfig; i++) {
|
|
ew(aci->autoconfig_raw, i * 4, prometheus_autoconfig[i]);
|
|
}
|
|
return true;
|
|
}
|
|
struct romconfig *rc = aci->rc;
|
|
struct pci_bridge *pcib = pci_bridge_alloc_zorro(PCI_BRIDGE_PROMETHEUS, rc);
|
|
if (!pcib)
|
|
return false;
|
|
pcib->label = _T("Prometheus");
|
|
pcib->endian_swap_config = 1;
|
|
pcib->endian_swap_io = -1;
|
|
pcib->endian_swap_memory = -1;
|
|
pcib->intena = 0xff;
|
|
pcib->intreq_mask = 0x0008;
|
|
pcib->get_index = prometheus_get_index;
|
|
pcib->bank = &pci_bridge_bank;
|
|
pcib->bank_zorro = 3;
|
|
pcib->pcipcidma = true;
|
|
if (rc->device_settings & 1)
|
|
pcib->amigapicdma = true;
|
|
|
|
add_pci_devices(pcib, aci);
|
|
|
|
memset(pcib->acmemory, 0xff, sizeof pcib->acmemory);
|
|
for (int i = 0; i < sizeof prometheus_autoconfig; i++) {
|
|
ew(pcib->acmemory, i * 4, prometheus_autoconfig[i]);
|
|
}
|
|
aci->addrbank = pcib->bank;
|
|
pci_init();
|
|
return true;
|
|
}
|
|
|
|
// G-REX
|
|
|
|
static int grex_get_index(uaecptr addr)
|
|
{
|
|
int slot = -1;
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
|
|
if ((addr & 0xfffc1000) == 0xfffc0000) {
|
|
int v = (addr & 0x3f000) >> 13;
|
|
slot = countbit(v);
|
|
slot |= ((addr >> 8) & 7) << 8;
|
|
}
|
|
return slot;
|
|
}
|
|
|
|
static bool grex_pci_init(struct autoconfig_info *aci)
|
|
{
|
|
struct pci_bridge *pcib = pci_bridge_alloc();
|
|
|
|
aci->zorro = 0;
|
|
aci->parent_of_previous = true;
|
|
aci->start = 0x80000000;
|
|
aci->size = 0x80000000;
|
|
|
|
device_add_reset(pci_reset);
|
|
if (!aci->doinit) {
|
|
return true;
|
|
}
|
|
|
|
bridges[PCI_BRIDGE_GREX] = pcib;
|
|
pcib->label = _T("G-REX");
|
|
pcib->intena = 0;
|
|
pcib->intreq_mask = 0x0008;
|
|
pcib->get_index = grex_get_index;
|
|
pcib->baseaddress = 0x80000000;
|
|
pcib->baseaddress_end = 0xffffffff;
|
|
pcib->configured = -1;
|
|
pcib->pcipcidma = true;
|
|
pcib->amigapicdma = true;
|
|
|
|
add_pci_devices(pcib, aci);
|
|
|
|
map_banks(&pci_config_bank, 0xfffc0000 >> 16, 0x20000 >> 16, 0);
|
|
map_banks(&pci_mem_bank, 0x80000000 >> 16, 0x78000000 >> 16, 0);
|
|
map_banks(&pci_io_bank, 0xfffa0000 >> 16, 0x20000 >> 16, 0);
|
|
map_banks(&pci_bridge_bank, 0xfffe0000 >> 16, 0x10000 >> 16, 0);
|
|
pcib->io_offset = 0xfffa0000;
|
|
pci_init();
|
|
return true;
|
|
}
|
|
|
|
// CyberVision/BlizzardVision without VGA chip...
|
|
|
|
static int xvision_get_index(uaecptr addr)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if ((addr & 0xfffcf700) == 0xfffc0000)
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|
|
static bool cbvision(struct autoconfig_info *aci)
|
|
{
|
|
struct pci_bridge *pcib = pci_bridge_alloc();
|
|
|
|
bridges[PCI_BRIDGE_XVISION] = pcib;
|
|
pcib->label = _T("CBVision");
|
|
pcib->intena = 0;
|
|
pcib->intreq_mask = 0x0008;
|
|
pcib->get_index = xvision_get_index;
|
|
pcib->baseaddress = 0xe0000000;
|
|
pcib->baseaddress_end = 0xffffffff;
|
|
pcib->configured = -1;
|
|
pcib->pcipcidma = true;
|
|
pcib->amigapicdma = true;
|
|
|
|
map_banks(&pci_config_bank, 0xfffc0000 >> 16, 0x20000 >> 16, 0);
|
|
map_banks(&pci_mem_bank, 0xe0000000 >> 16, 0x10000000 >> 16, 0);
|
|
map_banks(&pci_io_bank, 0xfffa0000 >> 16, 0x20000 >> 16, 0);
|
|
map_banks(&pci_bridge_bank, 0xfffe0000 >> 16, 0x10000 >> 16, 0);
|
|
pcib->io_offset = 0xfffa0000;
|
|
aci->zorro = 0;
|
|
aci->parent_of_previous = true;
|
|
pci_init();
|
|
return true;
|
|
}
|
|
|
|
// Mediator
|
|
|
|
// Mediator 4000MK2
|
|
static const uae_u8 autoconfig_mediator_4000mk2_256m[16] = { 0x84,0xa1,0x20,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
static const uae_u8 autoconfig_mediator_4000mk2_512m[16] = { 0x85,0xa1,0x20,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
static const uae_u8 autoconfig_mediator_4000mk2_2[16] = { 0x88,0x21,0x20,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
|
|
// Mediator 1200 TX
|
|
static const uae_u8 autoconfig_mediator_1200tx_1[16] = { 0xca,0x3c,0x00,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
static const uae_u8 autoconfig_mediator_1200tx_2_4m[16] = { 0xc7,0xbc,0x00,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
static const uae_u8 autoconfig_mediator_1200tx_2_8m[16] = { 0xc0,0xbc,0x00,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
|
|
// Mediator 1200 SX
|
|
static const uae_u8 autoconfig_mediator_1200sx_1[16] = { 0xca,0x28,0x00,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
static const uae_u8 autoconfig_mediator_1200sx_2_4m[16] = { 0xc7,0xa8,0x00,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
static const uae_u8 autoconfig_mediator_1200sx_2_8m[16] = { 0xc0,0xa8,0x00,0x00,0x08,0x9e,0x00,0x00,0x00,0x00,0x00,0x00 };
|
|
|
|
// Mediator 1200
|
|
static const uae_u8 autoconfig_mediator_1200_1[16] = { 0xca, 0x20, 0x00, 0x00, 0x08, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
static const uae_u8 autoconfig_mediator_1200_2_4m[16] = { 0xcf, 0xa0, 0x00, 0x00, 0x08, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
static const uae_u8 autoconfig_mediator_1200_2_8m[16] = { 0xc8, 0xa0, 0x00, 0x00, 0x08, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
|
|
struct mediator_autoconfig
|
|
{
|
|
const uae_u8 *io;
|
|
const uae_u8 *mem_small;
|
|
const uae_u8 *mem_large;
|
|
};
|
|
|
|
#define MED_1200 0
|
|
#define MED_1200SX 1
|
|
#define MED_1200TX 2
|
|
#define MED_4000MK2 3
|
|
|
|
static struct mediator_autoconfig mediator_ac[] =
|
|
{
|
|
{ autoconfig_mediator_1200_1, autoconfig_mediator_1200_2_4m, autoconfig_mediator_1200_2_8m },
|
|
{ autoconfig_mediator_1200sx_1, autoconfig_mediator_1200sx_2_4m, autoconfig_mediator_1200sx_2_8m },
|
|
{ autoconfig_mediator_1200tx_1, autoconfig_mediator_1200tx_2_4m, autoconfig_mediator_1200tx_2_8m },
|
|
{ autoconfig_mediator_4000mk2_2, autoconfig_mediator_4000mk2_256m, autoconfig_mediator_4000mk2_512m }
|
|
};
|
|
|
|
|
|
static int mediator_get_index_1200(uaecptr addr)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return -1;
|
|
uae_u32 offset = addr - pcib->baseaddress_2;
|
|
if (offset < 0x10000)
|
|
return -1;
|
|
offset -= 0x10000;
|
|
int slot = offset / 0x800;
|
|
if (slot >= 6)
|
|
return -1;
|
|
slot |= ((offset >> 8) & 7) << 8;
|
|
return slot;
|
|
}
|
|
|
|
static int mediator_get_index_4000(uaecptr addr)
|
|
{
|
|
struct pci_bridge *pcib = get_pci_bridge(addr);
|
|
if (!pcib)
|
|
return -1;
|
|
uae_u32 offset = addr - pcib->baseaddress_2;
|
|
if (offset < 0x800000 || offset >= 0xc00000)
|
|
return -1;
|
|
offset -= 0x800000;
|
|
int slot = offset / 0x800;
|
|
if (slot >= 6)
|
|
return -1;
|
|
slot |= ((offset >> 8) & 7) << 8;
|
|
return slot;
|
|
}
|
|
|
|
static void mediator_pci_init_1200(struct pci_bridge *pcib)
|
|
{
|
|
pcib->label = _T("Mediator 1200");
|
|
pcib->endian_swap_config = -1;
|
|
pcib->endian_swap_io = -1;
|
|
pcib->endian_swap_memory = -1;
|
|
pcib->intena = 0;
|
|
pcib->intreq_mask = 0x0008;
|
|
pcib->get_index = mediator_get_index_1200;
|
|
pcib->bank = &pci_bridge_bank;
|
|
pcib->bank_2 = &pci_bridge_bank_2;
|
|
pcib->bank_zorro = 2;
|
|
pcib->bank_2_zorro = 2;
|
|
pcib->pcipcidma = true;
|
|
if (pcib->rc->device_settings & 1)
|
|
pcib->amigapicdma = true;
|
|
mediator_set_window_offset(pcib, 0);
|
|
}
|
|
|
|
static addrbank *mediator_pci_init_1200_1(struct autoconfig_info *aci, struct romconfig *rc, struct mediator_autoconfig *m_ac)
|
|
{
|
|
device_add_reset(pci_reset);
|
|
if (!aci->doinit) {
|
|
for (int i = 0; i < 16; i++) {
|
|
ew(aci->autoconfig_raw, i * 4, m_ac->io[i]);
|
|
}
|
|
return NULL;
|
|
}
|
|
struct pci_bridge *pcib;
|
|
if (!(rc->device_settings & 4)) {
|
|
// io first
|
|
pcib = pci_bridge_alloc_zorro(PCI_BRIDGE_MEDIATOR, rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
mediator_pci_init_1200(pcib);
|
|
add_pci_devices(pcib, aci);
|
|
} else {
|
|
pcib = pci_bridge_get_zorro(rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
}
|
|
memset(pcib->acmemory_2, 0xff, sizeof pcib->acmemory_2);
|
|
for (int i = 0; i < 16; i++) {
|
|
ew(pcib->acmemory_2, i * 4, m_ac->io[i]);
|
|
}
|
|
pci_init();
|
|
return &pci_bridge_bank_2;
|
|
}
|
|
|
|
static addrbank *mediator_pci_init_1200_2(struct autoconfig_info *aci, struct romconfig *rc, struct mediator_autoconfig *m_ac)
|
|
{
|
|
device_add_reset(pci_reset);
|
|
if (!aci->doinit) {
|
|
const uae_u8 *ac = (rc->device_settings & 2) ? m_ac->mem_large : m_ac->mem_small;
|
|
for (int i = 0; i < 16; i++) {
|
|
ew(aci->autoconfig_raw, i * 4, ac[i]);
|
|
}
|
|
return NULL;
|
|
}
|
|
struct pci_bridge *pcib;
|
|
if (!(rc->device_settings & 4)) {
|
|
// memory last
|
|
pcib = pci_bridge_get_zorro(rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
} else {
|
|
// memory first
|
|
pcib = pci_bridge_alloc_zorro(PCI_BRIDGE_MEDIATOR, rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
mediator_pci_init_1200(pcib);
|
|
add_pci_devices(pcib, aci);
|
|
}
|
|
memset(pcib->acmemory, 0xff, sizeof pcib->acmemory);
|
|
const uae_u8 *ac = (rc->device_settings & 2) ? m_ac->mem_large : m_ac->mem_small;
|
|
for (int i = 0; i < 16; i++) {
|
|
ew(pcib->acmemory, i * 4, ac[i]);
|
|
}
|
|
pci_init();
|
|
return &pci_bridge_bank;
|
|
}
|
|
|
|
static void mediator_pci_init_4000(struct pci_bridge *pcib)
|
|
{
|
|
pcib->label = _T("Mediator 4000");
|
|
pcib->endian_swap_config = -1;
|
|
pcib->endian_swap_io = -1;
|
|
pcib->endian_swap_memory = -1;
|
|
pcib->intena = 0;
|
|
pcib->intreq_mask = 0x0008;
|
|
pcib->get_index = mediator_get_index_4000;
|
|
pcib->bank = &pci_bridge_bank;
|
|
pcib->bank_2 = &pci_bridge_bank_2;
|
|
pcib->bank_zorro = 3;
|
|
pcib->bank_2_zorro = 3;
|
|
pcib->pcipcidma = true;
|
|
if (pcib->rc->device_settings & 1)
|
|
pcib->amigapicdma = true;
|
|
mediator_set_window_offset(pcib, 0);
|
|
}
|
|
|
|
static addrbank *mediator_pci_init_4000_1(struct autoconfig_info *aci, struct romconfig *rc, struct mediator_autoconfig *m_ac)
|
|
{
|
|
device_add_reset(pci_reset);
|
|
if (!aci->doinit) {
|
|
aci->autoconfigp = m_ac->io;
|
|
return &pci_bridge_bank_2;
|
|
}
|
|
struct pci_bridge *pcib;
|
|
if (!(rc->device_settings & 4)) {
|
|
// io first
|
|
pcib = pci_bridge_alloc_zorro(PCI_BRIDGE_MEDIATOR, rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
mediator_pci_init_4000(pcib);
|
|
add_pci_devices(pcib, aci);
|
|
} else {
|
|
pcib = pci_bridge_get_zorro(rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
}
|
|
memset(pcib->acmemory_2, 0xff, sizeof pcib->acmemory_2);
|
|
for (int i = 0; i < 16; i++) {
|
|
ew(pcib->acmemory_2, i * 4, m_ac->io[i]);
|
|
}
|
|
pci_init();
|
|
return &pci_bridge_bank_2;
|
|
}
|
|
static addrbank *mediator_pci_init_4000_2(struct autoconfig_info *aci, struct romconfig *rc, struct mediator_autoconfig *m_ac)
|
|
{
|
|
device_add_reset(pci_reset);
|
|
if (!aci->doinit) {
|
|
aci->autoconfigp = (rc->device_settings & 2) ? m_ac->mem_large : m_ac->mem_small;
|
|
return &pci_bridge_bank;
|
|
}
|
|
struct pci_bridge *pcib;
|
|
if (!(rc->device_settings & 4)) {
|
|
// memory last
|
|
pcib = pci_bridge_get_zorro(rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
} else {
|
|
// memory first
|
|
pcib = pci_bridge_alloc_zorro(PCI_BRIDGE_MEDIATOR, rc);
|
|
if (!pcib)
|
|
return &expamem_null;
|
|
|
|
mediator_pci_init_4000(pcib);
|
|
add_pci_devices(pcib, aci);
|
|
}
|
|
memset(pcib->acmemory, 0xff, sizeof pcib->acmemory);
|
|
const uae_u8 *ac = (rc->device_settings & 2) ? m_ac->mem_large : m_ac->mem_small;
|
|
for (int i = 0; i < 16; i++) {
|
|
ew(pcib->acmemory, i * 4, ac[i]);
|
|
}
|
|
pci_init();
|
|
return &pci_bridge_bank;
|
|
}
|
|
|
|
bool mediator_init(struct autoconfig_info *aci)
|
|
{
|
|
struct romconfig *rc = aci->rc;
|
|
struct mediator_autoconfig *ac;
|
|
switch (rc->subtype)
|
|
{
|
|
case 0:
|
|
ac = &mediator_ac[MED_1200];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_1200_2(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_1200_1(aci, rc, ac);
|
|
return true;
|
|
case 1:
|
|
ac = &mediator_ac[MED_1200SX];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_1200_2(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_1200_1(aci, rc, ac);
|
|
return true;
|
|
case 2:
|
|
ac = &mediator_ac[MED_1200TX];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_1200_2(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_1200_1(aci, rc, ac);
|
|
return true;
|
|
case 3:
|
|
ac = &mediator_ac[MED_4000MK2];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_4000_2(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_4000_1(aci, rc, ac);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool mediator_init2(struct autoconfig_info *aci)
|
|
{
|
|
struct romconfig *rc = aci->rc;
|
|
struct mediator_autoconfig *ac;
|
|
switch (rc->subtype)
|
|
{
|
|
case 0:
|
|
ac = &mediator_ac[MED_1200];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_1200_1(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_1200_2(aci, rc, ac);
|
|
return true;
|
|
case 1:
|
|
ac = &mediator_ac[MED_1200SX];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_1200_1(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_1200_2(aci, rc, ac);
|
|
return true;
|
|
case 2:
|
|
ac = &mediator_ac[MED_1200TX];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_1200_1(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_1200_2(aci, rc, ac);
|
|
return true;
|
|
case 3:
|
|
ac = &mediator_ac[MED_4000MK2];
|
|
if (rc->device_settings & 4)
|
|
aci->addrbank = mediator_pci_init_4000_1(aci, rc, ac);
|
|
else
|
|
aci->addrbank = mediator_pci_init_4000_2(aci, rc, ac);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool prometheus_init(struct autoconfig_info *aci)
|
|
{
|
|
return prometheus_pci_init(aci);
|
|
}
|
|
|
|
bool cbvision_init(struct autoconfig_info *aci)
|
|
{
|
|
return cbvision(aci);
|
|
}
|
|
|
|
bool grex_init(struct autoconfig_info *aci)
|
|
{
|
|
return grex_pci_init(aci);
|
|
}
|
|
|
|
bool pci_expansion_init(struct autoconfig_info *aci)
|
|
{
|
|
static const int parent[] = { ROMTYPE_GREX, ROMTYPE_MEDIATOR, ROMTYPE_PROMETHEUS, 0 };
|
|
aci->parent_romtype = parent;
|
|
aci->zorro = 0;
|
|
return true;
|
|
}
|