/* multibus.c: Multibus I simulator | |
Copyright (c) 2010, William A. Beech | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the "Software"), | |
to deal in the Software without restriction, including without limitation | |
the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
and/or sell copies of the Software, and to permit persons to whom the | |
Software is furnished to do so, subject to the following conditions: | |
The above copyright notice and this permission notice shall be included in | |
all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
WILLIAM A. BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
Except as contained in this notice, the name of William A. Beech shall not be | |
used in advertising or otherwise to promote the sale, use or other dealings | |
in this Software without prior written authorization from William A. Beech. | |
MODIFICATIONS: | |
?? ??? 10 - Original file. | |
16 Dec 12 - Modified to use isbc_80_10.cfg file to set base and size. | |
24 Apr 15 -- Modified to use simh_debug | |
NOTES: | |
This software was written by Bill Beech, Dec 2010, to allow emulation of Multibus | |
Computer Systems. | |
*/ | |
#include "system_defs.h" | |
int32 mbirq = 0; /* set no multibus interrupts */ | |
/* function prototypes */ | |
t_stat multibus_svc(UNIT *uptr); | |
t_stat multibus_reset(DEVICE *dptr); | |
void set_irq(int32 int_num); | |
void clr_irq(int32 int_num); | |
uint8 nulldev(t_bool io, uint8 data); | |
uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port, uint8 devnum); | |
t_stat multibus_reset (DEVICE *dptr); | |
uint8 multibus_get_mbyte(uint16 addr); | |
void multibus_put_mbyte(uint16 addr, uint8 val); | |
/* external function prototypes */ | |
extern t_stat SBC_reset(DEVICE *dptr); /* reset the iSBC80/10 emulator */ | |
extern uint8 isbc064_get_mbyte(uint16 addr); | |
extern void isbc064_put_mbyte(uint16 addr, uint8 val); | |
extern void set_cpuint(int32 int_num); | |
extern t_stat SBC_reset (DEVICE *dptr); | |
extern t_stat isbc064_reset (DEVICE *dptr); | |
extern t_stat isbc201_reset (DEVICE *dptr, uint16); | |
extern t_stat isbc202_reset (DEVICE *dptr, uint16); | |
extern t_stat zx200a_reset(DEVICE *dptr, uint16 base); | |
/* external globals */ | |
extern uint8 xack; /* XACK signal */ | |
extern int32 int_req; /* i8080 INT signal */ | |
extern int32 isbc201_fdcnum; | |
extern int32 isbc202_fdcnum; | |
extern int32 zx200a_fdcnum; | |
/* multibus Standard SIMH Device Data Structures */ | |
UNIT multibus_unit = { | |
UDATA (&multibus_svc, 0, 0), 20 | |
}; | |
REG multibus_reg[] = { | |
{ HRDATA (MBIRQ, mbirq, 32) }, | |
{ HRDATA (XACK, xack, 8) } | |
}; | |
DEBTAB multibus_debug[] = { | |
{ "ALL", DEBUG_all }, | |
{ "FLOW", DEBUG_flow }, | |
{ "READ", DEBUG_read }, | |
{ "WRITE", DEBUG_write }, | |
{ "LEV1", DEBUG_level1 }, | |
{ "LEV2", DEBUG_level2 }, | |
{ NULL } | |
}; | |
DEVICE multibus_dev = { | |
"MBIRQ", //name | |
&multibus_unit, //units | |
multibus_reg, //registers | |
NULL, //modifiers | |
1, //numunits | |
16, //aradix | |
16, //awidth | |
1, //aincr | |
16, //dradix | |
8, //dwidth | |
NULL, //examine | |
NULL, //deposit | |
&multibus_reset, //reset | |
NULL, //boot | |
NULL, //attach | |
NULL, //detach | |
NULL, //ctxt | |
DEV_DEBUG, //flags | |
0, //dctrl | |
multibus_debug, //debflags | |
NULL, //msize | |
NULL //lname | |
}; | |
/* Service routines to handle simulator functions */ | |
/* service routine - actually does the simulated interrupts */ | |
t_stat multibus_svc(UNIT *uptr) | |
{ | |
switch (mbirq) { | |
case INT_1: | |
set_cpuint(INT_R); | |
clr_irq(SBC202_INT); /***** bad, bad, bad! */ | |
// sim_printf("multibus_svc: mbirq=%04X int_req=%04X\n", mbirq, int_req); | |
break; | |
default: | |
// sim_printf("multibus_svc: default mbirq=%04X\n", mbirq); | |
break; | |
} | |
sim_activate (&multibus_unit, multibus_unit.wait); /* continue poll */ | |
return SCPE_OK; | |
} | |
/* Reset routine */ | |
t_stat multibus_reset(DEVICE *dptr) | |
{ | |
SBC_reset(NULL); | |
sim_printf(" Multibus: Reset\n"); | |
isbc064_reset(NULL); | |
isbc201_fdcnum = 0; | |
isbc201_reset(NULL, SBC201_BASE); | |
isbc202_fdcnum = 0; | |
isbc202_reset(NULL, SBC202_BASE); | |
zx200a_fdcnum = 0; | |
zx200a_reset(NULL, ZX200A_BASE); | |
sim_activate (&multibus_unit, multibus_unit.wait); /* activate unit */ | |
return SCPE_OK; | |
} | |
void set_irq(int32 int_num) | |
{ | |
mbirq |= int_num; | |
// sim_printf("set_irq: int_num=%04X mbirq=%04X\n", int_num, mbirq); | |
} | |
void clr_irq(int32 int_num) | |
{ | |
mbirq &= ~int_num; | |
// sim_printf("clr_irq: int_num=%04X mbirq=%04X\n", int_num, mbirq); | |
} | |
/* This is the I/O configuration table. There are 256 possible | |
device addresses, if a device is plugged to a port it's routine | |
address is here, 'nulldev' means no device has been registered. | |
*/ | |
struct idev { | |
uint8 (*routine)(t_bool io, uint8 data); | |
uint16 port; | |
uint8 devnum; | |
}; | |
struct idev dev_table[256] = { | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 000H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 004H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 008H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 010H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 014H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 018H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 01CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 020H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 024H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 028H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 02CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 030H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 034H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 038H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 03CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 040H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 044H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 048H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 050H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 054H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 058H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 05CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 060H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 064H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 068H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 06CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 070H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 074H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 078H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 07CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 080H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 084H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 088H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 08CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 090H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 094H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 098H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 09CH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A4H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A8H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0A0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B4H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B8H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0B0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C4H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C8H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0CCH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D4H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0D8H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0DCH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E4H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0E8H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0ECH */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F0H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F4H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0F8H */ | |
{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 0FCH */ | |
}; | |
//uint8 nulldev(t_bool flag, uint8 data, uint8 devnum) | |
uint8 nulldev(t_bool flag, uint8 data) | |
{ | |
SET_XACK(0); /* set no XACK */ | |
return 0xFF; | |
} | |
//uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data, uint8 devnum), uint16 port, uint8 devnum) | |
uint8 reg_dev(uint8 (*routine)(t_bool io, uint8 data), uint16 port, uint8 devnum) | |
{ | |
if (dev_table[port].routine != &nulldev) { /* port already assigned */ | |
if (dev_table[port].routine != routine) | |
sim_printf(" I/O Port %04X is already assigned\n", port); | |
} else { | |
sim_printf(" Port %04X is assigned to dev %04X\n", port, devnum); | |
dev_table[port].routine = routine; | |
dev_table[port].devnum = devnum; | |
} | |
return 0; | |
} | |
/* get a byte from memory */ | |
uint8 multibus_get_mbyte(uint16 addr) | |
{ | |
SET_XACK(0); /* set no XACK */ | |
// sim_printf("multibus_get_mbyte: Cleared XACK for %04X\n", addr); | |
return isbc064_get_mbyte(addr); | |
} | |
/* get a word from memory */ | |
uint16 multibus_get_mword(uint16 addr) | |
{ | |
uint16 val; | |
val = multibus_get_mbyte(addr); | |
val |= (multibus_get_mbyte(addr+1) << 8); | |
return val; | |
} | |
/* put a byte to memory */ | |
void multibus_put_mbyte(uint16 addr, uint8 val) | |
{ | |
SET_XACK(0); /* set no XACK */ | |
// sim_printf("multibus_put_mbyte: Cleared XACK for %04X\n", addr); | |
isbc064_put_mbyte(addr, val); | |
// sim_printf("multibus_put_mbyte: Done XACK=%dX\n", XACK); | |
} | |
/* put a word to memory */ | |
void multibus_put_mword(uint16 addr, uint16 val) | |
{ | |
multibus_put_mbyte(addr, val & 0xff); | |
multibus_put_mbyte(addr+1, val >> 8); | |
} | |
/* end of multibus.c */ | |