1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-03-01 01:30:04 +00:00

Ridge32: Initial commit.

This commit is contained in:
Richard Cornwell
2020-08-19 21:59:27 -04:00
parent 5d1c01fcc9
commit 3abd69b166
6 changed files with 4780 additions and 0 deletions

1779
Ridge32/ridge32_cpu.c Normal file

File diff suppressed because it is too large Load Diff

170
Ridge32/ridge32_defs.h Normal file
View File

@@ -0,0 +1,170 @@
/* ridge32_defs.h: Ridge 32 simulator definitions
Copyright (c) 2019, Richard Cornwell
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
ROBERT M SUPNIK 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.
*/
#include "sim_defs.h" /* simulator defns */
/* Simulator stop codes */
#define STOP_HALT 1 /* halted */
#define STOP_IBKPT 2 /* breakpoint */
/* Conditional error returns */
/* Memory */
#define MAXMEMSIZE (16*1024*1024) /* max memory size */
#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */
#define MEMSIZE (cpu_unit.capac) /* actual memory size */
#define MEM_ADDR_OK(x) (((x)) < MEMSIZE)
extern uint32 *M;
/* Opcode definitions */
#define OP_MOVE 0x01
#define OP_NEG 0x02
#define OP_ADD 0x03
#define OP_SUB 0x04
#define OP_MPY 0x05
#define OP_DIV 0x06
#define OP_REM 0x07
#define OP_NOT 0x08
#define OP_OR 0x09
#define OP_XOR 0x0A
#define OP_AND 0x0B
#define OP_CBIT 0x0C
#define OP_SBIT 0x0D
#define OP_TBIT 0x0E
#define OP_CHK 0x0F
#define OP_NOP 0x10
#define OP_MOVEI 0x11
#define OP_ADDI 0x13
#define OP_SUBI 0x14
#define OP_MPYI 0x15
#define OP_NOTI 0x18
#define OP_ANDI 0x1B
#define OP_CHKI 0x1F
#define OP_FIXT 0x20
#define OP_FIXR 0x21
#define OP_RNEG 0x22
#define OP_RADD 0x23
#define OP_RSUB 0x24
#define OP_RMPY 0x25
#define OP_RDIV 0x26
#define OP_MAKERD 0x27
#define OP_LCOMP 0x28
#define OP_FLOAT 0x29
#define OP_RCOMP 0x2A
#define OP_EADD 0x2C
#define OP_ESUB 0x2D
#define OP_EMPY 0x2E
#define OP_EDIV 0x2F
#define OP_DFIXT 0x30
#define OP_DFIXR 0x31
#define OP_DRNEG 0x32
#define OP_DRADD 0x33
#define OP_DRSUB 0x34
#define OP_DRMPY 0x35
#define OP_DRDIV 0x36
#define OP_MAKEDR 0x37
#define OP_DCOMP 0x38
#define OP_DFLOAT 0x39
#define OP_DRCOMP 0x3A
#define OP_TRAP 0x3B
#define OP_SUS 0x40
#define OP_LUS 0x41
#define OP_RUM 0x42
#define OP_LDREGS 0x43
#define OP_TRANS 0x44
#define OP_DIRT 0x45
#define OP_MOVESR 0x46
#define OP_MOVERS 0x47
#define OP_MAINT 0x4C
#define OP_READ 0x4E
#define OP_WRITE 0x4F
#define OP_CALLR 0x53
#define OP_RET 0x57
#define OP_KCALL 0x5B
#define OP_LSL 0x60
#define OP_LSR 0x61
#define OP_ASL 0x62
#define OP_ASR 0x63
#define OP_DLSL 0x64
#define OP_DLSR 0x65
#define OP_CSL 0x68
#define OP_SEB 0x6A
#define OP_LSLI 0x70
#define OP_LSRI 0x71
#define OP_ASLI 0x72
#define OP_ASRI 0x73
#define OP_DLSLI 0x74
#define OP_DLSRI 0x75
#define OP_CSLI 0x78
#define OP_SEH 0x7A
/* Device context block */
struct ridge_dib {
uint8 dev_num; /* device address */
uint8 slot_num; /* Slot number */
int (*io_read)(uint32 dev, uint32 *data);
int (*io_write)(uint32 dev, uint32 data);
int (*io_iord)(uint32 *data);
};
typedef struct ridge_dib DIB;
/* Debuging controls */
#define DEBUG_CMD 0x0000001 /* Show device commands */
#define DEBUG_DATA 0x0000002 /* Show data transfers */
#define DEBUG_DETAIL 0x0000004 /* Show details */
#define DEBUG_EXP 0x0000008 /* Show error conditions */
#define DEBUG_TRAP 0x0000010 /* Show Trap requests */
#define DEBUG_INST 0x0000020 /* Show instruction execution */
#define DCB u3 /* DCB pointer */
extern DEBTAB dev_debug[];
extern DEVICE cpu_dev;
extern DEVICE flp_dev;
extern DEVICE dsk_dev;
extern uint8 ext_irq;
extern UNIT cpu_unit;
extern int32 tmxr_poll;
void cpu_boot(int);
uint8 io_dcbread_byte(UNIT *uptr, int off);
uint16 io_dcbread_half(UNIT *uptr, int off);
uint32 io_dcbread_addr(UNIT *uptr, int off);
void io_dcbread_blk(UNIT *uptr, int off, uint8 *data, int sz);
void io_read_blk(int addr, uint8 *data, int sz);
void io_dcbwrite_byte(UNIT *uptr, int off, uint8 data);
void io_dcbwrite_half(UNIT *uptr, int off, uint16 data);
void io_dcbwrite_blk(UNIT *uptr, int off, uint8 *data, int sz);
void io_write_blk(int addr, uint8 *data, int sz);
int io_read(uint32 dev_data, uint32 *data);
int io_write(uint32 dev_data, uint32 data);
int io_rd(uint32 *data);
t_stat chan_set_devs();
t_stat set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
t_stat show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc);
t_stat set_slot_num(UNIT * uptr, int32 val, CONST char *cptr, void *desc);
t_stat show_slot_num(FILE * st, UNIT * uptr, int32 v, CONST void *desc);
void fprint_inst(FILE *, t_addr addr, t_value *);

604
Ridge32/ridge32_dsk.c Normal file
View File

