blob: f5c632124f40983bff3e698f8323871ec54921ed [file] [log] [blame] [raw]
/* iJEDEC.c: Intel JEDEC Universal Site simulator for SBCs
Copyright (c) 2011, 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.
These functions support a simulated i2732 JEDEC device on an iSBC. This
allows the attachment of the device to a binary file containing the JEDEC
code.
Unit will support 8, 16 and 32 KB EPROMs as well as 8 and 16 KB static
RAMs in the JEDEC sockets. Units must be configured for 8KB for 8KB
SRAM and 32KB for 32KB SRAM. If configured for 16KB, SRAM cannot be
configured. Size is set by configuring the top JEDEC site for an EPROM.
Size and spacing for the other JEDEC units is derived from the top JEDEC
site configuration. Changing the top JEDEC site will clear the
configuration of all other JEDEC sites. The JEDEC driver can be set for
either 8- or 16bit data access.
The top JEDEC site can only be configured to contain an EPROM.
It contains the reset address for the 8088, 8086, 80188, 80186,
and 80286.
For illustration 8-bit mode - 4 Sites - configured for 8KB chips
+--------+ 0xFFFFF
| |
| jedec3 | Only ROM
| |
+--------+ 0xFE000
+--------+ 0xFDFFF
| |
| jedec2 | RAM/ROM
| |
+--------+ 0xFC000
+--------+ 0xFBFFF
| |
| jedec1 | RAM/ROM
| |
+--------+ 0xFA000
+--------+ 0xF9FFF
| |
| jedec0 | RAM/ROM
| |
+--------+ 0xF8000
For illustration 16-bit mode - 4 Sites - configured for 8KB chips
Odd data byte Even data byte
High data byte Low data byte
+--------+ 0xFFFFF +--------+ 0xFFFFE
| | | |
| jedec3 | Only ROM | jedec2 | Only ROM
| | | |
+--------+ 0xFC001 +--------+ 0xFC000
+--------+ 0xFBFFF +--------+ 0xFBFFE
| | | |
| jedec3 | RAM/ROM | jedec2 | RAM/ROM
| | | |
+--------+ 0xF8001 +--------+ 0xF8000
uptr->filename - ROM image file attached to unit
uptr->capac - unit capacity in bytes
uptr->u3 - unit base address
uptr->u4 - unit device type {none|8krom|16krom|32krom|8kram|32kram}
uptr->u5 - unit flags - ROM or RAM, 8 or 16BIT (top unit only)
uptr->u6 - unit number
*/
#include <stdio.h>
#include "multibus_defs.h"
#define JEDEC_NUM 4
#define UNIT_V_DMODE (UNIT_V_UF) /* data bus mode */
#define UNIT_DMODE (1 << UNIT_V_DMODE)
#define UNIT_V_MSIZE (UNIT_V_UF+1) /* Memory Size */
#define UNIT_MSIZE (1 << UNIT_V_MSIZE)
#define UNIT_NONE 0 /* No device */
#define UNIT_8KROM 1 /* 8KB ROM */
#define UNIT_16KROM 2 /* 16KB ROM */
#define UNIT_32KROM 3 /* 32KB ROM */
#define UNIT_8KRAM 4 /* 8KB RAM */
#define UNIT_32KRAM 5 /* 32KB RAM */
#define RAM 0x00000001
#define D16BIT 0x00000002
/* function prototypes */
t_stat JEDEC_set_size (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat JEDEC_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat JEDEC_attach (UNIT *uptr, char *cptr);
t_stat JEDEC_reset (DEVICE *dptr);
int32 JEDEC_get_mbyte(int32 addr);
void JEDEC_put_mbyte(int32 addr, int32 val);
/* SIMH JEDEC Standard I/O Data Structures */
UNIT JEDEC_unit[] = {
{ UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 },
{ UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 },
{ UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 },
{ UDATA (NULL, UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE+UNIT_RO, 0),0 }
};
MTAB JEDEC_mod[] = {
{ UNIT_DMODE, 0, "8-Bit", "8B", &JEDEC_set_mode },
{ UNIT_DMODE, UNIT_DMODE, "16-Bit", "16B", &JEDEC_set_mode },
{ UNIT_MSIZE, UNIT_NONE, "Not configured", "NONE", &JEDEC_set_size },
{ UNIT_MSIZE, UNIT_8KROM, "8KB ROM", "8KROM", &JEDEC_set_size },
{ UNIT_MSIZE, UNIT_16KROM, "16KB ROM", "16KROM", &JEDEC_set_size },
{ UNIT_MSIZE, UNIT_32KROM, "32KB ROM", "32KROM", &JEDEC_set_size },
{ UNIT_MSIZE, UNIT_8KRAM, "8KB RAM", "8KRAM", &JEDEC_set_size },
{ UNIT_MSIZE, UNIT_32KRAM, "32KB RAM", "32KRAM", &JEDEC_set_size },
{ 0 }
};
DEBTAB JEDEC_debug[] = {
{ "ALL", DEBUG_all },
{ "FLOW", DEBUG_flow },
{ "READ", DEBUG_read },
{ "WRITE", DEBUG_write },
{ "LEV1", DEBUG_level1 },
{ "LEV2", DEBUG_level2 },
{ NULL }
};
DEVICE JEDEC_dev = {
"JEDEC", //name
JEDEC_unit, //units
NULL, //registers
JEDEC_mod, //modifiers
JEDEC_NUM, //numunits
16, //aradix
32, //awidth
1, //aincr
16, //dradix
8, //dwidth
NULL, //examine
NULL, //deposit
&JEDEC_reset, //reset
NULL, //boot
&JEDEC_attach, //attach
NULL, //detach
NULL, //ctxt
DEV_DEBUG, //flags
0, //dctrl
JEDEC_debug, //debflags
NULL, //msize
NULL //lname
};
/* global variables */
uint8 *JEDEC_buf[JEDEC_NUM] = { /* JEDEC buffer pointers */
NULL,
NULL,
NULL,
NULL
};
/* JEDEC functions */
/* JEDEC attach - force JEDEC reset at completion */
t_stat JEDEC_attach (UNIT *uptr, char *cptr)
{
t_stat r;
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_attach: Entered with cptr=%s\n", cptr);
if ((r = attach_unit (uptr, cptr)) != SCPE_OK) {
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_attach: Error\n");
return r;
}
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_attach: Done\n");
return (JEDEC_reset (NULL));
}
/* JEDEC set mode = 8- or 16-bit data bus */
t_stat JEDEC_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc)
{
UNIT *uptr1;
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_set_mode: Entered with val=%08XH, unit=%d\n", val, uptr->u6);
uptr1 = JEDEC_dev.units + JEDEC_NUM - 1; /* top unit holds this configuration */
if (val) { /* 16-bit mode */
uptr1->u5 |= D16BIT;
} else { /* 8-bit mode */
uptr1->u5 &= ~D16BIT;
}
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("JEDEC%d->u5=%08XH\n", JEDEC_NUM - 1, uptr1->u5);
sim_printf("\tJEDEC_set_mode: Done\n");
}
/* JEDEC set type = none, 8krom, 16krom, 32krom, 8kram or 32kram */
t_stat JEDEC_set_size (UNIT *uptr, int32 val, char *cptr, void *desc)
{
uint32 i, basadr;
UNIT *uptr1;
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_set_size: Entered with val=%d, unit=%d\n", val, uptr->u6);
uptr1 = JEDEC_dev.units + JEDEC_NUM - 1; /* top unit holds u5 configuration */
uptr->u4 = val;
switch(val) {
case UNIT_NONE:
uptr->capac = 0;
uptr->u5 &= ~RAM; /* ROM */
if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */
uptr->u3 = 0; /* base address */
sim_printf("JEDEC site size set to 8KB\n");
for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */
uptr1 = JEDEC_dev.units + i;
uptr1->capac = 0;
}
}
break;
case UNIT_8KROM:
uptr->capac = 0x2000;
uptr1->u5 &= ~RAM; /* ROM */
basadr = 0x100000 - (uptr->capac * JEDEC_NUM);
sim_printf("JEDEC site base address = %06XH\n", basadr);
if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */
uptr->u3 = basadr + (uptr->capac * uptr->u6); /* base address */
sim_printf("JEDEC site size set to 8KB\n");
for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */
uptr1 = JEDEC_dev.units + i;
uptr1->capac = 0;
}
} else {
if (uptr1->capac != uptr->capac) {
uptr->capac = 0;
sim_printf("JEDEC site size precludes use of this device\n");
}
}
break;
case UNIT_16KROM:
uptr->capac = 0x4000;
uptr1->u5 &= ~RAM; /* ROM */
basadr = 0x100000 - (uptr->capac * JEDEC_NUM);
sim_printf("JEDEC site base address = %06XH\n", basadr);
if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */
uptr->u3 = basadr + (uptr->capac * uptr->u6); /* base address */
sim_printf("JEDEC site size set to 16KB\n");
for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */
uptr1 = JEDEC_dev.units + i;
uptr1->capac = 0;
}
} else {
if (uptr1->capac != uptr->capac) {
uptr->capac = 0;
sim_printf("JEDEC site size precludes use of this device\n");
}
}
break;
case UNIT_32KROM:
uptr->capac = 0x8000;
uptr1->u5 &= ~RAM; /* ROM */
basadr = 0x100000 - (uptr->capac * JEDEC_NUM);
sim_printf("JEDEC site base address = %06XH\n", basadr);
if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */
uptr->u3 = basadr + (uptr->capac * uptr->u6); /* base address */
sim_printf("JEDEC site size set to 32KB\n");
for (i = 0; i < JEDEC_NUM-1; i++) { /* clear all units but last unit */
uptr1 = JEDEC_dev.units + i;
uptr1->capac = 0;
}
} else {
if (uptr1->capac != uptr->capac) {
uptr->capac = 0;
sim_printf("JEDEC site size precludes use of this device\n");
}
}
break;
case UNIT_8KRAM:
uptr->capac = 0x2000;
if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */
sim_printf("JEDEC%d cannot be SRAM\n", uptr->u6);
} else {
if (uptr1->capac != uptr->capac) {
uptr->capac = 0;
sim_printf("JEDEC site size precludes use of this device\n");
} else {
uptr->u5 |= RAM; /* RAM */
}
}
break;
case UNIT_32KRAM:
uptr->capac = 0x8000;
if (uptr->u6 == JEDEC_NUM - 1) {/* top unit ? */
sim_printf("JEDEC%d cannot be SRAM\n", uptr->u6);
} else {
if (uptr1->capac != uptr->capac) {
uptr->capac = 0;
sim_printf("JEDEC site size precludes use of this device\n");
} else {
uptr->u5 |= RAM; /* RAM */
}
}
break;
default:
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_set_size: Error\n");
return SCPE_ARG;
}
if (JEDEC_buf[uptr->u6]) { /* any change requires a new buffer */
free (JEDEC_buf[uptr->u6]);
JEDEC_buf[uptr->u6] = NULL;
}
if (JEDEC_dev.dctrl & DEBUG_flow) {
sim_printf("\tJEDEC%d->capac=%04XH\n", uptr->u6, uptr->capac);
sim_printf("\tJEDEC%d->u3[Base addr]=%06XH\n", uptr->u6, uptr->u3);
sim_printf("\tJEDEC%d->u4[val]=%06XH\n", uptr->u6, uptr->u4);
sim_printf("\tJEDEC%d->u5[Flags]=%06XH\n", uptr->u6, uptr->u5);
sim_printf("\tJEDEC%d->u6[unit #]=%06XH\n", uptr->u6, uptr->u6);
uptr1 = JEDEC_dev.units + JEDEC_NUM - 1; /* top unit holds u5 configuration */
sim_printf("\tJEDEC%d->u5[Flags]=%06XH\n", JEDEC_NUM - 1, uptr1->u5);
sim_printf("\tJEDEC_set_size: Done\n");
}
return SCPE_OK;
}
/* JEDEC reset */
t_stat JEDEC_reset (DEVICE *dptr)
{
int32 i, j, c;
FILE *fp;
t_stat r;
UNIT *uptr;
static int flag = 1;
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_reset: Entered\n");
for (i = 0; i < JEDEC_NUM; i++) { /* handle all umits */
uptr = JEDEC_dev.units + i;
if (uptr->capac == 0) { /* if not configured */
sim_printf(" JEDEC%d: Not configured\n", i);
if (flag) {
sim_printf(" ALL: \"set JEDEC3 None | 8krom | 16krom | 32krom | 8kram | 32kram\"\n");
sim_printf(" EPROM: \"att JEDEC3 <filename>\"\n");
flag = 0;
}
uptr->capac = 0;
/* assume 8KB in base address calculation */
uptr->u3 = 0xF8000 + (0x2000 * i); /* base address */
uptr->u4 = 0; /* None */
uptr->u5 = 0; /* RO */
uptr->u6 = i; /* unit number - only set here! */
}
if (uptr->capac) { /* if configured */
sim_printf(" JEDEC%d: Initializing %2XKB %s [%04X-%04XH]\n",
i,
uptr->capac / 0x400,
uptr->u5 ? "Ram" : "Rom",
uptr->u3,
uptr->u3 + uptr->capac - 1);
if (JEDEC_buf[uptr->u6] == NULL) {/* no buffer allocated */
JEDEC_buf[uptr->u6] = malloc(uptr->capac);
if (JEDEC_buf[uptr->u6] == NULL) {
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_reset: Malloc error\n");
return SCPE_MEM;
}
}
if ((uptr->u5 & 0x0001) == 0) { /* ROM - load file */
fp = fopen(uptr->filename, "rb");
if (fp == NULL) {
sim_printf("\tUnable to open ROM file %s\n", uptr->filename);
sim_printf("\tNo ROM image loaded!!!\n");
} else {
j = 0;
c = fgetc(fp);
while (c != EOF) {
*(JEDEC_buf[uptr->u6] + j++) = c & 0xFF;
c = fgetc(fp);
if (j >= JEDEC_unit[uptr->u6].capac) {
sim_printf("\tImage is too large - Load truncated!!!\n");
break;
}
}
fclose(fp);
sim_printf("\t%d bytes of ROM image %s loaded\n", j, uptr->filename);
}
}
}
}
if (JEDEC_dev.dctrl & DEBUG_flow)
sim_printf("\tJEDEC_reset: Done\n");
return SCPE_OK;
}
/* I/O instruction handlers, called from the CPU module when an
JEDEC memory read or write is issued.
Need to fix for hi/low memory operations
*/
/* get a byte from memory */
int32 JEDEC_get_mbyte(int32 addr)
{
int32 i, val, org, len;
UNIT *uptr;
if (JEDEC_dev.dctrl & DEBUG_read)
sim_printf("\tJEDEC_get_mbyte: Entered\n");
for (i = 0; i < JEDEC_NUM; i++) { /* test all umits for address */
uptr = JEDEC_dev.units + i;
org = uptr->u3;
len = uptr->capac - 1;
if ((addr >= org) && (addr <= org + len)) {
if (JEDEC_dev.dctrl & DEBUG_read)
sim_printf("\tJEDEC%d Addr=%06XH Org=%06XH Len=%06XH\n", i, addr, org, len);
val = *(JEDEC_buf[uptr->u6] + (addr - org));
if (JEDEC_dev.dctrl & DEBUG_read)
sim_printf("\tJEDEC_get_mbyte: Exit with [%0XH]\n", val & 0xFF);
return (val & 0xFF);
}
}
if (JEDEC_dev.dctrl & DEBUG_read)
sim_printf("\tJEDEC_get_mbyte: Exit - Out of range\n", addr);
return 0xFF;
}
/* put a byte into memory */
void JEDEC_put_mbyte(int32 addr, int32 val)
{
int32 i, org, len, type;
UNIT *uptr;
if (JEDEC_dev.dctrl & DEBUG_write)
sim_printf("\tJEDEC_put_mbyte: Entered\n");
for (i = 0; i < JEDEC_NUM; i++) { /* test all umits for address */
uptr = JEDEC_dev.units + i;
org = uptr->u3;
len = uptr->capac - 1;
if ((addr >= org) && (addr < org + len)) {
if (JEDEC_dev.dctrl & DEBUG_write)
sim_printf("\tJEDEC%d Org=%06XH Len=%06XH\n", i, org, len);
if (uptr->u5 & RAM) { /* can't write to ROM */
*(JEDEC_buf[uptr->u6] + (addr - org)) = val & 0xFF;
if (JEDEC_dev.dctrl & DEBUG_write)
sim_printf("\tJEDEC_put_mbyte: Exit with [%06XH]=%02XH\n", addr, val);
} else
sim_printf("\tJEDEC_put_mbyte: Write to ROM ignored\n");
}
}
if (JEDEC_dev.dctrl & DEBUG_write)
sim_printf("\tJEDEC_put_mbyte: Exit - Out of range\n");
}
/* end of iJEDEC.c */