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:
1779
Ridge32/ridge32_cpu.c
Normal file
1779
Ridge32/ridge32_cpu.c
Normal file
File diff suppressed because it is too large
Load Diff
170
Ridge32/ridge32_defs.h
Normal file
170
Ridge32/ridge32_defs.h
Normal 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
604
Ridge32/ridge32_dsk.c
Normal 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
978
Ridge32/ridge32_flp.c
Normal 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
428
Ridge32/ridge32_iobus.c
Normal 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
821
Ridge32/ridge32_sys.c
Normal 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user