@@ -0,0 +1,604 @@
/* Ridge32_dsk.c: Ridge 32 Priam disk controller.
Copyright (c) 2020, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#include "ridge32_defs.h"
#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */
#define UNIT_M_DTYPE 1
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
#define DCB u3 /* DCB pointer */
#define STATUS u4 /* Last status */
#define CYL u5 /* Current cylinder */
#define CMD u6
#define WR_INH 0x8000
#define DSK_RD 0 /* Read command */
#define DSK_WR 1 /* Write command */
#define DSK_VFY 2 /* Verify data */
#define DSK_FMT 3 /* Format a track */
#define DSK_SEEK 4 /* Seek to cylinder */
#define DSK_RDH 5 /* Read Highest sector address */
#define DSK_RDF 6 /* Read full sector */
#define DSK_WRF 7 /* Write full sector */
#define DSK_HDR 0xE /* Read headers */
/* DCB control block.
DCB + 0C0
0 GORDER
0 - Read
1 - Write
2 - Verify
3 - Format track
4 - Seek
5 - Return highest sector address.
6 - Read full Sector.
7 - Write full sector.
1 SORDER Not used.
2 GSTAT
0 - Ok.
1 - Not Ready.
2 - Timeout
3 - Equipment Fault.
4 - Write protect
5 - Ridge double bit error.
6 - Data overrun
7 - Missing AM.
8 - Can't find header.
9 - header CRC
A - data CRC
B - Seek error.
FF - Illegal parameter in DCB order.
3 SSTAT reserved.
4 RETRIES
5 RIDGE ADDR
6
7
8 BYTE COUNT
9
A BYTE COUNT READ.
B
C Not used
D Header 4(bits), Cylinder (4bits).
E Cylinder
F Sector 0-17
10 -1B Data Labels
*/
#define SECT_SZ 1024
#define LBL_SZ 12
#define P142_DTYPE 0
#define P60_DTYPE 1
struct _dsk_type {
uint32 cyl;
uint16 hds;
uint16 sect;
uint16 bpt;
char *model;
} dsk_type[] = {
{1121, 7, 18, 20160, "Priam142"},
{1121, 3, 18, 20160, "Priam60"},
{0, 0, 0, 0, NULL},
};
int dsk_read(uint32 dev, uint32 *data);
int dsk_write(uint32 dev, uint32 data);
int dsk_iord(uint32 *data);
void dsk_start(UNIT *uptr, int drive);
t_stat dsk_svc (UNIT *uptr);
t_stat dsk_boot (int32, DEVICE *);
t_stat dsk_set_type(UNIT *, int32, CONST char *, void *);
t_stat dsk_attach(UNIT *uptr, CONST char *cptr);
t_stat dsk_detach(UNIT *uptr);
t_stat dsk_reset(DEVICE *dp);
uint8 dsk_sect_lab[LBL_SZ];
uint8 dsk_buf[SECT_SZ];
/* Device context block */
struct ridge_dib dsk_dib = {2, 2, dsk_read, dsk_write, dsk_iord};
MTAB dsk_mod[] = {
{UNIT_DTYPE, (P142_DTYPE << UNIT_V_DTYPE), "P142", "P142", &dsk_set_type },
{UNIT_DTYPE, (P60_DTYPE << UNIT_V_DTYPE), "P60", "P60", &dsk_set_type },
{MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "SLOT", "SLOT", &set_slot_num,
&show_slot_num, NULL},
{MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
&show_dev_addr, NULL},
{ 0 }
};
UNIT dsk_unit[] = {
{UDATA(&dsk_svc, UNIT_ATTABLE | UNIT_DISABLE | UNIT_FIX |
(P142_DTYPE << UNIT_V_DTYPE), 0)},
{UDATA(&dsk_svc, UNIT_ATTABLE | UNIT_DISABLE | UNIT_FIX |
(P142_DTYPE << UNIT_V_DTYPE), 0)},
{UDATA(&dsk_svc, UNIT_ATTABLE | UNIT_DISABLE | UNIT_FIX |
(P142_DTYPE << UNIT_V_DTYPE), 0)},
{UDATA(&dsk_svc, UNIT_ATTABLE | UNIT_DISABLE | UNIT_FIX |
(P142_DTYPE << UNIT_V_DTYPE), 0)},
};
DEVICE dsk_dev = {
"DSK", dsk_unit, NULL, dsk_mod,
4, 16, 24, 1, 16, 8,
NULL, NULL, &dsk_reset, &dsk_boot, &dsk_attach, &dsk_detach,
&dsk_dib, DEV_DEBUG, 0, dev_debug, NULL, NULL,
};
struct _dcb {
uint8 retries;
uint32 addr; /* transfer address */
uint16 count; /* byte count */
uint16 xcount; /* transfer count */
uint8 hd; /* Head */
uint16 cyl; /* Cylinder */
uint8 sect; /* Sector */
} dsk_dcb[4];
int
dsk_read(uint32 dev, uint32 *data)
{
UNIT *uptr = &dsk_unit[0];
*data = uptr->STATUS & 0x03FF00;
*data |= (dsk_dib.dev_num << 24) & 0xff000000;
*data |= 0x400000;
sim_debug(DEBUG_EXP, &dsk_dev, "read status %8x\n\r", *data);
return (uptr->STATUS & 0x2) ? 1 : 0;
}
int
dsk_write(uint32 dev, uint32 data)
{
UNIT *uptr = &dsk_unit[0];
UNIT *duptr;
int cmd = (data >> 24) & 0xff;
int drive = cmd & 3;
int offset = drive << 6;;
int i;
/* Check if command can be accepted */
if (uptr->STATUS & 1) {
return 1;
}
sim_debug(DEBUG_CMD, &dsk_dev, "Dsk start %02x\n", cmd);
switch (cmd) {
case 0x80:
case 0x81:
case 0x82:
case 0x83:
/* Find actual unit */
duptr = &dsk_unit[drive];
/* Read first word of DCB + 0xC0 */
duptr->CMD &= WR_INH;
duptr->CMD |= io_dcbread_byte(uptr, offset);
dsk_dcb[drive].addr = io_dcbread_addr(uptr, offset + 0x5);
dsk_dcb[drive].count = io_dcbread_half(uptr, offset + 0x8);
dsk_dcb[drive].xcount = 0;
dsk_dcb[drive].hd = io_dcbread_byte(uptr, offset + 0xd);
dsk_dcb[drive].cyl = io_dcbread_byte(uptr, offset + 0xe);
dsk_dcb[drive].sect = io_dcbread_byte(uptr, offset + 0xf);
dsk_dcb[drive].cyl |= (dsk_dcb[drive].hd & 0xf) << 4;
dsk_dcb[drive].hd = (dsk_dcb[drive].hd >> 4) & 0xf;
cmd = duptr->CMD & 0xf;
sim_debug(DEBUG_DETAIL, &dsk_dev,
"Start Disk %2x %6x %4x c=%4d h=%d s=%2d\n",
duptr->CMD, dsk_dcb[drive].addr, dsk_dcb[drive].count,
dsk_dcb[drive].cyl, dsk_dcb[drive].hd, dsk_dcb[drive].sect);
if (cmd > 7 && cmd != 0xe) {
/* Invalid */
io_dcbwrite_byte(uptr, offset + 0x2, 0xff);
uptr->STATUS = 0x40FF01 | (drive << 16);
ext_irq = 1;
return 0;
}
sim_activate(duptr, 100);
break;
case 0xc0: /* Boot floppy left */
(void)dsk_boot(0, &dsk_dev);
break;
case 0xc1: /* Update DCB */
uptr->DCB = (M[0x3c13c >> 2] & 0xffff) << 8;
uptr->STATUS = 0x400001;
ext_irq = 1;
break;
case 0xc2: /* Set write inhibit */
uptr->CMD |= WR_INH;
uptr->STATUS = 0x400001;
ext_irq = 1;
break;
case 0xc3: /* Clear write inhibit */
uptr->CMD &= ~WR_INH;
uptr->STATUS = 0x400001;
ext_irq = 1;
break;
case 0xc4: /* Update DCB */
M[0x3c13c >> 2] &= 0xffff0000;
M[0x3c13c >> 2] = (uptr->DCB >> 8) & 0xffff;
uptr->STATUS = 0x400001;
ext_irq = 1;
break;
}
return 0;
}
int
dsk_iord(uint32 *data)
{
UNIT *uptr = &dsk_unit[0];
*data = uptr->STATUS & 0x003FF00;
*data |= ((uint32)dsk_dib.dev_num) << 24;
*data |= 0x400000;
/* Check if irq pending */
if (uptr->STATUS & 1) {
uptr->STATUS &= ~1;
return 1;
}
return 0;
}
int
dsk_incsect(UNIT *uptr, int drive)
{
int type = GET_DTYPE(uptr->flags);
dsk_dcb[drive].sect++;
if (dsk_dcb[drive].sect >= dsk_type[type].sect) {
dsk_dcb[drive].sect = 0;
dsk_dcb[drive].hd++;
if (dsk_dcb[drive].hd >= dsk_type[type].hds) {
dsk_dcb[drive].hd = 0;
dsk_dcb[drive].cyl++;
if (dsk_dcb[drive].hd >= dsk_type[type].cyl) {
return 1;
}
}
}
return 0;
}
t_stat
dsk_svc (UNIT *uptr)
{
int drive = uptr - dsk_unit;
int offset = drive << 6;;
int type = GET_DTYPE(uptr->flags);
int da;
int flags;
int len;
int i;
int sc;
if (uptr->CYL != dsk_dcb[drive].cyl) {
/* Step in/out based on current cylinder, requested cylinder */
if (uptr->CYL < dsk_dcb[drive].cyl)
uptr->CYL++;
else if (uptr->CYL > dsk_dcb[drive].cyl)
uptr->CYL--;
sim_activate(uptr, 1000);
return SCPE_OK;
}
da = ((dsk_dcb[drive].cyl * dsk_type[type].hds + dsk_dcb[drive].hd)
* dsk_type[type].sect) + dsk_dcb[drive].sect;
switch (uptr->CMD & 0xf) {
case DSK_RD: /* Read command */
sim_debug(DEBUG_DETAIL, &dsk_dev,
"read sector %6x %4x %4d %d %2d\n",
dsk_dcb[drive].addr, dsk_dcb[drive].count, dsk_dcb[drive].cyl,
dsk_dcb[drive].hd, dsk_dcb[drive].sect);
(void)sim_fseek(uptr->fileref, da * SECT_SZ, SEEK_SET);
len = sim_fread(&dsk_buf, 1, sizeof(dsk_buf), uptr->fileref);
while (len < sizeof(dsk_buf)) {
dsk_buf[len++] = 0;
}
if (len > dsk_dcb[drive].count)
len = dsk_dcb[drive].count;
sim_debug(DEBUG_DETAIL, &dsk_dev, "Disk Read: %d bytes\n", len);
for (i = 0; i < len; i++) {
sim_debug(DEBUG_DATA, &dsk_dev, "%02x ", dsk_buf[i]);
if ((i & 0xf) == 0xf)
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
}
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
io_write_blk(dsk_dcb[drive].addr, &dsk_buf[0], len);
dsk_dcb[drive].count -= len;
dsk_dcb[drive].xcount += len;
dsk_dcb[drive].addr += len;
if (dsk_dcb[drive].count != 0) {
if (dsk_incsect(uptr, drive)) {
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].xcount);
io_dcbwrite_byte(uptr, offset + 0x2, 0xb);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
}
sim_activate(uptr, 100);
return SCPE_OK;
}
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].xcount);
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_WR: /* Write command */
sim_debug(DEBUG_DETAIL, &dsk_dev,
"write sector %6x %4x %4d %d %2d\n",
dsk_dcb[drive].addr, dsk_dcb[drive].count, dsk_dcb[drive].cyl,
dsk_dcb[drive].hd, dsk_dcb[drive].sect);
(void)sim_fseek(uptr->fileref, da * SECT_SZ, SEEK_SET);
len = sizeof(dsk_buf);
if (len > dsk_dcb[drive].count)
len = dsk_dcb[drive].count;
io_read_blk(dsk_dcb[drive].addr, &dsk_buf[0], len);
while (len < sizeof(dsk_buf)) {
dsk_buf[len++] = 0;
}
sim_debug(DEBUG_DETAIL, &dsk_dev, "Disk Write: %d bytes\n", len);
for (i = 0; i < len; i++) {
sim_debug(DEBUG_DATA, &dsk_dev, "%02x ", dsk_buf[i]);
if ((i & 0xf) == 0xf)
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
}
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
len = sim_fwrite(&dsk_buf, 1, sizeof(dsk_buf), uptr->fileref);
if (len > dsk_dcb[drive].count)
len = dsk_dcb[drive].count;
dsk_dcb[drive].count -= len;
dsk_dcb[drive].xcount += len;
dsk_dcb[drive].addr += len;
if (dsk_dcb[drive].count != 0) {
if (dsk_incsect(uptr, drive)) {
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].xcount);
io_dcbwrite_byte(uptr, offset + 0x2, 0xb);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
}
sim_activate(uptr, 100);
return SCPE_OK;
}
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].xcount);
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_VFY: /* Verify data */
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].xcount);
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_FMT: /* Format a track */
sim_debug(DEBUG_DETAIL, &dsk_dev,
"Format %6x %4x %2x %2x %2x\n",
dsk_dcb[drive].addr, dsk_dcb[drive].count, dsk_dcb[drive].hd,
dsk_dcb[drive].cyl, dsk_dcb[drive].sect);
da = ((dsk_dcb[drive].cyl * 7 + dsk_dcb[drive].hd) * 18);
(void)sim_fseek(uptr->fileref, da * SECT_SZ, SEEK_SET);
memset(&dsk_buf[0], 0, sizeof(dsk_buf));
for(sc = 0; sc < 18; sc ++) {
len = sim_fwrite(&dsk_buf, 1, sizeof(dsk_buf), uptr->fileref);
}
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].count);
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_SEEK: /* Seek to cylinder */
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_RDH: /* Read Highest sector address */
io_dcbwrite_byte(uptr, offset + 0xd, ((dsk_type[type].hds - 1) << 4) |
(((dsk_type[type].cyl - 1) >> 8) & 0xF));
io_dcbwrite_byte(uptr, offset + 0xe, (dsk_type[type].cyl - 1) & 0xFF);
io_dcbwrite_byte(uptr, offset + 0xf, dsk_type[type].sect - 1);
io_dcbwrite_half(uptr, offset + 0xa, 20160 / 18);
io_dcbwrite_byte(uptr, offset + 0x2, 0x00);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_RDF: /* Read full sector */
sim_debug(DEBUG_DETAIL, &dsk_dev,
"read fsector %6x %4x %4d %d %2d\n",
dsk_dcb[drive].addr, dsk_dcb[drive].count, dsk_dcb[drive].cyl,
dsk_dcb[drive].hd, dsk_dcb[drive].sect);
(void)sim_fseek(uptr->fileref, da * SECT_SZ, SEEK_SET);
memset(&dsk_buf[0], 0, LBL_SZ);
io_write_blk(dsk_dcb[drive].addr, &dsk_buf[0], LBL_SZ);
dsk_dcb[drive].addr += len;
len = sim_fread(&dsk_buf, 1, sizeof(dsk_buf), uptr->fileref);
while (len < sizeof(dsk_buf)) {
dsk_buf[len++] = 0;
}
sim_debug(DEBUG_DATA, &dsk_dev, "Disk Readfull\n");
for (i = 0; i < SECT_SZ; i++) {
sim_debug(DEBUG_DATA, &dsk_dev, "%02x ", dsk_buf[i]);
if ((i & 0xf) == 0xf)
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
}
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
io_write_blk(dsk_dcb[drive].addr, &dsk_buf[0], len);
dsk_dcb[drive].xcount += sizeof(dsk_sect_lab) + sizeof(dsk_buf) + 4;
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].xcount);
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_WRF: /* Write full sector */
sim_debug(DEBUG_DETAIL, &dsk_dev,
"Write fsector %6x %4x %4d %d %2d\n",
dsk_dcb[drive].addr, dsk_dcb[drive].count, dsk_dcb[drive].cyl,
dsk_dcb[drive].hd, dsk_dcb[drive].sect);
(void)sim_fseek(uptr->fileref, da * SECT_SZ, SEEK_SET);
io_read_blk(dsk_dcb[drive].addr, &dsk_buf[0], sizeof(dsk_sect_lab));
dsk_dcb[drive].addr += LBL_SZ;
io_read_blk(dsk_dcb[drive].addr, &dsk_buf[0], sizeof(dsk_buf));
sim_debug(DEBUG_DATA, &dsk_dev, "Disk Writefull\n");
for (i = 0; i < SECT_SZ; i++) {
sim_debug(DEBUG_DATA, &dsk_dev, "%02x ", dsk_buf[i]);
if ((i & 0xf) == 0xf)
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
}
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
len = sim_fwrite(&dsk_buf, 1, sizeof(dsk_buf), uptr->fileref);
dsk_dcb[drive].xcount += len;
io_dcbwrite_half(uptr, offset + 0xa, dsk_dcb[drive].xcount);
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
case DSK_HDR: /* Read headers */
io_dcbwrite_byte(uptr, offset + 0x2, 0);
dsk_unit[0].STATUS = 0x400001 | (drive << 16);
ext_irq = 1;
break;
}
return SCPE_OK;
}
t_stat
dsk_boot(int32 unit_num, DEVICE *dptr)
{
UNIT *dkuptr = &dptr->units[unit_num];
int i = 0;
if (unit_num != 0)
return SCPE_ARG;
if ((dkuptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT;
dkuptr->up8 = (void *)dkuptr;
/* Set up for generic read of track 2 */
dkuptr->CMD = 0;
dsk_dcb[unit_num].addr = 0x3e000;
dsk_dcb[unit_num].count = 4096;
dsk_dcb[unit_num].xcount = 0;
dsk_dcb[unit_num].hd = 0;
dsk_dcb[unit_num].cyl = 0;
dsk_dcb[unit_num].sect = 4;
/* Set CPU into idle state */
cpu_boot(1);
sim_activate(dkuptr, 20);
return SCPE_OK;
}
t_stat
dsk_reset(DEVICE *dptr)
{
int i,t;
dsk_unit[0].DCB = 0x3c100;
for (i = 0; i < dptr->numunits; i++) {
t = GET_DTYPE(dsk_unit[i].flags);
dsk_unit[i].capac = dsk_type[t].cyl * dsk_type[t].hds *
dsk_type[t].sect * 1024;
}
return SCPE_OK;
}
t_stat
dsk_set_type(UNIT *uptr, int32 val, CONST char *cptr, void *desc)
{
int i;
if (uptr == NULL) return SCPE_IERR;
i = GET_DTYPE(val);
uptr->capac = dsk_type[i].cyl * dsk_type[i].hds *
dsk_type[i].sect * 1024;
return SCPE_OK;
}
/* Attach routine */
t_stat
dsk_attach(UNIT *uptr, CONST char *cptr)
{
char header[4];
t_stat r;
r = attach_unit(uptr, cptr); /* attach unit */
if ( r != SCPE_OK) /* error? */
return r;
/* Determine length of this disk */
uptr->capac = sim_fsize(uptr->fileref);
return SCPE_OK;
}
/* Detach routine */
t_stat dsk_detach(UNIT *uptr)
{
t_stat r;
r = detach_unit(uptr); /* detach unit */
return r;
}

978
Ridge32/ridge32_flp.c Normal file
View File

@@ -0,0 +1,978 @@
/* Ridge32_flp.c: Ridge 32 765 floppy disk controller.
Copyright (c) 2019, Richard Cornwell
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
RICHARD CORNWELL 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.
*/
#include "ridge32_defs.h"
#include "sim_imd.h"
#define DCB u3 /* DCB pointer */
#define STATUS u4 /* Last status */
#define CYL u5 /* Current cylinder */
#define PHASE u6 /* Command phase */
#define PHASE_IDLE 0 /* No commands */
#define PHASE_SEEK 1 /* Seek to desired cylinder */
#define PHASE_CMD 2 /* Decode commands */
#define PHASE_EXEC 3 /* Execute the command */
#define PHASE_RES 4 /* Place results */
#define PHASE_IRQ 5 /* Post interrupt */
#define CMD_RDTRK 0x2 /* Read track */
#define CMD_FIXDR 0x3 /* Fix drive */
#define CMD_CHKDR 0x4 /* Check drive */
#define CMD_WRSEC 0x5 /* Write sector */
#define CMD_RDSEC 0x6 /* Read sector */
#define CMD_RECAL 0x7 /* Recalibrate drive */
#define CMD_CHKIR 0x8 /* Check IRQ */
#define CMD_WRDEL 0x9 /* Write delete */
#define CMD_RDSID 0xa /* Read sector ID */
#define CMD_RDDEL 0xc /* Read delete */
#define CMD_FMTTK 0xd /* Format track */
#define CMD_SEEK 0xf /* Seek */
#define BLD_OP 0x01
#define SEEK_OP 0x02
#define READ_OP 0x04
#define WRIT_OP 0x08
#define SK_OP 0x10
#define ST_OP 0x20
#define INV_OP 0x80
/*
* Read Track 0FS00010/xxxxxHDD/Cyl/Head/Sec/Sectsize/tl/lgap3/dataleng.
* Write sec MF000101/same.
* Read sec MFS00110/same.
* Write del MF001001/smae.
* Read Del MF001100/same.
* Fmt Track 0F001101/xxxxxHDD/Sect/Track/Lgap3/fill
* Data per sector: Track/Head/Sect Num/Sect size.
* Fix Drive 00000011/step,hd ult/hd lt,ndm No status
* Chk Drive 00000100/xxxxxHDD ST3
* Cali 00000111/xxxxx0DD No status
* Chk Irq 00001000 ST0,Cyl
* Rd Sec ID 0F001010/xxxxxHDD
* Seek 00001111/xxxxxHDD/cyl
*/
/* M = Multi track operations.
F = FM/MFM 0=single/1=double
S = skip deleted.
H = Head number.
DD = drive.
Sectsize = 128 * 2^x... 2=512.
lgap3 = std 42, min = 32, std =27 3.5.
tl = track length/#sectors.
*/
/* Result phase.
ST0
IC 00= normal.
01 = abnormal.
10 = invalid
11 = abnomral, polling.
SE Seek end.
UC Unit Check
NR Drive not ready
HD head
US drive number
ST1
EN End Cyl
0
DE Data error.
TO Timeout/DMA error.
NDAT No data.
NW Not writable
NID No address mark.
ST2
0
DADM Deleted address mark
CRCE Crc error.
WCYL Wrong cylinder
SEQ Seek equal
SERR Seek error.
BCYL Back cylinder.
NDAM: No data.
Cyl
Hd
S#
SS.
ST3
ESIG Error
WPDR Write protect
RDY Controller ready.
T00 Track zero.
DSDR Double sided.
HD Head select.
DD Drive selected.
*/
/* DCB control block.
DCB + 0C0
0 GORDER
0 - Read, FDLP Build, implied seek.
1 - Write, FDLP Build, implied seek.
2 - Read, implied seek.
3 - Write, implied seek.
4 - Read, FDLP Build.
5 - Write, FDLP Build.
6 - Read.
7 - Write.
8 - Seek.
9 - Recalibrate.
A - Drive status.
1 SORDER bit 0,1,2 Len 0 read/write 6 for format.
3,4,5 Density
0 DD 512x16
1 SD 128x26
2 SD 256x15
3 DD 256x26
4 DD 1024x8
5 DD 512x15
6 DD 2048x4
7 DD 4096x2.
6 - 1= write.
7 - 1= nodma.
0 EOT 16 MFM 1 N = 2 GPL = 1b
1 EOT 26 MFM 0 N = 0 GPL = 07
2 EOT 15 MFM 0 N = 1 GPL = 0e
3 EOT 26 MFM 1 N = 1 GPL = 0e
4 EOT 8 MFM 1 N = 3 GPL = 35
5 EOT 15 MFM 1 N = 2 GPL = 35
6 EOT 4 MFM 1 N = 4 GPL = 35
7 EOT 2 MFM 1 N = 6 GPL = 35
2 GSTAT
0 - Ok.
1 - Not Ready.
2 - Timeout
3 - Equipment Fault.
4 - Write protect
5 - Ridge double bit error.
6 - Data overrun
7 - Missing AM.
8 - Can't find header.
9 - header CRC
A - data CRC
FF - Illegal parameter in DCB order.
3 SSTAT
bit 01 - unit
2 - head
3 - two sided
4 - track 0
5 - ready
6 - write protect.
7 - fault.
4 RETRIES
5 RIDGE ADDR
6
7
8 BYTE COUNT
9
A BYTE COUNT READ.
B
C NEC ORDER
D Head/unit
E Cylinder
F Sector
10 -18 CMD 00-08 Command built by controller.
19 -1F STATUS 00-06 Status returned by the drive.
*/
int flp_read(uint32 dev, uint32 *data);
int flp_write(uint32 dev, uint32 data);
int flp_iord(uint32 *data);
void flp_start(UNIT *uptr, int drive);
t_stat flp_svc (UNIT *uptr);
t_stat flp_boot (int32, DEVICE *);
t_stat flp_attach(UNIT *uptr, CONST char *cptr);
t_stat flp_detach(UNIT *uptr);
void com_write_char(int line, uint8 ch);
t_stat flp_reset(DEVICE *dp);
t_stat con_svc(UNIT *uptr);
uint8 flp_buf[4096];
/* Device context block */
struct ridge_dib flp_dib = {1, 1, flp_read, flp_write, flp_iord};
MTAB flp_mod[] = {
{MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "SLOT", "SLOT", &set_slot_num,
&show_slot_num, NULL},
{MTAB_XTD | MTAB_VDV | MTAB_VALR, 0, "DEV", "DEV", &set_dev_addr,
&show_dev_addr, NULL},
{ 0 }
};
UNIT flp_unit[] = {
{UDATA(&flp_svc, UNIT_ATTABLE, 0)},
{UDATA(&flp_svc, UNIT_ATTABLE, 0)},
{UDATA(&con_svc, UNIT_DIS, 0)},
};
DEVICE flp_dev = {
"FLP", flp_unit, NULL, flp_mod,
3, 16, 24, 1, 16, 8,
NULL, NULL, &flp_reset, &flp_boot, &flp_attach, &flp_detach,
&flp_dib, DEV_DEBUG, 0, dev_debug, NULL, NULL,
};
int
flp_read(uint32 dev, uint32 *data)
{
UNIT *uptr = &flp_unit[0];
*data = uptr->STATUS & 0xFFFF02;
*data |= (flp_dib.dev_num << 24) & 0xff000000;
if (uptr->STATUS & 0x4)
uptr->STATUS &= ~7;
return (uptr->STATUS & 0x2) ? 1 : 0;
}
int
flp_write(uint32 dev, uint32 data)
{
UNIT *uptr = &flp_unit[0];
int cmd = (data >> 24) & 0xff;
/* Check if command can be accepted */
if (uptr->STATUS & 3) {
return 1;
}
sim_debug(DEBUG_EXP, &flp_dev, "Start cmd %2x\n", cmd);
if (cmd < 0x80) {
com_write_char(0, cmd);
uptr->STATUS = (0x80 << 16);
} else if ((cmd & 0xc0) == 0xc0) {
switch (cmd) {
case 0xc0: /* Boot floppy left */
(void)flp_boot(0, &flp_dev);
break;
case 0xc1: /* Update DCB */
uptr->DCB = M[0x3c0fc >> 2];
case 0xc3: /* Read one char port 0 no irq */
uptr->STATUS = (0x80 << 16) | 1;
ext_irq = 1;
break;
case 0xc2: /* Read one char port 0 no irq */
uptr->STATUS = 2;
/* Fall through */
case 0xff: /* Read one char port 0 irq */
flp_unit[2].u3 = cmd;
break;
}
return 0;
} else if ((cmd & 0xe0) == 0x80) {
switch (cmd & 0x1f) {
case 0x06: /* Start left floppy */
case 0x07: /* Start right floppy */
flp_start(uptr, cmd & 1);
sim_activate(uptr, 20);
break;
case 0x00: /* Write on port 0 */
case 0x01: /* Write on port 1 */
case 0x02: /* Write on port 2 */
case 0x03: /* Write on port 3 */
case 0x04: /* Write on printer */
case 0x05: /* Write on plotter */
case 0x08: /* Read on port 0 */
case 0x09: /* Read on port 1 */
case 0x0a: /* Read on port 2 */
case 0x0b: /* Read on port 3 */
case 0x0c: /* Control on port 0 */
case 0x0d: /* Control on port 1 */
case 0x0e: /* Control on port 2 */
case 0x0f: /* Control on port 3 */
case 0x18: /* Read one char on port 0 */
case 0x19: /* Read one char on port 1 */
case 0x1a: /* Read one char on port 2 */
case 0x1b: /* Read one char on port 3 */
break;
}
} else {
/* undefined */
}
return 0;
}
int
flp_iord(uint32 *data)
{
UNIT *uptr = &flp_unit[0];
*data = uptr->STATUS & 0x0FFFF02;
*data |= ((uint32)flp_dib.dev_num) << 24;
/* Check if irq pending */
if (uptr->STATUS & 1) {
uptr->STATUS &= ~1;
return 1;
}
return 0;
}
/* Write port DCB.
0 GORDER
1 - Write block of up to 256 chars.
3 - Single Char (SORDER)
5 - assert break.
1 SORDER char for 3.
2 GSTAT not used.
3 SSTAT not used.
4 RETRIES not used.
5 ADDRESS
6
7
8 REQUEST BYTE COUNT
9
A BYTES TRANSFERED
B
Read port DCB.
0 GORDER
0 - Read term by count or MAP
1 SORDER not used.
2 GSTAT not used.
3 SSTAT not used.
4 RETRIES not used.
5 ADDRESS
6
7
8 REQUEST BYTE COUNT
9
A BYTES TRANSFERED
B
Control port DCB.
0 GORDER
0 - Return termtype in SORDER
1 - Set termtype from SORDER
2 - Return Baud rate in SORDER
3 - Set Baud rate from SORDER
4 - Return SIO status
5 - Set SIO registers
6 - Abort read in progress
7 - abort write in progress.
8 - Read map into memory
9 - Write map from memory.
1 SORDER PARM1
2 GSTAT PARM2
3 SSTAT PARM3
Termtype:
Bit 0 - Uses XOFF.
1 - Generate XOFF
2 - Clear DTR.
3 - Send IRQ when port stat changes.
Map... bit 0 - port 0.
1 - port 1.
2 - port 2.
3 - port 3.
Initial zero except 3 and D. If char received on line has bit set, stop read.
*/
struct _dcb {
uint8 gorder; /* Order code */
uint8 sorder;
uint8 gstat; /* Output status */
uint8 sstat;
uint32 addr; /* transfer address */
uint16 count; /* byte count */
uint16 xcount; /* transfer count */
uint8 retries;
uint8 order; /* NEC 765 order code */
uint8 hd; /* Head */
uint8 cyl; /* Cylinder */
uint8 sect; /* Sector */
uint8 cmd[9]; /* NEC 765 command sequenece */
uint8 stat[7]; /* Status */
int stat_len; /* Size of status */
int sect_sz; /* Size of sector */
} flp_dcb;
static uint8 order[] = {
BLD_OP|SEEK_OP|READ_OP, /* 0 - Read, FDLP Build, implied seek. */
BLD_OP|SEEK_OP|WRIT_OP, /* 1 - Write, FDLP Build, implied seek. */
SEEK_OP|READ_OP, /* 2 - Read, implied seek. */
SEEK_OP|WRIT_OP, /* 3 - Write, implied seek. */
BLD_OP|READ_OP, /* 4 - Read, FDLP Build. */
BLD_OP|WRIT_OP, /* 5 - Write, FDLP Build. */
READ_OP, /* 6 - Read. */
WRIT_OP, /* 7 - Write. */
BLD_OP|SEEK_OP|SK_OP, /* 8 - Seek. */
BLD_OP|SEEK_OP|SK_OP, /* 9 - Recalibrate. */
BLD_OP|ST_OP, /* A - Drive status. */
};
struct _flp_data {
uint8 eot;
uint8 n;
uint8 gpl;
uint8 dtl;
uint8 mfm;
int ssz;
} flp_data[] = {
{16, 2, 0x1b, 0xff, 1, 512},
{26, 0, 0x07, 0x80, 0, 128},
{15, 1, 0x0e, 0xff, 0, 256},
{26, 1, 0x0e, 0xff, 1, 256},
{ 8, 3, 0x35, 0xff, 1, 1024},
{15, 2, 0x35, 0xff, 1, 512},
{ 4, 4, 0x35, 0xff, 1, 2048},
{ 2, 6, 0x35, 0xff, 1, 4096},
};
void
flp_start(UNIT *uptr, int drive)
{
UNIT *fluptr;
int gorder;
/* Find actual unit */
fluptr = &flp_unit[drive & 1];
fluptr->up8 = (void *)uptr;
/* Read first word of DCB + 0xC0 */
flp_dcb.gorder = io_dcbread_byte(uptr, 0xC0);
flp_dcb.sorder = io_dcbread_byte(uptr, 0xC1);
flp_dcb.addr = io_dcbread_addr(uptr, 0xC5);
flp_dcb.count = io_dcbread_half(uptr, 0xC8);
flp_dcb.xcount = 0;
flp_dcb.order = io_dcbread_byte(uptr, 0xCC);
flp_dcb.hd = io_dcbread_byte(uptr, 0xCD);
flp_dcb.cyl = io_dcbread_byte(uptr, 0xCE);
flp_dcb.sect = io_dcbread_byte(uptr, 0xCF);
sim_debug(DEBUG_DETAIL, &flp_dev,
"Start floppy go=%2x so=%2x a=%6x c=%4x o=%2x h=%d t=%d s=%d\n\r",
flp_dcb.gorder, flp_dcb.sorder, flp_dcb.addr, flp_dcb.count, flp_dcb.order,
flp_dcb.hd, flp_dcb.cyl, flp_dcb.sect);
if (flp_dcb.gorder > 10) {
/* Invalid */
io_dcbwrite_byte(uptr, 0xc2, 0xff);
uptr->STATUS = ((0x86 + drive) << 16) | (0xff << 8) | 1;
ext_irq = 1;
return;
}
gorder = order[flp_dcb.gorder];
if ((gorder & BLD_OP) != 0) { /* Build command */
int den = (flp_dcb.sorder >> 3) & 7;
int i = 0;
if (gorder & SK_OP) {
flp_dcb.cmd[i++] = CMD_SEEK;
flp_dcb.cmd[i++] = flp_dcb.hd;
flp_dcb.cmd[i++] = flp_dcb.cyl;
if (flp_dcb.gorder & 1)
flp_dcb.cyl = 0; /* Force recalbirate */
} else if (gorder & ST_OP) {
flp_dcb.cmd[i++] = CMD_CHKDR;
flp_dcb.cmd[i++] = flp_dcb.hd;
} else {
flp_dcb.cmd[i++] = flp_dcb.order; /* 0 */
flp_dcb.cmd[i++] = flp_dcb.hd; /* 1 */
if ((flp_dcb.cmd[0] & 0x0f) != 0xd) {
flp_dcb.cmd[i++] = flp_dcb.cyl; /* 2 */
flp_dcb.cmd[i++] = (flp_dcb.hd & 0x4) != 0; /* 3 */
flp_dcb.cmd[i++] = flp_dcb.sect; /* 4 */
}
flp_dcb.cmd[i++] = flp_data[den].n; /* N */ /* 2 or 5 */
flp_dcb.cmd[i++] = flp_data[den].eot; /* EOT */
flp_dcb.cmd[i++] = flp_data[den].gpl; /* GPL */
flp_dcb.cmd[i++] = flp_data[den].dtl; /* DTL */
if (flp_data[den].mfm)
flp_dcb.cmd[0] |= 0x40;
}
} else {
io_dcbread_blk(uptr, 0xD0, &flp_dcb.cmd[0], 9);
}
if ((gorder & SEEK_OP) != 0) /* Seek first */
fluptr->PHASE = PHASE_SEEK;
else
fluptr->PHASE = PHASE_CMD;
flp_dcb.stat[0] = (flp_dcb.cmd[1] & 0x7);
flp_dcb.stat_len = 0;
if ((fluptr->flags & UNIT_ATT) == 0) {
flp_dcb.stat[0] |= 0xc8;
fluptr->PHASE = PHASE_RES;
}
flp_dcb.gstat = 0;
sim_activate(fluptr, 200);
}
t_stat
flp_svc (UNIT *uptr)
{
int flags;
int len;
int i;
/* Read status to decide action */
switch (uptr->PHASE) {
case PHASE_IDLE: /* Done with commands, just idle out */
return SCPE_OK;
case PHASE_SEEK:
/* Step in/out based on current cylinder, requested cylinder */
/* Match, PHASE = PHASE_CMD */
if (uptr->CYL < flp_dcb.cyl)
uptr->CYL++;
else if (uptr->CYL > flp_dcb.cyl)
uptr->CYL--;
else
uptr->PHASE = PHASE_CMD;
sim_debug(DEBUG_DETAIL, &flp_dev, "Seek n=%2d c=%2d\n\r", flp_dcb.cyl, uptr->CYL);
sim_activate(uptr, 2000);
return SCPE_OK;
case PHASE_CMD:
/* Decode command */
switch(flp_dcb.cmd[0] & 0xf) {
case CMD_RECAL: /* Recalibrate drive */
flp_dcb.cmd[2] = 0;
/* Fall through */
case CMD_SEEK: /* Seek */
if (uptr->CYL == flp_dcb.cmd[2]) {
flp_dcb.stat[0] |= 0x20;
uptr->PHASE = PHASE_RES;
sim_activate(uptr, 10);
return SCPE_OK;
}
flp_dcb.cyl = flp_dcb.cmd[2];
uptr->PHASE = PHASE_SEEK;
sim_activate(uptr, 10);
return SCPE_OK;
case CMD_CHKIR: /* Check IRQ */
flp_dcb.stat[0] = 0;
flp_dcb.stat_len = 2;
uptr->PHASE = PHASE_RES;
sim_activate(uptr, 10);
return SCPE_OK;
case CMD_CHKDR: /* Check drive */
uptr->PHASE = PHASE_RES;
sim_activate(uptr, 10);
return SCPE_OK;
case CMD_RDSEC: /* Read sector */
case CMD_RDTRK: /* Read track */
case CMD_WRSEC: /* Write sector */
case CMD_WRDEL: /* Write delete */
case CMD_RDDEL: /* Read delete */
/* Make sure cylinder is correct */
flp_dcb.stat[1] = 0;
flp_dcb.stat[2] = 0;
flp_dcb.stat[3] = flp_dcb.cmd[2]; /* C */
flp_dcb.stat[4] = flp_dcb.cmd[3]; /* H */
flp_dcb.stat[5] = flp_dcb.cmd[4]; /* R */
flp_dcb.stat[6] = flp_dcb.cmd[5]; /* N */
flp_dcb.stat_len = 7;
if (uptr->CYL != flp_dcb.cmd[2]) {
flp_dcb.stat[0] |= 0x40;
flp_dcb.stat[1] = 0;
flp_dcb.stat[2] = 0x10;
uptr->PHASE = PHASE_RES;
} else {
uptr->PHASE = PHASE_EXEC;
}
sim_activate(uptr, 100);
return SCPE_OK;
case CMD_FIXDR: /* Fix drive */
case CMD_RDSID: /* Read sector ID */
case CMD_FMTTK: /* Format track */
uptr->PHASE = PHASE_EXEC;
sim_activate(uptr, 10);
return SCPE_OK;
default: /* Invalid command */
return SCPE_OK;
}
case PHASE_EXEC:
/* Transfer data to/from memory */
switch(flp_dcb.cmd[0] & 0xf) {
case CMD_RDSEC: /* Read sector */
/* cyl head sect */
flags = 0;
if (sectRead((DISK_INFO *)uptr->up7, flp_dcb.stat[3],
flp_dcb.stat[4], flp_dcb.stat[5],
&flp_buf[0], sizeof(flp_buf), &flags, &len) != SCPE_OK) {
uptr->PHASE = PHASE_RES;
sim_activate(uptr, 1000);
return SCPE_OK;
}
sim_debug(DEBUG_DETAIL, &flp_dev, "Read a=%6x c=%4x h=%x t=%d s=%d l=%d\n\r",
flp_dcb.addr, flp_dcb.count, flp_dcb.stat[4], flp_dcb.stat[3], flp_dcb.stat[5], len);
sim_debug(DEBUG_DATA, &dsk_dev, "Disk Read: %d bytes\n", len);
for (i = 0; i < len; i++) {
sim_debug(DEBUG_DATA, &dsk_dev, "%02x ", flp_buf[i]);
if ((i & 0xf) == 0xf)
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
}
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
if (len > flp_dcb.count)
len = flp_dcb.count;
io_write_blk(flp_dcb.addr, &flp_buf[0], len);
flp_dcb.count -= len;
flp_dcb.xcount += len;
flp_dcb.addr += len;
if (flp_dcb.stat[5] == flp_dcb.cmd[6]) {
flp_dcb.stat[5] = 1;
if(flp_dcb.stat[4]) {
flp_dcb.stat[3]++;
flp_dcb.stat[4] = 0;
} else {
flp_dcb.stat[4] = 1;
}
} else {
flp_dcb.stat[5]++;
}
if (flp_dcb.count == 0) {
uptr->PHASE = PHASE_RES;
sim_activate(uptr, 10);
} else {
sim_activate(uptr, 100);
}
return SCPE_OK;
case CMD_WRSEC: /* Write sector */
flags = 0;
len = flp_dcb.cmd[5];
if (len == 0) {
len = flp_dcb.cmd[8];
} else {
len *= 512;
}
if (len > flp_dcb.count)
len = flp_dcb.count;
io_read_blk(flp_dcb.addr, &flp_buf[0], len);
sim_debug(DEBUG_DATA, &dsk_dev, "Disk Write: %d bytes\n", len);
for (i = 0; i < len; i++) {
sim_debug(DEBUG_DATA, &dsk_dev, "%02x ", flp_buf[i]);
if ((i & 0xf) == 0xf)
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
}
sim_debug(DEBUG_DATA, &dsk_dev, "\n");
if (sectWrite((DISK_INFO *)uptr->up7, flp_dcb.stat[3],
flp_dcb.stat[4], flp_dcb.stat[5],
&flp_buf[0], sizeof(flp_buf), &flags, &len) != SCPE_OK) {
uptr->PHASE = PHASE_RES;
sim_activate(uptr, 1000);
return SCPE_OK;
}
flp_dcb.count -= len;
flp_dcb.xcount += len;
flp_dcb.addr += len;
if (flp_dcb.stat[5] == flp_dcb.cmd[6]) {
flp_dcb.stat[5] = 1;
if(flp_dcb.stat[4]) {
flp_dcb.stat[3]++;
flp_dcb.stat[4] = 0;
} else {
flp_dcb.stat[4] = 1;
}
} else {
flp_dcb.stat[5]++;
}
if (flp_dcb.count == 0) {
uptr->PHASE = PHASE_RES;
sim_activate(uptr, 10);
} else {
sim_activate(uptr, 100);
}
return SCPE_OK;
case CMD_RDTRK: /* Read track */
case CMD_WRDEL: /* Write delete */
case CMD_RDDEL: /* Read delete */
/* Make sure cylinder is correct */
flp_dcb.stat[1] = 0;
flp_dcb.stat[2] = 0;
flp_dcb.stat[3] = flp_dcb.cmd[2]; /* C */
flp_dcb.stat[4] = flp_dcb.cmd[3]; /* H */
flp_dcb.stat[5] = flp_dcb.cmd[4]; /* R */
flp_dcb.stat[6] = flp_dcb.cmd[5]; /* N */
flp_dcb.stat_len = 7;
if (uptr->CYL != flp_dcb.cmd[2]) {
flp_dcb.stat[0] |= 0x40;
flp_dcb.stat[1] = 0;
flp_dcb.stat[2] = 0x10;
uptr->PHASE = PHASE_RES;
} else {
uptr->PHASE = PHASE_EXEC;
}
sim_activate(uptr, 10);
return SCPE_OK;
case CMD_FIXDR: /* Fix drive */
case CMD_RDSID: /* Read sector ID */
case CMD_FMTTK: /* Format track */
uptr->PHASE = PHASE_EXEC;
sim_activate(uptr, 10);
return SCPE_OK;
default: /* Invalid command */
return SCPE_OK;
}
case PHASE_RES:
/* Save results back to memory */
io_dcbwrite_blk(uptr, 0xD9, &flp_dcb.stat[0], flp_dcb.stat_len);
io_dcbwrite_byte(uptr, 0xc2, flp_dcb.gstat);
flags = flp_dcb.hd & 7;
flags |= 0x28; /* Ready & Two sided */
if (uptr->CYL == 0)
flags |= 0x10;
io_dcbwrite_byte(uptr, 0xc3, flags);
io_dcbwrite_half(uptr, 0xca, flp_dcb.xcount);
sim_debug(DEBUG_DETAIL, &flp_dev,"Stop floppy %2x %4x %2x\n\r",
flags, flp_dcb.xcount, flp_dcb.gstat);
uptr->PHASE = PHASE_IRQ;
/* Fall Through */
case PHASE_IRQ:
if (((UNIT *)(uptr->up8))->STATUS & 1) {
sim_activate(uptr, 100);
return SCPE_OK;
}
((UNIT *)(uptr->up8))->STATUS = ((0x86 + (flp_dcb.hd & 1)) << 16) |
(flp_dcb.gstat << 8) | 1;
uptr->PHASE = PHASE_IDLE;
ext_irq = 1;
}
return SCPE_OK;
}
void
com_write_char(int line, uint8 ch)
{
sim_putchar(ch);
}
t_stat
con_svc(UNIT *uptr)
{
t_stat r;
uint8 ch;
sim_clock_coschedule (uptr, 1000);
r = sim_poll_kbd ();
if (r & SCPE_KFLAG) {
ch = r & 0377;
if (uptr->u3 != 0) {
if (uptr->u3 == 0xFF) {
flp_unit[0].STATUS = (0x88 << 16) | (ch << 8) | 1;
ext_irq = 1;
} else {
flp_unit[0].STATUS = ((0x80 | ch) << 16) | 6;
}
sim_debug(DEBUG_CMD, &flp_dev, "Read cmd %2x %2x\n", uptr->u3, ch);
uptr->u3 = 0;
} else {
if (ch == '\003')
cpu_unit.flags ^= (0x1 << (UNIT_V_UF + 4));
}
return SCPE_OK;
}
return r;
}
/*
* 00-01 Invalid
* 02 Read Diag
* 03 specify
* 04 sense drive status
* 05 Read
* 06 Write
* x7 Recalibrate
* 08 sense irq
* 09 write deleted
* 0a read id
* 0b Invalid
* 0c read delated
* 0d format
* 0e Invalid
* 0f seek
* 10 version
* 11 scan equal
* 12-6 Invalid
* 17 recalibrate
* 18 invalid
* 19 scan low or equal
* 1a-c invalid
* 1d scan high or equal
* 1e invalid
* 1f recalibrate
*/
t_stat
flp_boot(int32 unit_num, DEVICE *dptr)
{
UNIT *fluptr = &dptr->units[unit_num];
int i = 0;
if (unit_num != 0)
return SCPE_ARG;
if ((fluptr->flags & UNIT_ATT) == 0)
return SCPE_UNATT;
fluptr->up8 = (void *)fluptr;
/* Set up for generic read of track 2 */
flp_dcb.gorder = 0;
flp_dcb.sorder = 0;
flp_dcb.addr = 0x3e000;
flp_dcb.count = 8192;
flp_dcb.xcount = 0;
flp_dcb.order = 0x46;
flp_dcb.hd = 0;
flp_dcb.cyl = 2;
flp_dcb.sect = 1;
sim_debug(DEBUG_DETAIL, dptr,
"Boot floppy go=%2x so=%2x a=%6x c=%4x o=%2x h=%2x t=%2x s=%2x\n",
flp_dcb.gorder, flp_dcb.sorder, flp_dcb.addr, flp_dcb.count, flp_dcb.order, flp_dcb.hd,
flp_dcb.cyl, flp_dcb.sect);
flp_dcb.cmd[i++] = flp_dcb.order;
flp_dcb.cmd[i++] = flp_dcb.hd;
flp_dcb.cmd[i++] = flp_dcb.cyl;
flp_dcb.cmd[i++] = 0;
flp_dcb.cmd[i++] = flp_dcb.sect;
flp_dcb.cmd[i++] = flp_data[0].n; /* N */
flp_dcb.cmd[i++] = flp_data[0].eot; /* EOT */
flp_dcb.cmd[i++] = flp_data[0].gpl; /* GPL */
flp_dcb.cmd[i++] = flp_data[0].dtl; /* DTL */
fluptr->PHASE = PHASE_SEEK;
flp_dcb.stat[0] = (flp_dcb.cmd[1] & 0x7);
flp_dcb.stat_len = 0;
/* Set CPU into idle state */
cpu_boot(0);
sim_activate(fluptr, 20);
return SCPE_OK;
}
t_stat
flp_reset(DEVICE *dp)
{
flp_unit[0].DCB = 0x3c000;
flp_unit[0].STATUS = 0;
flp_unit[0].PHASE = PHASE_IDLE;
flp_unit[1].PHASE = PHASE_IDLE;
flp_unit[2].u3 = 0;
sim_clock_coschedule (&flp_unit[2], 1000);
return SCPE_OK;
}
/* Attach routine */
t_stat
flp_attach(UNIT *uptr, CONST char *cptr)
{
char header[4];
t_stat r;
r = attach_unit(uptr, cptr); /* attach unit */
if ( r != SCPE_OK) /* error? */
return r;
/* Determine length of this disk */
uptr->capac = sim_fsize(uptr->fileref);
if(uptr->capac > 0) {
char *rtn = fgets(header, 4, uptr->fileref);
if((rtn != NULL) && strncmp(header, "IMD", 3)) {
sim_printf("Only IMD disk images are supported\n");
return SCPE_OPENERR;
}
} else {
/* create a disk image file in IMD format. */
if (diskCreate(uptr->fileref, "Ridge32") != SCPE_OK) {
sim_printf("Failed to create IMD disk.\n");
return SCPE_OPENERR;
}
uptr->capac = sim_fsize(uptr->fileref);
}
uptr->up7 = (void *)diskOpen(uptr->fileref, TRUE);
uptr->CYL = 0;
return SCPE_OK;
}
/* Detach routine */
t_stat flp_detach(UNIT *uptr)
{
t_stat r;
int8 i;
r = diskClose((DISK_INFO **)&uptr->up7);
if (r != SCPE_OK)
return r;
uptr->up7 = NULL;
r = detach_unit(uptr); /* detach unit */
if (r != SCPE_OK)
return r;
return SCPE_OK;
}

428
Ridge32/ridge32_iobus.c Normal file
View File

@@ -0,0 +1,428 @@
/* Ridge32_iobus.c: Ridge 32 I/O bus simulation.
Copyright (c) 2019, Richard Cornwell
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
RICHARD CORNWELL 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.
The Ridge 32 system allowed for several different I/O controllers to be put
on the bus. Priority was determined by position on the bus. Because some of
the devices actually controlled several different unit types, the iobus module
is used to tell the simulator what boards are installed and what device
address they are at.
Devices addressed as 1 and 2 are special as they were the only two that
could be bootstraped.
The simulator supports up to 8 I/O boards consisting of:
FLP0/1: Floppy disk/terminal/line printer.
flp: 4 Units.
term: 8 Units. Unit zero is console.
lpt: 2 Units.
DSK0/1: Priam disk controller 60 and 142MB devices.
dsk0: 4 units.
dsk1: 4 units.
SMD0/1: SMD disk controller.
smd0: 4 units.
smd1: 4 units.
DISP: Monochrome display.
TAPE: Tape Controller.
tp: 4 units.
DRNIU: DR11 interface to NIU-150 network interface.
niu: 1 unit.
Empty: No card installed.
*/
#include "ridge32_defs.h"
int empty_read(uint32 dev, uint32 *data);
int empty_write(uint32 dev, uint32 data);
int empty_iord(uint32 *data);
DIB *dev_table[256]; /* Device table */
uint8 slot_dev[8]; /* Device in slot */
DIB null_dev = {0, 0, &empty_read, &empty_write, &empty_iord};
uint8
io_dcbread_byte(UNIT *uptr, int off)
{
uint32 word;
word = M[(uptr->DCB + off) >> 2];
word >>= 8 * (3 - (off & 0x3));
word &= 0xff;
return (uint8) word;
}
uint16
io_dcbread_half(UNIT *uptr, int off)
{
uint32 word1;
uint32 word2;
word1 = M[(uptr->DCB + off) >> 2];
word1 >>= 8 * (3 - (off & 0x3));
word1 &= 0xff;
word2 = M[(uptr->DCB + off + 1) >> 2];
word2 >>= 8 * (3 - ((off + 1) & 0x3));
word2 &= 0xff;
return (uint16) ((word1 << 8) | word2);
}
uint32
io_dcbread_addr(UNIT *uptr, int off)
{
uint32 word1;
uint32 word2;
uint32 word3;
word1 = M[(uptr->DCB + off) >> 2];
word1 >>= 8 * (3 - (off & 0x3));
word1 &= 0xff;
word2 = M[(uptr->DCB + off + 1) >> 2];
word2 >>= 8 * (3 - ((off + 1) & 0x3));
word2 &= 0xff;
word3 = M[(uptr->DCB + off + 2) >> 2];
word3 >>= 8 * (3 - ((off + 2) & 0x3));
word3 &= 0xff;
return ((word1 << 16) | (word2 << 8) | word3);
}
void
io_dcbread_blk(UNIT *uptr, int off, uint8 *data, int sz)
{
io_read_blk(uptr->DCB + off, data, sz);
}
void
io_read_blk(int addr, uint8 *data, int sz)
{
uint32 word;
int i;
for (i = 0; sz > 0; sz--, addr++) {
word = M[(addr & 0xffffff) >> 2];
word >>= 8 * (3 - (addr & 0x3));
data[i++] = (uint8)(word & 0xff);
if ((addr & 3) == 0) {
word = M[addr >> 2];
sim_debug(DEBUG_DETAIL, &cpu_dev, "Read %06x, data=%08x '%c%c%c%c'\n",
addr, word, isprint((word >> 24) & 0xff)?(word >> 24)& 0xff:'.',
isprint((word >> 16) & 0xff)?(word >> 16)& 0xff:'.',
isprint((word >> 8) & 0xff)?(word >> 8)& 0xff:'.',
isprint(word & 0xff)?word& 0xff:'.');
}
}
}
void
io_dcbwrite_byte(UNIT *uptr, int off, uint8 data)
{
int offset;
int addr = uptr->DCB + off;
offset = 8 * (3 - (addr & 0x3));
M[addr >> 2] &= ~(0xff << offset);
M[addr >> 2] |= ((uint32)(data)) << offset;
return;
}
void
io_dcbwrite_half(UNIT *uptr, int off, uint16 data)
{
io_dcbwrite_byte(uptr, off, (uint8)((data >> 8) & 0xff));
io_dcbwrite_byte(uptr, off+1, (uint8)(data & 0xff));
return;
}
void
io_dcbwrite_blk(UNIT *uptr, int off, uint8 *data, int sz)
{
io_write_blk(uptr->DCB + off, data, sz);
}
void
io_write_blk(int addr, uint8 *data, int sz)
{
int offset;
int i;
sim_debug(DEBUG_DETAIL, &cpu_dev, "blkWrite %06x, len=%4x\n", addr, sz);
for (i = 0; sz > 0; sz--, addr++) {
offset = 8 * (3 - (addr & 0x3));
M[addr >> 2] &= ~(0xff << offset);
M[addr >> 2] |= ((uint32)(data[i++])) << offset;
if ((addr & 3) == 3) {
uint32 word = M[addr >> 2];
sim_debug(DEBUG_DETAIL, &cpu_dev, "Write %06x, data=%08x '%c%c%c%c'\n",
addr, word, isprint((word >> 24) & 0xff)?(word >> 24)& 0xff:'.',
isprint((word >> 16) & 0xff)?(word >> 16)& 0xff:'.',
isprint((word >> 8) & 0xff)?(word >> 8)& 0xff:'.',
isprint(word & 0xff)?word& 0xff:'.');
}
}
}
int
io_read(uint32 dev_data, uint32 *data)
{
int dev;
int r;
dev = (dev_data >> 24) & 0xff;
r = dev_table[dev]->io_read(dev_data, data);
sim_debug(DEBUG_CMD, &cpu_dev, "Read %02x, data=%08x\n", dev, *data);
return r;
}
int
io_write(uint32 dev_data, uint32 data)
{
int dev;
int r;
dev = (dev_data >> 24) & 0xff;
sim_debug(DEBUG_CMD, &cpu_dev, "Write %02x, data=%08x\n", dev, data);
r = dev_table[dev]->io_write(dev_data, data);
return r;
}
/*
* Check if interrupt pending. if not return 0.
* If pending, find device and set IORD into data.
* then return 1.
*/
int
io_rd(uint32 *data)
{
int i;
if (ext_irq) {
for (i = 0; i < 8; i++) {
if (slot_dev[i] != 0) {
if (dev_table[slot_dev[i]]->io_iord(data)) {
return 1;
}
}
}
ext_irq = 0;
}
return 0;
}
int
empty_read(uint32 dev, uint32 *data)
{
return 2;
}
int
empty_write(uint32 dev, uint32 data)
{
return 2;
}
int
empty_iord(uint32 *data)
{
/* Should never occur */
return 0;
}
t_stat
chan_set_devs()
{
int i, j;
for (i = 0; i < 256; i++) {
dev_table[i] = &null_dev; /* Empty device */
}
for (i = 0; i < 8; i++) { /* Slots are empty */
slot_dev[i] = 0;
}
/* Build channel array */
for (i = 0; sim_devices[i] != NULL; i++) {
DEVICE *dptr = sim_devices[i];
DIB *dibp = (DIB *) dptr->ctxt;
int addr;
int slot;
/* If no DIB, not channel device */
if (dibp == NULL)
continue;
/* Skip disabled devices */
if (dptr->flags & DEV_DIS)
continue;
addr = dibp->dev_num;
slot = dibp->slot_num;
if (dev_table[addr] != &null_dev) {
fprintf(stderr, "Device conflict\n\r");
return SCPE_IERR;
}
if (slot_dev[slot] != 0) {
fprintf(stderr, "Slot error\n\r");
return SCPE_IERR;
}
dev_table[addr] = dibp;
slot_dev[slot] = addr;
}
return SCPE_OK;
}
/* Sets the address of a device */
t_stat
set_dev_addr(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
t_value newdev;
t_stat r;
int addr;
int slot;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
newdev = get_uint (cptr, 16, 0xff, &r);
if (r != SCPE_OK)
return r;
addr = dibp->dev_num;
slot = dibp->slot_num;
/* Clear out existing entry */
dev_table[addr] = &null_dev;
/* Check if device already at newdev */
if (dev_table[newdev] != &null_dev)
r = SCPE_ARG;
/* If not, point to new dev, else restore old */
if (r == SCPE_OK)
addr = newdev;
/* Update device entry */
dev_table[addr] = dibp;
return r;
}
t_stat
show_dev_addr(FILE * st, UNIT * uptr, int32 v, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
int addr;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
addr = dibp->dev_num;
fprintf(st, "dev=%02x", addr);
return SCPE_OK;
}
/* Put a device at a specific slot */
t_stat
set_slot_num(UNIT * uptr, int32 val, CONST char *cptr, void *desc)
{
DEVICE *dptr;
DIB *dibp;
t_value newslot;
t_stat r;
int addr;
int slot;
if (cptr == NULL)
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
newslot = get_uint (cptr, 16, 0x8, &r);
if (r != SCPE_OK)
return r;
if (newslot > 8)
return SCPE_ARG;
addr = dibp->dev_num;
slot = dibp->slot_num;
slot_dev[slot] = 0;
slot_dev[newslot] = addr;
return r;
}
t_stat
show_slot_num(FILE * st, UNIT * uptr, int32 v, CONST void *desc)
{
DEVICE *dptr;
DIB *dibp;
int addr;
int slot;
if (uptr == NULL)
return SCPE_IERR;
dptr = find_dev_from_unit(uptr);
if (dptr == NULL)
return SCPE_IERR;
dibp = (DIB *) dptr->ctxt;
if (dibp == NULL)
return SCPE_IERR;
slot = dibp->slot_num;
fprintf(st, "slot=%d", slot);
return SCPE_OK;
}

821
Ridge32/ridge32_sys.c Normal file
View File

@@ -0,0 +1,821 @@
/* ridge32_sys.c: Ridge 32 Simulator system interface.
Copyright (c) 2019, Richard Cornwell
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
ROBERT M SUPNIK 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.
*/
#include "ridge32_defs.h"
#include <ctype.h>
#include "sim_imd.h"
extern DEVICE cpu_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern uint32 *M;
/* SCP data structures and interface routines
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words for examine
sim_devices array of pointers to simulated devices
sim_stop_messages array of pointers to stop messages
sim_load binary loader
*/
char sim_name[] = "Ridge 32";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 16;
DEVICE *sim_devices[] = {
&cpu_dev,
&flp_dev,
&dsk_dev,
NULL
};
/* Simulator debug controls */
DEBTAB dev_debug[] = {
{"CMD", DEBUG_CMD, "Show command execution to devices"},
{"DATA", DEBUG_DATA, "Show data transfers"},
{"DETAIL", DEBUG_DETAIL, "Show details about device"},
{"TRAP", DEBUG_TRAP, "Show trap information"},
{"EXP", DEBUG_EXP, "Show exception information"},
{"INST", DEBUG_INST, "Show instruction execution"},
{0, 0}
};
const char *sim_stop_messages[] = {
"Unknown error",
"HALT",
"Breakpoint",
};
/* Load a image file into memory. */
t_stat sim_load (FILE *fileref, CONST char *cptr, CONST char *fnam, int flag)
{
DISK_INFO *disk;
uint8 buf[1024];
int i, sect;
uint32 flags;
uint32 len;
uint32 addr = 0x3e000;
uint32 data;
uint32 mask;
uint32 pa;
int offset;
disk = diskOpen(fileref, TRUE);
fprintf(stderr, " %06x ", addr);
for (sect = 1; sect < 17; sect++) {
if (sectRead(disk, 2, 0, sect, buf, 1024, &flags, &len) == SCPE_OK) {
for (i = 0; i <len; i++) {
offset = 8 * (3 - (addr & 0x3));
pa = addr >> 2;
mask = 0xff;
data = buf[i];
data <<= offset;
mask <<= offset;
M[pa] &= ~mask;
M[pa] |= data;
fprintf(stderr, "%02x ", buf[i]);
addr++;
if ((i & 0xf) == 0xf)
fprintf(stderr, "\n %06x ", addr);
}
} else {
fprintf(stderr, "Read error %d\n", sect);
}
}
diskClose(&disk);
return SCPE_NOFNC;
}
/* Symbol tables */
typedef struct _opcode {
uint8 opbase;
char *name;
uint8 type;
} t_opcode;
#define RZ 0 /* Zero register */
#define R1 1 /* One register */
#define RR 2 /* Register to register */
#define RI 3 /* Short immediate to register */
#define RX 4 /* Register index */
#define RN 5 /* Number */
#define M 6 /* Maint instruction */
#define IND 0x8 /* Indexed */
#define COND 0x10 /* Conditional */
#define PCREL 0x20 /* PC Relative */
#define SHORT 0x40 /* Short displacement */
#define LONG 0x80 /* Long displacment */
t_opcode optab[] = {
{ OP_MOVE, "MOVE", RR, },
{ OP_NEG, "NEG", RR, },
{ OP_ADD, "ADD", RR, },
{ OP_SUB, "SUB", RR, },
{ OP_MPY, "MPY", RR, },
{ OP_DIV, "DIV", RR, },
{ OP_REM, "REM", RR, },
{ OP_NOT, "NOT", RR, },
{ OP_OR, "OR", RR, },
{ OP_XOR, "XOR", RR, },
{ OP_AND, "AND", RR, },
{ OP_CBIT, "CBIT", RR, },
{ OP_SBIT, "SBIT", RR, },
{ OP_TBIT, "TBIT", RR, },
{ OP_CHK, "CHK", RR, },
{ OP_NOP, "NOP", RR, },
{ OP_MOVEI, "MOVEI", RI, },
{ OP_ADDI, "ADDI", RI, },
{ OP_SUBI, "SUBI", RI, },
{ OP_MPYI, "MPYI", RI, },
{ OP_NOTI, "NOTI", RI, },
{ OP_ANDI, "ANDI", RI, },
{ OP_CHKI, "CHKI", RI, },
{ OP_FIXT, "FIXT", RR, },
{ OP_FIXR, "FIXR", RR, },
{ OP_RNEG, "RNEG", RR, },
{ OP_RADD, "RADD", RR, },
{ OP_RSUB, "RSUB", RR, },
{ OP_RMPY, "RMPY", RR, },
{ OP_RDIV, "RDIV", RR, },
{ OP_MAKERD, "MAKERD", RR, },
{ OP_LCOMP, "LCOMP", RR, },
{ OP_FLOAT, "FLOAT", RR, },
{ OP_RCOMP, "RCOMP", RR, },
{ OP_EADD, "EADD", RR, },
{ OP_ESUB, "ESUB", RR, },
{ OP_EMPY, "EMPY", RR, },
{ OP_EDIV, "EDIV", RR, },
{ OP_DFIXT, "DFIXT", RR, },
{ OP_DFIXR, "DFIXR", RR, },
{ OP_DRNEG, "DRNEG", RR, },
{ OP_DRADD, "DRADD", RR, },
{ OP_DRSUB, "DRSUB", RR, },
{ OP_DRMPY, "DRMPY", RR, },
{ OP_DRDIV, "DRDIV", RR, },
{ OP_MAKEDR, "MAKEDR", RR, },
{ OP_DCOMP, "DCOMP", RR, },
{ OP_DFLOAT, "DFLOAT", RR, },
{ OP_DRCOMP, "DRCOMP", RR, },
{ OP_TRAP, "TRAP", RN, },
{ OP_SUS, "SUS", RR, },
{ OP_LUS, "LUS", RR, },
{ OP_RUM, "RUM", RZ, },
{ OP_LDREGS, "LDREGS", RR, },
{ OP_TRANS, "TRANS", RR, },
{ OP_DIRT, "DIRT", RR, },
{ OP_MOVESR, "MOVESR", RR, },
{ OP_MOVERS, "MOVERS", RR, },
{ OP_MAINT, "", M, },
{ OP_READ, "READ", RR, },
{ OP_WRITE, "WRITE", RR, },
{ 0x50, "TEST", RR|COND, },
{ 0x51, "TEST", RR|COND, },
{ 0x52, "TEST", RR|COND, },
{ 0x54, "TESTI", RI|COND, },
{ 0x55, "TESTI", RI|COND, },
{ 0x56, "TESTI", RI|COND, },
{ 0x58, "TEST", RR|COND, },
{ 0x59, "TEST", RR|COND, },
{ 0x5A, "TEST", RR|COND, },
{ 0x5C, "TESTI", RI|COND, },
{ 0x5D, "TESTI", RI|COND, },
{ 0x5E, "TESTI", RI|COND, },
{ OP_CALLR, "CALLR", RR, },
{ OP_RET, "RET", RR, },
{ OP_KCALL, "KCALL", RN, },
{ OP_LSL, "LSL", RR, },
{ OP_LSR, "LSR", RR, },
{ OP_ASL, "ASL", RR, },
{ OP_ASR, "ASR", RR, },
{ OP_DLSL, "DLSL", RR, },
{ OP_DLSR, "DLSR", RR, },
{ OP_CSL, "CSL", RR, },
{ OP_SEB, "SEB", RR, },
{ OP_LSLI, "LSLI", RI, },
{ OP_LSRI, "LSRI", RI, },
{ OP_ASLI, "ASLI", RI, },
{ OP_ASRI, "ASRI", RI, },
{ OP_DLSLI, "DLSLI", RI, },
{ OP_DLSRI, "DLSRI", RI, },
{ OP_CSLI, "CSLI", RI, },
{ OP_SEH, "SEH", RR, },
{ 0x80, "BR", RR|COND|PCREL|SHORT, },
{ 0x82, "BR", RR|COND|PCREL|SHORT, },
{ 0x83, "CALL", R1|PCREL|SHORT, },
{ 0x84, "BR", RR|COND|PCREL|SHORT, },
{ 0x85, "BR", RI|COND|PCREL|SHORT, },
{ 0x86, "BR", RI|COND|PCREL|SHORT, },
{ 0x87, "LOOP", RI|PCREL|SHORT, },
{ 0x88, "BR", RR|COND|PCREL|SHORT, },
{ 0x8A, "BR", RR|COND|PCREL|SHORT, },
{ 0x8B, "BR", RZ|PCREL|SHORT, },
{ 0x8C, "BR", RR|COND|PCREL|SHORT, },
{ 0x8D, "BR", RI|COND|PCREL|SHORT, },
{ 0x8E, "BR", RI|COND|PCREL|SHORT, },
{ 0x90, "BR", RR|COND|PCREL|LONG, },
{ 0x92, "BR", RR|COND|PCREL|LONG, },
{ 0x93, "CALL", R1|PCREL|LONG, },
{ 0x94, "BR", RR|COND|PCREL|LONG, },
{ 0x95, "BR", RI|COND|PCREL|LONG, },
{ 0x96, "BR", RI|COND|PCREL|LONG, },
{ 0x97, "LOOP", RI|PCREL|LONG, },
{ 0x98, "BR", RR|COND|PCREL|LONG, },
{ 0x9A, "BR", RR|COND|PCREL|LONG, },
{ 0x9B, "BR", RZ|PCREL|LONG, },
{ 0x9C, "BR", RR|COND|PCREL|LONG, },
{ 0x9D, "BR", RI|COND|PCREL|LONG, },
{ 0x9E, "BR", RI|COND|PCREL|LONG, },
{ 0xA0, "STOREB", RX|SHORT, },
{ 0xA1, "STOREB", RX|IND|SHORT, },
{ 0xA2, "STOREH", RX|SHORT, },
{ 0xA3, "STOREH", RX|IND|SHORT, },
{ 0xA6, "STORE", RX|SHORT, },
{ 0xA7, "STORE", RX|IND|SHORT, },
{ 0xA8, "STORED", RX|SHORT, },
{ 0xA9, "STORED", RX|IND|SHORT, },
{ 0xB0, "STOREB", RX|LONG, },
{ 0xB1, "STOREB", RX|IND|LONG, },
{ 0xB2, "STOREH", RX|LONG, },
{ 0xB3, "STOREH", RX|IND|LONG, },
{ 0xB6, "STORE", RX|LONG, },
{ 0xB7, "STORE", RX|IND|LONG, },
{ 0xB8, "STORED", RX|LONG, },
{ 0xB9, "STORED", RX|IND|LONG, },
{ 0xC0, "LOADB", RX|SHORT, },
{ 0xC1, "LOADB", RX|IND|SHORT, },
{ 0xC2, "LOADH", RX|SHORT, },
{ 0xC3, "LOADH", RX|IND|SHORT, },
{ 0xC6, "LOAD", RX|SHORT, },
{ 0xC7, "LOAD", RX|IND|SHORT, },
{ 0xC8, "LOADD", RX|SHORT, },
{ 0xC9, "LOADD", RX|IND|SHORT, },
{ 0xCE, "LADDR", RX|SHORT, },
{ 0xCF, "LADDR", RX|IND|SHORT, },
{ 0xD0, "LOADB", RX|LONG, },
{ 0xD1, "LOADB", RX|IND|LONG, },
{ 0xD2, "LOADH", RX|LONG, },
{ 0xD3, "LOADH", RX|IND|LONG, },
{ 0xD6, "LOAD", RX|LONG, },
{ 0xD7, "LOAD", RX|IND|LONG, },
{ 0xD8, "LOADD", RX|LONG, },
{ 0xD9, "LOADD", RX|IND|LONG, },
{ 0xDE, "LADDR", RX|LONG, },
{ 0xDF, "LADDR", RX|IND|LONG, },
{ 0xE0, "LOADBP", RX|PCREL|SHORT, },
{ 0xE1, "LOADBP", RX|IND|PCREL|SHORT, },
{ 0xE2, "LOADHP", RX|PCREL|SHORT, },
{ 0xE3, "LOADHP", RX|IND|PCREL|SHORT, },
{ 0xE6, "LOADP", RX|PCREL|SHORT, },
{ 0xE7, "LOADP", RX|IND|PCREL|SHORT, },
{ 0xE8, "LOADDP", RX|PCREL|SHORT, },
{ 0xE9, "LOADDP", RX|IND|PCREL|SHORT, },
{ 0xEE, "LADDRP", RX|PCREL|SHORT, },
{ 0xEF, "LADDRP", RX|IND|PCREL|SHORT, },
{ 0xF0, "LOADBP", RX|PCREL|LONG, },
{ 0xF1, "LOADBP", RX|IND|PCREL|LONG, },
{ 0xF2, "LOADHP", RX|PCREL|LONG, },
{ 0xF3, "LOADHP", RX|IND|PCREL|LONG, },
{ 0xF6, "LOADP", RX|PCREL|LONG, },
{ 0xF7, "LOADP", RX|IND|PCREL|LONG, },
{ 0xF8, "LOADDP", RX|PCREL|LONG, },
{ 0xF9, "LOADDP", RX|IND|PCREL|LONG, },
{ 0xFE, "LADDRP", RX|PCREL|LONG, },
{ 0xFF, "LADDRP", RX|IND|PCREL|LONG, },
{ 0, NULL, 0 }
};
CONST char *cond[] = {
">", "<", "=", "", ">", "<", "=", "",
"<=", ">=", "<>", "", "<=", ">=", "<>", ""};
CONST char *cond_str[] = {"<=", ">=", "<>", ">", "<", "=", NULL };
CONST uint8 cond_val[] = { 0x8, 0x9, 0xA, 0x0, 0x1, 0x2, 0xff };
CONST char *rone[] = {
"ELOGR", "ELOGW", "MAINT2", "MAINT3", "MAINT4", "TWRITED", "FLUSH",
"TRAPEXIT", "ITEST", "MAINT9", "MACHINEID", "VERSION", "CREG", "RDLOG",
"MAINT14", "MAINT15"};
void fprint_inst(FILE *of, t_addr addr, t_value *val) {
uint8 inst = val[0];
int i;
int l = 1;
t_opcode *tab;
uint32 disp = 0;
for (tab = optab; tab->name != NULL; tab++) {
if (tab->opbase == inst) {
if ((tab->type & 0xf) == M)
fputs(rone[val[1] & 0xF], of);
else
fputs(tab->name, of);
fputc(' ', of);
if (tab->type & (SHORT|LONG)) {
disp = (val[2] << 8) | val[3];
if (tab->type & LONG) {
disp <<= 16;
disp |= (val[4] << 8) | val[5];
} else if (disp & 0x8000) {
disp |= 0xffff0000;
}
}
if (tab->type & PCREL) {
disp = (disp + addr) & 0xffffff;
}
switch (tab->type & 0x7) {
case RR:
fprintf(of, "R%d", (val[1] >> 4) & 0xF);
if (tab->type & COND) {
fputs(cond[inst & 0xF], of);
} else {
fputc(',',of);
}
fprintf(of, "R%d", val[1] & 0xF);
if (tab->type & PCREL) {
fputc(',',of);
}
break;
case R1:
fprintf(of, "R%d,", (val[1] >> 4) & 0xF);
break;
case RI:
fprintf(of, "R%d", (val[1] >> 4) & 0xF);
if (tab->type & COND) {
fputs(cond[inst & 0xF], of);
} else {
fputc(',',of);
}
fprintf(of, "%d", val[1] & 0xF);
if (tab->type & (LONG|SHORT))
fputc(',',of);
/* Fall through */
case RZ:
break;
case M:
fprintf(of, "R%d", (val[1] >> 4) & 0xF);
break;
case RX:
fprintf(of, "R%d,", (val[1] >> 4) & 0xF);
if (tab->type & IND)
fprintf(of, "R%d,", val[1] & 0xF);
break;
case RN:
fprintf(of, "%d", val[1] & 0xFF);
break;
}
if (tab->type & (LONG|PCREL)) {
fprint_val(of, disp, 16, 32, PV_RZRO);
if (tab->type & LONG)
fputs(",L", of);
} else if (tab->type & SHORT) {
fprint_val(of, disp, 16, 16, PV_RZRO);
}
}
}
}
/* Symbolic decode
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
return = status code
*/
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val,
UNIT *uptr, int32 sw)
{
uint8 inst = *val;
int i;
int l = 1;
int rdx = 16;
t_opcode *tab;
uint32 num;
if (sw & SWMASK ('D'))
rdx = 10;
else if (sw & SWMASK ('O'))
rdx = 8;
else if (sw & SWMASK ('H'))
rdx = 16;
if (sw & SWMASK ('M')) {
l = 2;
if (inst & 0x80) {
l += 2;
if (inst & 0x10)
l += 2;
}
sw &= ~ SWMASK('F'); /* Can't do F and M at same time */
} else if (sw & SWMASK('F')) {
l = 4;
} else if (sw & SWMASK('W')) {
l = 2;
} else if (sw & SWMASK('B')) {
l = 1;
}
if (sw & SWMASK ('C')) {
fputc('\'', of);
for(i = 0; i < l; i++) {
char ch = val[i] & 0xff;
if (ch >= 0x20 && ch <= 0x7f)
fprintf(of, "%c", ch);
else
fputc('_', of);
}
fputc('\'', of);
}
if (sw & SWMASK ('M')) {
i = 0;
num = (uint32)(val[i++] << 8);
num |= (uint32)val[i++];
fprint_val(of, num, 16, 16, PV_RZRO);
fputc(' ', of);
if (inst & 0x80) {
num = (uint32)(val[i++] << 8);
num |= (uint32)val[i++];
fprint_val(of, num, 16, 16, PV_RZRO);
if ((inst & 0x10) != 0) {
num = (uint32)(val[i++] << 8);
num |= (uint32)val[i++];
fprint_val(of, num, 16, 16, PV_RZRO);
} else {
fputs(" ", of);
}
} else {
fputs(" ", of);
}
fputc(' ', of);
fprint_inst(of, addr, val);
} else {
num = 0;
for (i = 0; i < l && i < 4; i++)
num |= (uint32)val[i] << ((l-i-1) * 8);
fprint_val(of, num, rdx, l*8, PV_RZRO);
}
return -(l-1);
}
/*
* Collect register name.
*/
t_stat get_reg (CONST char *cptr, CONST char **tptr, int *reg)
{
while (sim_isspace (*cptr)) cptr++;
if ((*cptr == 'R') || (*cptr == 'r')) /* Skip R */
cptr++;
if ((*cptr >= '0') && (*cptr <= '9')) {
*reg = *cptr++ - '0';
if ((*cptr >= '0') && (*cptr <= '9'))
*reg = (*reg * 10) + (*cptr++ - '0');
if (*reg > 0xf)
return SCPE_ARG;
} else if ((*cptr >= 'a') && (*cptr <= 'f'))
*reg = (*cptr++ - 'a') + 10;
else if ((*cptr >= 'A') && (*cptr <= 'F'))
*reg = (*cptr++ - 'A') + 10;
else
return SCPE_ARG;
while (sim_isspace (*cptr)) cptr++;
*tptr = cptr;
return SCPE_OK;;
}
/*
* Collect disp in radix.
*/
t_stat get_disp (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val)
{
t_stat r;
r = SCPE_OK;
*val = (uint32)strtotv (cptr, tptr, radix);
if (cptr == *tptr)
r = SCPE_ARG;
else {
cptr = *tptr;
while (sim_isspace (*cptr)) cptr++;
*tptr = cptr;
}
return r;
}
/*
* Collect n in radix.
*/
t_stat get_n (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val)
{
t_stat r;
r = SCPE_OK;
*val = (uint32)strtotv (cptr, tptr, radix);
if ((cptr == *tptr) || (*val > 0xff))
r = SCPE_ARG;
else {
cptr = *tptr;
while (sim_isspace (*cptr)) cptr++;
*tptr = cptr;
}
return r;
}
/*
* Collect immediate in radix.
*/
t_stat get_imm (CONST char *cptr, CONST char **tptr, uint32 radix, uint32 *val)
{
t_stat r;
r = SCPE_OK;
*val = (uint32)strtotv (cptr, tptr, radix);
if ((cptr == *tptr) || (*val > 0xf))
r = SCPE_ARG;
else {
cptr = *tptr;
while (sim_isspace (*cptr)) cptr++;
*tptr = cptr;
}
return r;
}
/* Symbolic input
Inputs:
*cptr = pointer to input string
addr = current PC
uptr = pointer to unit
*val = pointer to output values
sw = switches
Outputs:
status = error status
*/
t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw)
{
int i;
int l = 1;
int rdx = 16;
char mod = 0;
t_opcode *tab;
t_stat r;
uint32 num;
uint32 max[5] = { 0, 0xff, 0xffff, 0, 0xffffffff };
CONST char *tptr;
char gbuf[CBUFSIZE];
if (sw & SWMASK ('D'))
rdx = 10;
else if (sw & SWMASK ('O'))
rdx = 8;
else if (sw & SWMASK ('H'))
rdx = 16;
if (sw & SWMASK('F')) {
l = 4;
} else if (sw & SWMASK('W')) {
l = 2;
}
if (sw & SWMASK ('C')) {
cptr = get_glyph_quoted(cptr, gbuf, 0); /* Get string */
for(i = 0; gbuf[i] != 0; i++) {
val[i] = gbuf[i];
}
return -(i - 1);
}
if (sw & SWMASK ('M')) {
cptr = get_glyph(cptr, gbuf, 0); /* Get opcode */
for (tab = optab; tab->name != NULL; tab++) {
if (sim_strcasecmp(tab->name, gbuf) == 0)
break;
}
if (tab->name == NULL) {
int j;
for (j = 0; j <= 0xF; j++) {
if (sim_strcasecmp(rone[j], gbuf) == 0) {
if ((r = get_reg(cptr, &tptr, &i)) != SCPE_OK)
return r;
val[0] = OP_MAINT;
val[1] = (j << 4) | i;
return -1;
}
}
return SCPE_ARG;
}
val[0] = tab->opbase;
l = 0;
switch (tab->type & 7) {
case RR:
if ((r = get_reg(cptr, &tptr, &i)) != SCPE_OK)
return r;
cptr = tptr;
val[1] = i << 4;
if (tab->type & COND) {
int j;
for (j = 0; cond_str[j] != NULL; j++) {
if (sim_strcasecmp(cond_str[j], gbuf) == 0) {
val[0] |= cond_val[j];
cptr += (cond_val[j] & 0x8) ? 2 : 1;
break;
}
}
if (cond_val[j] == 0xff)
return SCPE_ARG;
} else {
if (*cptr != ',')
return SCPE_ARG;
cptr++;
}
while (sim_isspace (*cptr)) cptr++;
if ((r = get_reg(cptr, &tptr, &i)) != SCPE_OK)
return r;
val[1] |= i;
cptr = tptr;
if (tab->type & PCREL) {
if (*cptr != ',')
return SCPE_ARG;
cptr++;
while (sim_isspace (*cptr)) cptr++;
if ((r = get_disp(cptr, &tptr, rdx, &num)) != SCPE_OK)
return SCPE_ARG;
cptr = tptr;
if (*cptr == ',') {
cptr++;
while (sim_isspace (*cptr)) cptr++;
if (*cptr != 'L' || *cptr != 'l')
return SCPE_ARG;
val[0] |= 0x10;
l = 4;
} else {
l = 2;
if (num > 0x10000)
return SCPE_ARG;
}
for (i = 0; i < l && i < 4; i++)
val[i+2] = (num >> (((l - 1) - i) * 8)) & 0xff;
}
return -(l-1);
case R1:
return SCPE_ARG;
case RI:
if ((r = get_reg(cptr, &tptr, &i)) != SCPE_OK)
return r;
val[1] = i << 4;
cptr = tptr;
if (tab->type & COND) {
int j;
for (j = 0; cond_str[j] != NULL; j++) {
if (sim_strcasecmp(cond_str[j], gbuf) == 0) {
val[0] |= cond_val[j];
cptr += (cond_val[j] & 0x8) ? 2 : 1;
break;
}
}
if (cond_val[j] == 0xff)
return SCPE_ARG;
} else {
if (*cptr != ',')
return SCPE_ARG;
cptr++;
}
while (sim_isspace (*cptr)) cptr++;
if ((r = get_imm(cptr, &tptr, rdx, &i)) != SCPE_OK)
return r;
val[1] |= i;
cptr = tptr;
if (tab->type & PCREL) {
if (*cptr != ',')
return SCPE_ARG;
cptr++;
while (sim_isspace (*cptr)) cptr++;
if ((r = get_disp(cptr, &tptr, rdx, &num)) != SCPE_OK)
return SCPE_ARG;
cptr = tptr;
if (*cptr == ',') {
cptr++;
while (sim_isspace (*cptr)) cptr++;
if (*cptr != 'L' || *cptr != 'l')
return SCPE_ARG;
val[0] |= 0x10;
l = 4;
} else {
l = 2;
if (num > 0x10000)
return SCPE_ARG;
}
for (i = 0; i < l && i < 4; i++)
val[i+2] = (num >> (((l - 1) - i) * 8)) & 0xff;
}
return -(l-1);
case RZ:
if (tab->type & PCREL) {
if ((r = get_disp(cptr, &tptr, rdx, &num)) != SCPE_OK)
return SCPE_ARG;
cptr = tptr;
if (*cptr == ',') {
cptr++;
while (sim_isspace (*cptr)) cptr++;
if (*cptr != 'L' || *cptr != 'l')
return SCPE_ARG;
val[0] |= 0x10;
l = 4;
} else {
l = 2;
if (num > 0x10000)
return SCPE_ARG;
}
for (i = 0; i < l && i < 4; i++)
val[i+2] = (num >> (((l - 1) - i) * 8)) & 0xff;
}
return -(l-1);
case RX:
if ((r = get_reg(cptr, &tptr, &i)) != SCPE_OK)
return r;
val[1] = i << 4;
cptr = tptr;
while (sim_isspace (*cptr)) cptr++;
if (*cptr != ',')
return SCPE_ARG;
cptr++;
r = get_reg(cptr, &tptr, &i);
if (r == SCPE_OK) {
val[1] |= num;
cptr = tptr;
if (*cptr != ',')
return SCPE_ARG;
cptr++;
}
if ((r = get_disp(cptr, &tptr, rdx, &num)) != SCPE_OK)
return SCPE_ARG;
cptr = tptr;
if (*cptr == ',') {
cptr++;
while (sim_isspace (*cptr)) cptr++;
if (*cptr != 'L' || *cptr != 'l')
return SCPE_ARG;
val[0] |= 0x10;
l = 4;
} else {
l = 2;
if (num > 0x10000)
return SCPE_ARG;
}
for (i = 0; i < l && i < 4; i++)
val[i+2] = (num >> (((l - 1) - i) * 8)) & 0xff;
return -(l-1);
case RN:
if ((r = get_n(cptr, &tptr, rdx, &i)) != SCPE_OK)
return r;
val[1] = i;
return -1;
}
}
num = get_uint(cptr, rdx, max[l], &r);
for (i = 0; i < l && i < 4; i++)
val[i] = (num >> (((l - 1) - i) * 8)) & 0xff;
return -(l-1);
}