Notes For V3.8

The makefile now works for Linux and most Unix's. However, for Solaris
and MacOS, you must first export the OSTYPE environment variable:

> export OSTYPE
> make

Otherwise, you will get build errors.

1. New Features

1.1 3.8-0

1.1.1 SCP and Libraries

- BREAK, NOBREAK, and SHOW BREAK with no argument will set, clear, and
  show (respectively) a breakpoint at the current PC.

1.1.2 GRI

- Added support for the GRI-99 processor.

1.1.3 HP2100

- Added support for the BACI terminal interface.
- Added support for RTE OS/VMA/EMA, SIGNAL, VIS firmware extensions.

1.1.4 Nova

- Added support for 64KW memory (implemented in third-party CPU's).

1.1.5 PDP-11

- Added support for DC11, RC11, KE11A, KG11A.
- Added modem control support for DL11.
- Added ASCII character support for all 8b devices.

1.2 3.8-1

1.2.1 SCP and libraries

- Added capability to set line connection order for terminal multiplexers.

1.2.2 HP2100

- Added support for 12620A/12936A privileged interrupt fence.
- Added support for 12792C eight-channel asynchronous multiplexer.

1.3 3.8-2

1.3.1 1401

- Added "no rewind" option to magtape boot.

1.3.2 PDP-11

- Added RD32 support to RQ
- Added debug support to RL

1.3.3 PDP-8

- Added FPP support (many thanks to Rick Murphy for debugging the code)

2. Bugs Fixed

Please see the revision history on http://simh.trailing-edge.com or
in the source module sim_rev.h.
This commit is contained in:
Bob Supnik 2010-04-26 06:04:00 -07:00 committed by Mark Pizzolato
parent 9c4779c061
commit 35eac703c3
55 changed files with 4948 additions and 760 deletions

View file

@ -1,7 +1,7 @@
Notes For V3.8
The makefile now works for Linux and most Unix's. Howevr, for Solaris
The makefile now works for Linux and most Unix's. However, for Solaris
and MacOS, you must first export the OSTYPE environment variable:
> export OSTYPE
@ -49,6 +49,21 @@ Otherwise, you will get build errors.
- Added support for 12620A/12936A privileged interrupt fence.
- Added support for 12792C eight-channel asynchronous multiplexer.
1.3 3.8-2
1.3.1 1401
- Added "no rewind" option to magtape boot.
1.3.2 PDP-11
- Added RD32 support to RQ
- Added debug support to RL
1.3.3 PDP-8
- Added FPP support (many thanks to Rick Murphy for debugging the code)
2. Bugs Fixed

View file

@ -1,6 +1,6 @@
/* altair_dsk.c: MITS Altair 88-DISK Simulator
Copyright (c) 1997-2005, Charles E. Owen
Copyright (c) 1997-2010, Charles E. Owen
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -325,6 +325,8 @@ int32 dsk12(int32 io, int32 data)
cur_sect[cur_disk]);*/
pos = DSK_TRACSIZE * cur_track[cur_disk];
pos += DSK_SECTSIZE * cur_sect[cur_disk];
if ((uptr == NULL) || (uptr->fileref == NULL))
return 0;
rtn = fseek(uptr -> fileref, pos, 0);
rtn = fread(dskbuf, 137, 1, uptr -> fileref);
cur_byte[cur_disk] = 1;

View file

@ -1,6 +1,6 @@
/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80)
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -144,6 +144,8 @@ extern int32 simh_dev (const int32 port, const int32 io, const int32 data);
extern int32 sr_dev (const int32 port, const int32 io, const int32 data);
extern void install_ALTAIRbootROM(void);
extern void do_SIMH_sleep(void);
extern void prepareMemoryAccessMessage(const t_addr loc);
extern void prepareInstructionMessage(const t_addr loc, const uint32 op);
extern FILE *sim_deb;
@ -1279,10 +1281,9 @@ static const uint8 cpTable[256] = {
128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,
};
/* remove comments to generate table contents and define globally NEED_SIM_VM_INIT
static void altairz80_init(void);
void (*sim_vm_init) (void) = &altairz80_init;
static void altairz80_init(void) {
/* remove comments to generate table contents and add a call to
altairz80_print_tables in the altairz80_init
static void altairz80_print_tables(void) {
*/
/* parityTable */
/*
@ -1591,7 +1592,7 @@ uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
printf("%s memory 0x%05x, handler=%p\n", unmap ? "Unmapping" : " Mapping",
addr, routine);
if (unmap) {
if (mmu_table[page].routine == routine) /* unmap only if it was mapped */
if (mmu_table[page].routine == routine) { /* unmap only if it was mapped */
if (MEMORYSIZE < MAXBANKSIZE)
if (addr < MEMORYSIZE)
mmu_table[page] = RAM_PAGE;
@ -1600,6 +1601,7 @@ uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
else
mmu_table[page] = RAM_PAGE;
}
}
else {
mmu_table[page] = ROM_PAGE;
mmu_table[page].routine = routine;
@ -1785,44 +1787,32 @@ static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) {
return (sim_brk_pend[0] && (loc == sim_brk_ploc[0])) ? MASK_BRK : FALSE;
}
static void prepareMemoryAccessMessage(t_addr loc) {
extern char memoryAccessMessage[];
sprintf(memoryAccessMessage, "Memory access breakpoint [%05xh]", loc);
}
#define PUSH(x) { \
MM_PUT_BYTE(SP, (x) >> 8); \
MM_PUT_BYTE(SP, x); \
}
#define CHECK_BREAK_BYTE(a) \
if (sim_brk_summ && sim_brk_test((a) & 0xffff, SWMASK('M'))) { \
if (sim_brk_summ) { \
if (sim_brk_test((a) & 0xffff, SWMASK('M'))) { \
reason = STOP_MEM; \
prepareMemoryAccessMessage((a) & 0xffff); \
goto end_decode; \
} \
sim_brk_pend[0] = FALSE; \
}
#define CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2, iCode) \
if (sim_brk_summ) { \
br1 = sim_brk_lookup((a1) & 0xffff, SWMASK('M')); \
br2 = br1 ? FALSE : sim_brk_lookup((a2) & 0xffff, SWMASK('M'));\
if ((br1 == MASK_BRK) || (br2 == MASK_BRK)) { \
sim_brk_pend[0] = FALSE; \
} \
else if (br1 || br2) { \
int32 brl = sim_brk_lookup((a1) & 0xffff, SWMASK('M')); \
if ((brl == TRUE) || (brl == FALSE) && (sim_brk_lookup((a2) \
& 0xffff, SWMASK('M')) == TRUE)) { \
reason = STOP_MEM; \
if (br1) { \
prepareMemoryAccessMessage((a1) & 0xffff); \
} \
else { \
prepareMemoryAccessMessage((a2) & 0xffff); \
} \
prepareMemoryAccessMessage((brl ? (a1):(a2)) & 0xffff); \
iCode; \
goto end_decode; \
} \
else { \
sim_brk_pend[0] = FALSE; \
} \
}
#define CHECK_BREAK_TWO_BYTES(a1, a2) CHECK_BREAK_TWO_BYTES_EXTENDED(a1, a2,;)
@ -1908,7 +1898,7 @@ static t_stat sim_instr_mmu (void) {
register uint32 tStates;
uint32 tStatesInSlice; /* number of t-states in 10 mSec time-slice */
uint32 startTime, now;
int32 br1, br2, tStateModifier = FALSE;
int32 tStateModifier = FALSE;
switch_cpu_now = TRUE; /* hharte */
@ -1991,12 +1981,13 @@ static t_stat sim_instr_mmu (void) {
}
if (sim_brk_summ) {
if (sim_brk_lookup(PC, SWMASK('E')) == TRUE) { /* breakpoint? */
if (sim_brk_test(PC, (2u << SIM_BKPT_V_SPC) | SWMASK('E'))) { /* breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
break;
}
if (sim_brk_test(GetBYTE(PC), (1u << SIM_BKPT_V_SPC) | SWMASK('I'))) { /* instruction breakpoint? */
reason = STOP_IBKPT; /* stop simulation */
reason = STOP_INSTR; /* stop simulation */
prepareInstructionMessage(PC, GetBYTE(PC));
break;
}
}
@ -3826,7 +3817,7 @@ static t_stat sim_instr_mmu (void) {
case 0xdd: /* DD prefix */
CHECK_CPU_8080;
switch (op = RAM_PP(PC)) {
switch (RAM_PP(PC)) {
case 0x09: /* ADD IX,BC */
tStates += 15;
@ -4712,7 +4703,7 @@ static t_stat sim_instr_mmu (void) {
case 0xed: /* ED prefix */
CHECK_CPU_8080;
switch (op = RAM_PP(PC)) {
switch (RAM_PP(PC)) {
case 0x40: /* IN B,(C) */
tStates += 12;
@ -5205,7 +5196,6 @@ static t_stat sim_instr_mmu (void) {
case 0xb0: /* LDIR */
tStates -= 5;
acu = HIGH_REGISTER(AF);
BC &= ADDRMASK;
if (BC == 0)
BC = 0x10000;
@ -5456,7 +5446,7 @@ static t_stat sim_instr_mmu (void) {
case 0xfd: /* FD prefix */
CHECK_CPU_8080;
switch (op = RAM_PP(PC)) {
switch (RAM_PP(PC)) {
case 0x09: /* ADD IY,BC */
tStates += 15;
@ -6388,10 +6378,10 @@ static char *ramTypeToString[] = { "AZ80", "HRAM", "VRAM", "CRAM" };
static t_stat chip_show(FILE *st, UNIT *uptr, int32 val, void *desc) {
fprintf(st, cpu_unit.flags & UNIT_CPU_OPSTOP ? "ITRAP, " : "NOITRAP, ");
if (chiptype <= MAX_CHIP_TYPE)
fprintf(st, chipTypeToString[chiptype]);
fprintf(st, "%s", chipTypeToString[chiptype]);
fprintf(st, ", ");
if (ramtype <= MAX_RAM_TYPE)
fprintf(st, ramTypeToString[ramtype]);
fprintf(st, "%s", ramTypeToString[ramtype]);
return SCPE_OK;
}
@ -6603,8 +6593,8 @@ static void cpu_set_chiptype_short(int32 value, uint32 need_cpu_clear) {
extern REG *sim_PC;
if ((chiptype == value) || (chiptype > MAX_CHIP_TYPE))
return; /* nothing to do */
if ((chiptype == CHIP_TYPE_8080) && (value == CHIP_TYPE_Z80) ||
(chiptype == CHIP_TYPE_Z80) && (value == CHIP_TYPE_8080)) {
if (((chiptype == CHIP_TYPE_8080) && (value == CHIP_TYPE_Z80)) ||
((chiptype == CHIP_TYPE_Z80) && (value == CHIP_TYPE_8080))) {
chiptype = value;
return;
}
@ -6783,7 +6773,7 @@ static t_stat cpu_set_memory(UNIT *uptr, int32 value, char *cptr, void *desc) {
return SCPE_ARG;
result = sscanf(cptr, "%i%n", &size, &i);
if ((result == 1) && (cptr[i] == 'K') && ((cptr[i + 1] == 0) ||
(cptr[i + 1] == 'B') && (cptr[i + 2] == 0)))
((cptr[i + 1] == 'B') && (cptr[i + 2] == 0))))
return set_size(size);
return SCPE_ARG;
}
@ -6791,6 +6781,7 @@ static t_stat cpu_set_memory(UNIT *uptr, int32 value, char *cptr, void *desc) {
/* AltairZ80 Simulator initialization */
void altairz80_init(void) {
cpu_clear();
/* altairz80_print_tables(); */
}
void (*sim_vm_init) (void) = &altairz80_init;

View file

@ -1,6 +1,6 @@
/* altairz80_defs.h: MITS Altair simulator definitions
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -57,7 +57,8 @@
#define STOP_HALT 0 /* HALT */
#define STOP_IBKPT 1 /* breakpoint (program counter) */
#define STOP_MEM 2 /* breakpoint (memory access) */
#define STOP_OPCODE 3 /* invalid operation encountered (8080, Z80, 8086) */
#define STOP_INSTR 3 /* breakpoint (instruction access) */
#define STOP_OPCODE 4 /* invalid operation encountered (8080, Z80, 8086) */
#define UNIT_CPU_V_OPSTOP (UNIT_V_UF+0) /* stop on invalid operation */
#define UNIT_CPU_OPSTOP (1 << UNIT_CPU_V_OPSTOP)
@ -74,8 +75,11 @@
#define UNIT_CPU_V_SWITCHER (UNIT_V_UF+6) /* switcher 8086 <--> 8080/Z80 enabled */
#define UNIT_CPU_SWITCHER (1 << UNIT_CPU_V_SWITCHER)
#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) \
|| defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__))
#if defined (__linux) || defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__)
#define UNIX_PLATFORM 1
#else
#define UNIX_PLATFORM 0
#endif
#define ADDRESS_FORMAT "[0x%05x]"
@ -86,7 +90,7 @@
#define NLP "\n"
#endif
#if defined (__MWERKS__) && defined (macintosh)
#if (defined (__MWERKS__) && defined (macintosh)) || defined(__DECC)
#define __FUNCTION__ __FILE__
#endif

View file

@ -1,6 +1,6 @@
/* altairz80_dsk.c: MITS Altair 88-DISK Simulator
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -319,7 +319,7 @@ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) {
}
static int32 dskseek(const UNIT *xptr) {
return fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] +
return sim_fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] +
DSK_SECTSIZE * current_sector[current_disk], SEEK_SET);
}
@ -338,9 +338,9 @@ static void writebuf(void) {
printf("DSK%i: " ADDRESS_FORMAT " fseek failed D%d T%d S%d" NLP, current_disk,
PCX, current_disk, current_track[current_disk], current_sector[current_disk]);
}
rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
if (rtn != 1) {
printf("DSK%i: " ADDRESS_FORMAT " fwrite failed T%d S%d Return=%d" NLP, current_disk,
rtn = sim_fwrite(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref);
if (rtn != DSK_SECTSIZE) {
printf("DSK%i: " ADDRESS_FORMAT " sim_fwrite failed T%d S%d Return=%d" NLP, current_disk,
PCX, current_track[current_disk], current_sector[current_disk], rtn);
}
}
@ -507,7 +507,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
/* Disk Data In/Out */
int32 dsk12(const int32 port, const int32 io, const int32 data) {
int32 i;
int32 i, rtn;
UNIT *uptr;
if (current_disk >= NUM_OF_DSK) {
@ -530,8 +530,21 @@ int32 dsk12(const int32 port, const int32 io, const int32 data) {
PCX, current_disk, current_track[current_disk], current_sector[current_disk]));
for (i = 0; i < DSK_SECTSIZE; i++)
dskbuf[i] = 0;
dskseek(uptr);
fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref);
if (dskseek(uptr)) {
if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) {
warnDSK12++;
printf("DSK%i: " ADDRESS_FORMAT " fseek error D%d T%d S%d" NLP, current_disk,
PCX, current_disk, current_track[current_disk], current_sector[current_disk]);
}
}
rtn = sim_fread(dskbuf, 1, DSK_SECTSIZE, uptr -> fileref);
if (rtn != DSK_SECTSIZE) {
if ((dsk_dev.dctrl & VERBOSE_MSG) && (warnDSK12 < warnLevelDSK)) {
warnDSK12++;
printf("DSK%i: " ADDRESS_FORMAT " sim_fread error D%d T%d S%d" NLP, current_disk,
PCX, current_disk, current_track[current_disk], current_sector[current_disk]);
}
}
current_byte[current_disk] = 0;
}
return dskbuf[current_byte[current_disk]++] & 0xff;

View file

@ -1,6 +1,6 @@
/* altairz80_sio.c: MITS Altair serial I/O card
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -105,8 +105,8 @@
#define PORT_TABLE_SIZE 256 /* size of port mapping table */
#define SLEEP_ALLOWED_START_DEFAULT 100 /* default initial value for sleepAllowedCounter*/
#define DEFAULT_TIMER_DELTA 100 /* default value for timer delta in ms */
static t_stat sio_set_verbose (UNIT *uptr, int32 value, char *cptr, void *desc);
static t_stat simh_dev_set_timeron (UNIT *uptr, int32 value, char *cptr, void *desc);
static t_stat simh_dev_set_timeroff (UNIT *uptr, int32 value, char *cptr, void *desc);
static t_stat sio_reset(DEVICE *dptr);
@ -154,6 +154,19 @@ extern UNIT cpu_unit;
extern volatile int32 stop_cpu;
extern int32 sim_interval;
#define TRACE_PRINT(device, level, args) if (device.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB generic_dt[] = {
{ "IN", IN_MSG },
{ "OUT", OUT_MSG },
{ "CMD", CMD_MSG },
{ "VERBOSE", VERBOSE_MSG },
{ NULL, 0 }
};
/* SIMH pseudo device status registers */
/* ZSDOS clock definitions */
static time_t ClockZSDOSDelta = 0; /* delta between real clock and Altair clock */
@ -168,12 +181,12 @@ static int32 setClockCPM3Adr = 0; /* address in M of 5 byte parame
static int32 getClockCPM3Pos = 0; /* determines state for sending clock information */
static int32 daysCPM3SinceOrg = 0; /* days since 1 Jan 1978 */
/* interrupt related */
/* timer interrupt related */
static uint32 timeOfNextInterrupt; /* time when next interrupt is scheduled */
int32 timerInterrupt = FALSE; /* timer interrupt pending */
int32 timerInterruptHandler = 0x0fc00; /* default address of interrupt handling routine */
static int32 setTimerInterruptAdrPos= 0; /* determines state for receiving timerInterruptHandler */
static int32 timerDelta = 100; /* interrupt every 100 ms */
static int32 timerDelta = DEFAULT_TIMER_DELTA; /* interrupt every 100 ms */
static int32 setTimerDeltaPos = 0; /* determines state for receiving timerDelta */
/* stop watch and timer related */
@ -270,7 +283,7 @@ static MTAB sio_mod[] = {
{ UNIT_SIO_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */
{ UNIT_SIO_BS, UNIT_SIO_BS, "DEL", "DEL", NULL }, /* map backspace to delete */
{ UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */
{ UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", &sio_set_verbose },
{ UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", NULL },
/* verbose, display warning messages */
{ UNIT_SIO_MAP, 0, "NOMAP", "NOMAP", NULL }, /* disable character mapping */
{ UNIT_SIO_MAP, UNIT_SIO_MAP, "MAP", "MAP", NULL }, /* enable all character mapping */
@ -291,12 +304,16 @@ DEVICE sio_dev = {
1, 10, 31, 1, 8, 8,
NULL, NULL, &sio_reset,
NULL, &sio_attach, &sio_detach,
NULL, 0, 0,
NULL, NULL, "Serial Input Output SIO"
NULL, DEV_DEBUG, 0,
generic_dt, NULL, "Serial Input Output SIO"
};
static MTAB ptpptr_mod[] = {
{ 0 }
};
static UNIT ptr_unit = {
UDATA (NULL, UNIT_SEQ | UNIT_ATTABLE | UNIT_ROABLE, 0)
UDATA (NULL, UNIT_ATTABLE | UNIT_ROABLE, 0)
};
static REG ptr_reg[] = {
@ -305,25 +322,25 @@ static REG ptr_reg[] = {
};
DEVICE ptr_dev = {
"PTR", &ptr_unit, ptr_reg, NULL,
"PTR", &ptr_unit, ptr_reg, ptpptr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE, 0,
NULL, NULL, "Paper Tape Reader PTR"
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
generic_dt, NULL, "Paper Tape Reader PTR"
};
static UNIT ptp_unit = {
UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0)
UDATA (NULL, UNIT_ATTABLE, 0)
};
DEVICE ptp_dev = {
"PTP", &ptp_unit, NULL, NULL,
"PTP", &ptp_unit, NULL, ptpptr_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL,
NULL, DEV_DISABLE, 0,
NULL, NULL, "Paper Tape Puncher PTP"
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
generic_dt, NULL, "Paper Tape Puncher PTP"
};
/* Synthetic device SIMH for communication
@ -373,37 +390,19 @@ static MTAB simh_mod[] = {
{ 0 }
};
#define TRACE_PRINT(level, args) if (simh_device.dctrl & level) { \
printf args; \
}
/* Debug Flags */
static DEBTAB simh_dt[] = {
{ "IN", IN_MSG },
{ "OUT", OUT_MSG },
{ "CMD", CMD_MSG },
{ "VERBOSE", VERBOSE_MSG },
{ NULL, 0 }
};
DEVICE simh_device = {
"SIMH", &simh_unit, simh_reg, simh_mod,
1, 10, 31, 1, 16, 4,
NULL, NULL, &simh_dev_reset,
NULL, NULL, NULL,
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
simh_dt, NULL, "Pseudo Device SIMH"
generic_dt, NULL, "Pseudo Device SIMH"
};
static void resetSIOWarningFlags(void) {
warnUnattachedPTP = warnUnattachedPTR = warnPTREOF = warnUnassignedPort = 0;
}
static t_stat sio_set_verbose(UNIT *uptr, int32 value, char *cptr, void *desc) {
resetSIOWarningFlags();
return SCPE_OK;
}
static t_stat sio_attach(UNIT *uptr, char *cptr) {
t_stat r = SCPE_IERR;
sio_unit.u3 = FALSE; /* no character in terminal input buffer */
@ -439,6 +438,7 @@ static void pollConnection(void) {
/* reset routines */
static t_stat sio_reset(DEVICE *dptr) {
int32 i;
TRACE_PRINT(sio_dev, VERBOSE_MSG, ("SIO: " ADDRESS_FORMAT " Reset" NLP, PCX));
sio_unit.u3 = FALSE; /* no character in terminal input buffer */
resetSIOWarningFlags();
if (sio_unit.u4) { /* is terminal input attached to a file? */
@ -454,6 +454,7 @@ static t_stat sio_reset(DEVICE *dptr) {
}
static t_stat ptr_reset(DEVICE *dptr) {
TRACE_PRINT(ptr_dev, VERBOSE_MSG, ("PTR: " ADDRESS_FORMAT " Reset" NLP, PCX));
resetSIOWarningFlags();
ptr_unit.u3 = FALSE; /* End Of File not yet reached */
if (ptr_unit.flags & UNIT_ATT) /* attached? */
@ -464,6 +465,7 @@ static t_stat ptr_reset(DEVICE *dptr) {
}
static t_stat ptp_reset(DEVICE *dptr) {
TRACE_PRINT(ptp_dev, VERBOSE_MSG, ("PTP: " ADDRESS_FORMAT " Reset" NLP, PCX));
resetSIOWarningFlags();
sim_map_resource(0x12, 1, RESOURCE_TYPE_IO, &sio1s, dptr->flags & DEV_DIS);
sim_map_resource(0x13, 1, RESOURCE_TYPE_IO, &sio1d, dptr->flags & DEV_DIS);
@ -625,17 +627,18 @@ static void voidSleep(void) {
}
/* generic status port for keyboard input / terminal output */
int32 sio0s(const int32 port, const int32 io, const int32 data) {
static int32 sio0sCore(const int32 port, const int32 io, const int32 data) {
int32 ch, result;
SIO_PORT_INFO spi = lookupPortInfo(port, &ch);
assert(spi.port == port);
pollConnection();
if (io == 0) { /* IN */
if (sio_unit.u4) /* attached to a file? */
if (sio_unit.u4) { /* attached to a file? */
if (sio_unit.u5) /* EOF reached? */
sio_detach(&sio_unit); /* detach file and switch to keyboard input */
else
return spi.sio_can_read | spi.sio_can_write;
}
if (sio_unit.flags & UNIT_ATT) { /* attached to a port? */
if (tmxr_rqln(&TerminalLines[spi.terminalLine]))
result = spi.sio_can_read;
@ -664,13 +667,25 @@ int32 sio0s(const int32 port, const int32 io, const int32 data) {
checkSleep();
return spi.sio_can_write | spi.sio_cannot_read;
} /* OUT follows, no fall-through from IN */
if (spi.hasReset && (data == spi.sio_reset)) /* reset command */
if (spi.hasReset && (data == spi.sio_reset)) { /* reset command */
sio_unit.u3 = FALSE; /* indicate that no character is available */
TRACE_PRINT(sio_dev, CMD_MSG,
("SIO: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data));
}
return 0x00; /* ignored since OUT */
}
int32 sio0s(const int32 port, const int32 io, const int32 data) {
const int32 result = sio0sCore(port, io, data);
if ((io == 0) && (sio_dev.dctrl & IN_MSG))
printf("SIO_S: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x" NLP, PCX, port, result);
else if ((io) && (sio_dev.dctrl & OUT_MSG))
printf("SIO_S: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x" NLP, PCX, port, data);
return result;
}
/* generic data port for keyboard input / terminal output */
int32 sio0d(const int32 port, const int32 io, const int32 data) {
static int32 sio0dCore(const int32 port, const int32 io, const int32 data) {
int32 ch;
SIO_PORT_INFO spi = lookupPortInfo(port, &ch);
assert(spi.port == port);
@ -705,14 +720,23 @@ int32 sio0d(const int32 port, const int32 io, const int32 data) {
return 0x00; /* ignored since OUT */
}
int32 sio0d(const int32 port, const int32 io, const int32 data) {
const int32 result = sio0dCore(port, io, data);
if ((io == 0) && (sio_dev.dctrl & IN_MSG))
printf("SIO_D: " ADDRESS_FORMAT " IN(0x%03x) = 0x%02x" NLP, PCX, port, result);
else if ((io) && (sio_dev.dctrl & OUT_MSG))
printf("SIO_D: " ADDRESS_FORMAT " OUT(0x%03x) = 0x%02x" NLP, PCX, port, data);
return result;
}
/* PTR/PTP status port */
int32 sio1s(const int32 port, const int32 io, const int32 data) {
static int32 sio1sCore(const int32 port, const int32 io, const int32 data) {
if (io == 0) { /* IN */
/* reset I bit iff PTR unit not attached or
no more data available. O bit is always
set since write always possible. */
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* PTR is not attached */
if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) {
if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) {
warnUnattachedPTR++;
/*06*/ printf("PTR: " ADDRESS_FORMAT " Attempt to test status of unattached PTR[0x%02x]. 0x02 returned." NLP, PCX, port);
}
@ -722,24 +746,36 @@ int32 sio1s(const int32 port, const int32 io, const int32 data) {
(SIO_CAN_WRITE and SIO_CAN_READ) */
return ptr_unit.u3 ? SIO_CAN_WRITE : (SIO_CAN_READ | SIO_CAN_WRITE);
} /* OUT follows */
if (data == SIO_RESET)
if (data == SIO_RESET) {
ptr_unit.u3 = FALSE; /* reset EOF indicator */
TRACE_PRINT(ptr_dev, CMD_MSG,
("PTR: " ADDRESS_FORMAT " Command OUT(0x%03x) = 0x%02x" NLP, PCX, port, data));
}
return 0x00; /* ignored since OUT */
}
int32 sio1s(const int32 port, const int32 io, const int32 data) {
const int32 result = sio1sCore(port, io, data);
if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG)))
printf("PTP/PTR_S: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result);
else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG)))
printf("PTP/PTR_S: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data);
return result;
}
/* PTR/PTP data port */
int32 sio1d(const int32 port, const int32 io, const int32 data) {
static int32 sio1dCore(const int32 port, const int32 io, const int32 data) {
int32 ch;
if (io == 0) { /* IN */
if (ptr_unit.u3) { /* EOF reached, no more data available */
if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnPTREOF < warnLevelSIO)) {
if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnPTREOF < warnLevelSIO)) {
warnPTREOF++;
/*07*/ printf("PTR: " ADDRESS_FORMAT " PTR[0x%02x] attempted to read past EOF. 0x00 returned." NLP, PCX, port);
}
return 0x00;
}
if ((ptr_unit.flags & UNIT_ATT) == 0) { /* not attached */
if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTR < warnLevelSIO)) {
if ((ptr_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTR < warnLevelSIO)) {
warnUnattachedPTR++;
/*08*/ printf("PTR: " ADDRESS_FORMAT " Attempt to read from unattached PTR[0x%02x]. 0x00 returned." NLP, PCX, port);
}
@ -754,13 +790,22 @@ int32 sio1d(const int32 port, const int32 io, const int32 data) {
if (ptp_unit.flags & UNIT_ATT) /* unit must be attached */
putc(data, ptp_unit.fileref);
/* else ignore data */
else if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnattachedPTP < warnLevelSIO)) {
else if ((ptp_dev.dctrl & VERBOSE_MSG) && (warnUnattachedPTP < warnLevelSIO)) {
warnUnattachedPTP++;
/*09*/ printf("PTP: " ADDRESS_FORMAT " Attempt to output '0x%02x' to unattached PTP[0x%02x] - ignored." NLP, PCX, data, port);
}
return 0x00; /* ignored since OUT */
}
int32 sio1d(const int32 port, const int32 io, const int32 data) {
const int32 result = sio1dCore(port, io, data);
if ((io == 0) && ((ptr_dev.dctrl & IN_MSG) || (ptp_dev.dctrl & IN_MSG)))
printf("PTP/PTR_D: " ADDRESS_FORMAT " IN(0x%02x) = 0x%02x" NLP, PCX, port, result);
else if ((io) && ((ptr_dev.dctrl & OUT_MSG) || (ptp_dev.dctrl & OUT_MSG)))
printf("PTP/PTR_D: " ADDRESS_FORMAT " OUT(0x%02x) = 0x%02x" NLP, PCX, port, data);
return result;
}
static t_stat toBool(char tf, int *result) {
if (tf == 'T') {
*result = TRUE;
@ -856,8 +901,8 @@ static t_stat sio_dev_set_port(UNIT *uptr, int32 value, char *cptr, void *desc)
printf("\n");
port_table[position] = sip;
sim_map_resource(sip.port, 1, RESOURCE_TYPE_IO, (sip.hasOUT ||
(sip.sio_can_read == 0) && (sip.sio_cannot_read == 0) &&
(sip.sio_can_write == 0)) ? &sio0d : &sio0s, FALSE);
((sip.sio_can_read == 0) && (sip.sio_cannot_read == 0) &&
(sip.sio_can_write == 0))) ? &sio0d : &sio0s, FALSE);
return SCPE_OK;
}
@ -888,9 +933,8 @@ static t_stat sio_dev_set_interruptoff(UNIT *uptr, int32 value, char *cptr, void
}
static t_stat sio_svc(UNIT *uptr) {
if (sio0s(0, 0, 0) & KBD_HAS_CHAR) {
if (sio0s(0, 0, 0) & KBD_HAS_CHAR)
keyboardInterrupt = TRUE;
}
if (sio_unit.flags & UNIT_SIO_INTERRUPT)
sim_activate(&sio_unit, sio_unit.wait); /* activate unit */
return SCPE_OK;
@ -909,13 +953,11 @@ static void mapAltairPorts(void) {
int32 nulldev(const int32 port, const int32 io, const int32 data) {
if ((sio_unit.flags & UNIT_SIO_VERBOSE) && (warnUnassignedPort < warnLevelSIO)) {
warnUnassignedPort++;
if (io == 0) {
if (io == 0)
printf("SIO: " ADDRESS_FORMAT " Attempt to input from unassigned port 0x%04x - ignored." NLP, PCX, port);
}
else {
else
printf("SIO: " ADDRESS_FORMAT " Attempt to output 0x%02x to unassigned port 0x%04x - ignored." NLP, PCX, data, port);
}
}
return io == 0 ? 0xff : 0;
}
@ -1063,7 +1105,7 @@ static t_stat simh_dev_reset(DEVICE *dptr) {
}
static void warnNoRealTimeClock(void) {
TRACE_PRINT(VERBOSE_MSG,
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Sorry - no real time clock available." NLP, PCX));
}
@ -1078,18 +1120,30 @@ static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *de
static t_stat simh_dev_set_timeroff(UNIT *uptr, int32 value, char *cptr, void *desc) {
timerInterrupt = FALSE;
if (rtc_avail)
sim_cancel(&simh_unit);
return SCPE_OK;
}
static t_stat simh_svc(UNIT *uptr) {
uint32 n = sim_os_msec();
if (n >= timeOfNextInterrupt) {
uint32 now = sim_os_msec();
if (now >= timeOfNextInterrupt) {
timerInterrupt = TRUE;
timeOfNextInterrupt += timerDelta;
if (n >= timeOfNextInterrupt) /* time of next interrupt is not in the future */
timeOfNextInterrupt = n + timerDelta; /* make sure it is in the future! */
if (timerDelta == 0)
timeOfNextInterrupt = now + DEFAULT_TIMER_DELTA;
else {
uint32 newTimeOfNextInterrupt = now + timerDelta - (now - timeOfNextInterrupt) % timerDelta;
if (newTimeOfNextInterrupt != timeOfNextInterrupt + timerDelta) {
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Timer interrupts skipped %i. Delta %i. Expect %i. Got %i." NLP, PCX,
(newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1,
timerDelta,
timeOfNextInterrupt + timerDelta - now, newTimeOfNextInterrupt - now));
}
timeOfNextInterrupt = newTimeOfNextInterrupt;
}
}
/* post condition: now < timeOfNextInterrupt */
if (simh_unit.flags & UNIT_SIMH_TIMERON)
sim_activate(&simh_unit, simh_unit.wait); /* activate unit */
return SCPE_OK;
@ -1175,7 +1229,7 @@ static int32 simh_in(const int32 port) {
case getHostFilenamesCmd:
#if UNIX_PLATFORM
if (globValid)
if (globValid) {
if (globPosNameList < globS.gl_pathc) {
if (!(result = globS.gl_pathv[globPosNameList][globPosName++])) {
globPosNameList++;
@ -1187,13 +1241,13 @@ static int32 simh_in(const int32 port) {
lastCommand = 0;
globfree(&globS);
}
}
#elif defined (_WIN32)
if (globValid)
if (globFinished)
globValid = FALSE;
else if (firstPathCharacter <= lastPathSeparator) {
else if (firstPathCharacter <= lastPathSeparator)
result = cpmCommandLine[firstPathCharacter++];
}
else if (!(result = FindFileData.cFileName[globPosName++])) {
globPosName = firstPathCharacter = 0;
if (!FindNextFile(hFind, &FindFileData)) {
@ -1296,7 +1350,7 @@ static int32 simh_in(const int32 port) {
result = getBankSelect();
else {
result = 0;
TRACE_PRINT(VERBOSE_MSG,
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Get selected bank ignored for non-banked memory." NLP, PCX));
}
lastCommand = 0;
@ -1340,7 +1394,7 @@ static int32 simh_in(const int32 port) {
break;
default:
TRACE_PRINT(VERBOSE_MSG,
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Undefined IN from SIMH pseudo device on port %03xh ignored." NLP,
PCX, port));
result = lastCommand = 0;
@ -1349,6 +1403,10 @@ static int32 simh_in(const int32 port) {
}
void do_SIMH_sleep(void) {
/* Do not sleep when timer interrupts are pending or are about to be created.
Otherwise there is the possibility that such interrupts are skipped. */
if ((simh_unit.flags & UNIT_SIMH_TIMERON) && rtc_avail && (sim_os_msec() + 1 >= timeOfNextInterrupt))
return;
#if defined (_WIN32)
if ((SIMHSleep / 1000) && !sio_unit.u4) /* time to sleep and SIO not attached to a file */
Sleep(SIMHSleep / 1000);
@ -1390,7 +1448,7 @@ static int32 simh_out(const int32 port, const int32 data) {
if (cpu_unit.flags & UNIT_CPU_BANKED)
setBankSelect(data & BANKMASK);
else {
TRACE_PRINT(VERBOSE_MSG,
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Set selected bank to %i ignored for non-banked memory."
NLP, PCX, data & 3));
}
@ -1405,6 +1463,12 @@ static int32 simh_out(const int32 port, const int32 data) {
else {
timerDelta |= (data << 8);
setTimerDeltaPos = lastCommand = 0;
if (timerDelta == 0) {
timerDelta = DEFAULT_TIMER_DELTA;
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Timer delta set to 0 ms ignored. Using %i ms instead."
NLP, PCX, DEFAULT_TIMER_DELTA));
}
}
break;
@ -1420,7 +1484,7 @@ static int32 simh_out(const int32 port, const int32 data) {
break;
default:
TRACE_PRINT(CMD_MSG,
TRACE_PRINT(simh_device, CMD_MSG,
("SIMH: " ADDRESS_FORMAT " CMD(0x%02x) <- %i (0x%02x, '%s')" NLP, PCX, port, data, data,
(0 <= data) && (data <= lastSIMHCommand) ? cmdNames[data] : "Unknown command"));
@ -1435,7 +1499,7 @@ static int32 simh_out(const int32 port, const int32 data) {
createCPMCommandLine();
globError = glob(cpmCommandLine, GLOB_ERR, NULL, &globS);
if (globError) {
TRACE_PRINT(VERBOSE_MSG,
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %i."
NLP, PCX, cpmCommandLine, globError));
globfree(&globS);
@ -1451,7 +1515,7 @@ static int32 simh_out(const int32 port, const int32 data) {
setLastPathSeparator();
hFind = FindFirstFile(cpmCommandLine, &FindFileData);
if (hFind == INVALID_HANDLE_VALUE) {
TRACE_PRINT(VERBOSE_MSG,
TRACE_PRINT(simh_device, VERBOSE_MSG,
("SIMH: " ADDRESS_FORMAT " Cannot expand '%s'. Error is %lu."
NLP, PCX, cpmCommandLine, GetLastError()));
globValid = FALSE;
@ -1465,21 +1529,18 @@ static int32 simh_out(const int32 port, const int32 data) {
break;
case printTimeCmd: /* print time */
if (rtc_avail) {
if (rtc_avail)
printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec());
}
else {
else
warnNoRealTimeClock();
}
break;
case startTimerCmd: /* create a new timer on top of stack */
if (rtc_avail)
if (markTimeSP < TIMER_STACK_LIMIT)
markTime[markTimeSP++] = sim_os_msec();
else {
else
printf("SIMH: " ADDRESS_FORMAT " Timer stack overflow." NLP, PCX);
}
else
warnNoRealTimeClock();
break;
@ -1490,15 +1551,14 @@ static int32 simh_out(const int32 port, const int32 data) {
uint32 delta = sim_os_msec() - markTime[--markTimeSP];
printf("SIMH: " ADDRESS_FORMAT " Timer stopped. Elapsed time in milliseconds = %d." NLP, PCX, delta);
}
else {
else
printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX);
}
else
warnNoRealTimeClock();
break;
case resetPTRCmd: /* reset ptr device */
ptr_reset(NULL);
ptr_reset(&ptr_dev);
break;
case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */
@ -1569,9 +1629,8 @@ static int32 simh_out(const int32 port, const int32 data) {
uint32 delta = sim_os_msec() - markTime[markTimeSP - 1];
printf("SIMH: " ADDRESS_FORMAT " Timer running. Elapsed in milliseconds = %d." NLP, PCX, delta);
}
else {
else
printf("SIMH: " ADDRESS_FORMAT " No timer active." NLP, PCX);
}
else
warnNoRealTimeClock();
break;
@ -1622,7 +1681,7 @@ static int32 simh_out(const int32 port, const int32 data) {
break;
default:
TRACE_PRINT(CMD_MSG,
TRACE_PRINT(simh_device, CMD_MSG,
("SIMH: " ADDRESS_FORMAT " Unknown command (%i) to SIMH pseudo device on port %03xh ignored."
NLP, PCX, data, port));
}
@ -1635,13 +1694,13 @@ int32 simh_dev(const int32 port, const int32 io, const int32 data) {
int32 result = 0;
if (io == 0) {
result = simh_in(port);
TRACE_PRINT(IN_MSG,
TRACE_PRINT(simh_device, IN_MSG,
("SIMH: " ADDRESS_FORMAT " IN(0x%02x) -> %i (0x%02x, '%c')" NLP, PCX, port, result, result,
(32 <= (result & 0xff)) && ((result & 0xff) <= 127) ? (result & 0xff) : '?'));
}
else {
TRACE_PRINT(OUT_MSG,
TRACE_PRINT(simh_device, OUT_MSG,
("SIMH: " ADDRESS_FORMAT " OUT(0x%02x) <- %i (0x%02x, '%c')" NLP, PCX, port, data, data,
(32 <= (data & 0xff)) && ((data & 0xff) <= 127) ? (data & 0xff) : '?'));
simh_out(port, data);

View file

@ -1,6 +1,6 @@
/* altairz80_sys.c: MITS Altair system interface
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -76,6 +76,8 @@ extern DEVICE fpc_dev;
extern int32 chiptype;
extern long disasm (unsigned char *data, char *output, int segsize, long offset);
void prepareMemoryAccessMessage(const t_addr loc);
void prepareInstructionMessage(const t_addr loc, const uint32 op);
t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw);
t_stat parse_sym(char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw);
@ -123,11 +125,13 @@ DEVICE *sim_devices[] = {
NULL
};
char memoryAccessMessage[80];
static char memoryAccessMessage[256];
static char instructionMessage[256];
const char *sim_stop_messages[] = {
"HALT instruction",
"Breakpoint",
memoryAccessMessage,
instructionMessage,
"Invalid Opcode"
};
@ -347,6 +351,15 @@ static char *const MnemonicsXCB[256] = {
"SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" /* f8-ff */
};
void prepareMemoryAccessMessage(const t_addr loc) {
sprintf(memoryAccessMessage, "Memory access breakpoint [%05xh]", loc);
}
void prepareInstructionMessage(const t_addr loc, const uint32 op) {
sprintf(instructionMessage, "Instruction \"%s\" breakpoint [%05xh]", chiptype == CHIP_TYPE_8080 ? Mnemonics8080[op & 0xff] :
(chiptype == CHIP_TYPE_Z80 ? MnemonicsZ80[op & 0xff] : "???"), loc);
}
/* Symbolic disassembler
Inputs:
@ -504,7 +517,7 @@ static int32 checkbase(char ch, const char *numString) {
static int32 numok(char ch, const char **numString, const int32 minvalue,
const int32 maxvalue, const int32 requireSign, int32 *result) {
int32 sign = 1, value = 0, base;
if (requireSign)
if (requireSign) {
if (ch == '+')
ch = *(*numString)++;
else if (ch == '-') {
@ -513,6 +526,7 @@ static int32 numok(char ch, const char **numString, const int32 minvalue,
}
else
return FALSE;
}
if (!(base = checkbase(ch, *numString)))
return FALSE;
while (isxdigit(ch)) {

View file

@ -1,6 +1,6 @@
/* altairz80_cpu_opt.c: MITS Altair CPU (8080 and Z80)
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -2353,7 +2353,7 @@ t_stat sim_instr_nommu(void) {
case 0xdd: /* DD prefix */
CHECK_CPU_8080;
switch (op = RAM_PP(PC)) {
switch (RAM_PP(PC)) {
case 0x09: /* ADD IX,BC */
IX &= ADDRMASK;
@ -3019,7 +3019,7 @@ t_stat sim_instr_nommu(void) {
case 0xed: /* ED prefix */
CHECK_CPU_8080;
switch (op = RAM_PP(PC)) {
switch (RAM_PP(PC)) {
case 0x40: /* IN B,(C) */
temp = in(LOW_REGISTER(BC));
@ -3405,7 +3405,6 @@ t_stat sim_instr_nommu(void) {
break;
case 0xb0: /* LDIR */
acu = HIGH_REGISTER(AF);
BC &= ADDRMASK;
if (BC == 0)
BC = 0x10000;
@ -3594,7 +3593,7 @@ t_stat sim_instr_nommu(void) {
case 0xfd: /* FD prefix */
CHECK_CPU_8080;
switch (op = RAM_PP(PC)) {
switch (RAM_PP(PC)) {
case 0x09: /* ADD IY,BC */
IY &= ADDRMASK;

BIN
AltairZ80/altairz80_doc.pdf Normal file

Binary file not shown.

View file

@ -1,6 +1,6 @@
/* altairz80_hdsk.c: simulated hard disk device to increase capacity
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -42,6 +42,7 @@ static t_stat show_format(FILE *st, UNIT *uptr, int32 val, void *desc);
static t_stat hdsk_reset(DEVICE *dptr);
static t_stat hdsk_attach(UNIT *uptr, char *cptr);
static t_stat hdsk_detach(UNIT *uptr);
#define UNIT_V_HDSK_WLK (UNIT_V_UF + 0) /* write locked */
#define UNIT_HDSK_WLK (1 << UNIT_V_HDSK_WLK)
@ -77,13 +78,14 @@ extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
extern int32 find_unit_index(UNIT *uptr);
static t_stat hdsk_boot(int32 unitno, DEVICE *dptr);
int32 hdsk_io(const int32 port, const int32 io, const int32 data);
static int32 hdskLastCommand = HDSK_NONE;
static int32 hdskCommandPosition = 0;
static int32 paramcount = 0;
static int32 parameterCount = 0;
static int32 selectedDisk;
static int32 selectedSector;
static int32 selectedTrack;
@ -104,33 +106,115 @@ typedef struct {
uint16 off; /* number of reserved tracks */
uint8 psh; /* physical record shift factor, CP/M 3 */
uint8 phm; /* physical record mask, CP/M 3 */
int32 physicalSectorSize; /* 0 for 128 << psh, > 0 for special */
int32 offset; /* offset in physical sector where logical sector starts */
int32 *skew; /* pointer to skew table or NULL */
} DPB;
typedef struct {
PNP_INFO pnp; /* Plug and Play */
} HDSK_INFO;
static HDSK_INFO hdsk_info_data = { { 0x0000, 0, 0xFD, 1 } };
/* static HDSK_INFO *hdsk_info = &hdsk_info_data; */
#define SPT16 16
#define SPT32 32
#define SPT26 26
/* Note in the following CKS = 0 for fixed media which are not supposed to be changed while CP/M is executing */
static HDSK_INFO hdsk_info_data = { { 0x0000, 0, 0xFD, 1 } };
static int32 standard8[SPT26] = { 0, 6, 12, 18, 24, 4, 10, 16,
22, 2, 8, 14, 20, 1, 7, 13,
19, 25, 5, 11, 17, 23, 3, 9,
15, 21 };
static int32 appple_ii_DOS[SPT16] = { 0, 6, 12, 3, 9, 15, 14, 5,
11, 2, 8, 7, 13, 4, 10, 1 };
static int32 appple_ii_DOS2[SPT32] = { 0, 1, 12, 13, 24, 25, 6, 7,
18, 19, 30, 31, 28, 29, 10, 11,
22, 23, 4, 5, 16, 17, 14, 15,
26, 27, 8, 9, 20, 21, 2, 3 };
static int32 appple_ii_PRODOS[SPT16] = { 0, 9, 3, 12, 6, 15, 1, 10,
4, 13, 7, 8, 2, 11, 5, 14 };
static int32 appple_ii_PRODOS2[SPT32] = { 0, 1, 18, 19, 6, 7, 24, 25,
12, 13, 30, 31, 2, 3, 20, 21,
8, 9, 26, 27, 14, 15, 16, 17,
4, 5, 22, 23, 10, 11, 28, 29 };
static int32 mits[SPT32] = { 0, 17, 2, 19, 4, 21, 6, 23,
8, 25, 10, 27, 12, 29, 14, 31,
16, 1, 18, 3, 20, 5, 22, 7,
24, 9, 26, 11, 28, 13, 30, 15 };
/* Note in the following CKS = 0 for fixed media which are not supposed to be
changed while CP/M is executing. Also note that spt (sectors per track) is
measured in CP/M sectors of size 128 bytes. Standard format "HDSK" must be
first as index 0 is used as default in some cases.
*/
static DPB dpb[] = {
/* name capac spt bsh blm exm dsm drm al0 al1 cks off psh phm */
{ "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF, 0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00 }, /* AZ80 HDSK */
{ "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E, 0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03 }, /* 128K FLASH */
{ "P112", 1474560, 72, 0x04, 0x0F, 0x00, 710, 0x00FE, 0xF0, 0x00, 0x0000, 0x0002, 0x02, 0x03 }, /* 1.44M P112 */
{ "SU720", 737280, 36, 0x04, 0x0F, 0x00, 354, 0x007E, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* 720K Super I/O */
{ "OSB1", 102400, 20, 0x04, 0x0F, 0x01, 45, 0x003F, 0x80, 0x00, 0x0000, 0x0003, 0x02, 0x03 }, /* Osborne1 5.25" SS SD */
{ "OSB2", 204800, 40, 0x03, 0x07, 0x00, 184, 0x003F, 0xC0, 0x00, 0x0000, 0x0003, 0x02, 0x03 }, /* Osborne1 5.25" SS DD */
{ "NSSS1", 179200, 40, 0x03, 0x07, 0x00, 0xA4, 0x003F, 0xC0, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar SSDD Format 1 */
{ "NSSS2", 179200, 40, 0x04, 0x0F, 0x01, 0x51, 0x003F, 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar SSDD Format 2 */
{ "NSDS2", 358400, 40, 0x04, 0x0F, 0x01, 0xA9, 0x003F, 0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03 }, /* Northstar DSDD Format 2 */
{ "VGSS", 315392, 32, 0x04, 0x0F, 0x00, 149, 0x007F, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* Vector SS SD */
{ "VGDS", 632784, 32, 0x04, 0x0F, 0x00, 299, 0x007F, 0xC0, 0x00, 0x0020, 0x0004, 0x02, 0x03 }, /* Vector DS SD */
/* Note on DISK1A Images: this is a bit of a mess. The first track on the disk is 128x26 bytes (SD) and to make this work
I had to "move" the data from 0x2d00 in the DSK image file down to 0x4000 (2-tracks in). I used WinHex to do it. */
{ "DISK1A", 630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F, 0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03 }, /* CompuPro Disk1A 8" SS SD */
{ "SSSD8", 256256, 26, 0x03, 0x07, 0x00, 242, 0x003F, 0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00 }, /* Standard 8" SS SD */
/* name capac spt bsh blm exm dsm drm
al0 al1 cks off psh phm ss off skew */
{ "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF,
0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00, 0, 0, NULL }, /* AZ80 HDSK */
{ "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E,
0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03, 0, 0, NULL }, /* 128K FLASH */
{ "P112", 1474560, 72, 0x04, 0x0F, 0x00, 710, 0x00FE,
0xF0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* 1.44M P112 */
{ "SU720", 737280, 36, 0x04, 0x0F, 0x00, 354, 0x007E,
0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* 720K Super I/O */
{ "OSB1", 102400, 20, 0x04, 0x0F, 0x01, 45, 0x003F,
0x80, 0x00, 0x0000, 0x0003, 0x02, 0x03, 0, 0, NULL }, /* Osborne1 5.25" SS SD */
{ "OSB2", 204800, 40, 0x03, 0x07, 0x00, 184, 0x003F,
0xC0, 0x00, 0x0000, 0x0003, 0x02, 0x03, 0, 0, NULL }, /* Osborne1 5.25" SS DD */
{ "NSSS1", 179200, 40, 0x03, 0x07, 0x00, 0xA4, 0x003F,
0xC0, 0x00, 0x0010, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Northstar SSDD Format 1 */
{ "NSSS2", 179200, 40, 0x04, 0x0F, 0x01, 0x51, 0x003F,
0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Northstar SSDD Format 2 */
{ "NSDS2", 358400, 40, 0x04, 0x0F, 0x01, 0xA9, 0x003F,
0x80, 0x00, 0x0010, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Northstar DSDD Format 2 */
{ "VGSS", 315392, 32, 0x04, 0x0F, 0x00, 149, 0x007F,
0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Vector SS SD */
{ "VGDS", 630784, 32, 0x04, 0x0F, 0x00, 299, 0x007F,
0xC0, 0x00, 0x0020, 0x0004, 0x02, 0x03, 0, 0, NULL }, /* Vector DS SD */
{ "DISK1A", 630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F,
0xC0, 0x00, 0x0020, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* CompuPro Disk1A 8" SS SD */
{ "SSSD8", 256256, SPT26, 0x03, 0x07, 0x00, 242, 0x003F,
0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00, 0, 0, NULL }, /* Standard 8" SS SD */
{ "SSSD8S", 256256, SPT26, 0x03, 0x07, 0x00, 242, 0x003F,
0xC0, 0x00, 0x0000, 0x0002, 0x00, 0x00, 0, 0, standard8 }, /* Standard 8" SS SD with skew */
{ "APPLE-DO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F,
0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, appple_ii_DOS }, /* Apple II DOS 3.3 */
{ "APPLE-PO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F,
0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, appple_ii_PRODOS }, /* Apple II PRODOS */
{ "APPLE-D2",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F,
0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, appple_ii_DOS2 }, /* Apple II DOS 3.3, deblocked */
{ "APPLE-P2",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F,
0xC0, 0x00, 0x0000, 0x0003, 0x00, 0x00, 0, 0, appple_ii_PRODOS2 }, /* Apple II PRODOS, deblocked */
{ "MITS", 337568, SPT32, 0x03, 0x07, 0x00, 254, 0x00FF,
0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00, 137, 3, mits }, /* MITS Altair original */
{ "MITS2", 1113536, SPT32, 0x04, 0x0F, 0x00, 0x1EF, 0x00FF,
0xF0, 0x00, 0x0000, 0x0006, 0x00, 0x00, 137, 3, mits }, /* MITS Altair original, extra */
{ "", 0 }
};
@ -180,7 +264,7 @@ DEVICE hdsk_dev = {
"HDSK", hdsk_unit, hdsk_reg, hdsk_mod,
8, 10, 31, 1, 8, 8,
NULL, NULL, &hdsk_reset,
&hdsk_boot, &hdsk_attach, NULL,
&hdsk_boot, &hdsk_attach, &hdsk_detach,
&hdsk_info_data, (DEV_DISABLE | DEV_DEBUG), 0,
hdsk_dt, NULL, "Hard Disk HDSK"
};
@ -212,7 +296,7 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) {
return r;
/* Step 1: Determine capacity of this disk */
uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good candidate */
uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good indication */
if (uptr -> capac == 0) { /* file does not exist or has length 0 */
uptr -> capac = uptr -> HDSK_NUMBER_OF_TRACKS *
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE;
@ -255,7 +339,7 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) {
uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh;
uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh);
}
assert(uptr -> HDSK_SECTORS_PER_TRACK && uptr -> HDSK_SECTOR_SIZE);
assert((uptr -> HDSK_SECTORS_PER_TRACK) && (uptr -> HDSK_SECTOR_SIZE) && (uptr -> HDSK_FORMAT_TYPE >= 0));
/* Step 4: Number of tracks is smallest number to accomodate capacity */
uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK *
@ -264,9 +348,23 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) {
uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) &&
(uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS *
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) );
return SCPE_OK;
}
static t_stat hdsk_detach(UNIT *uptr) {
t_stat result;
if (uptr == NULL)
return SCPE_IERR;
result = detach_unit(uptr);
uptr -> capac = HDSK_CAPACITY;
uptr -> HDSK_FORMAT_TYPE = 0;
uptr -> HDSK_SECTOR_SIZE = 0;
uptr -> HDSK_SECTORS_PER_TRACK = 0;
uptr -> HDSK_NUMBER_OF_TRACKS = 0;
return result;
}
/* Set disk geometry routine */
static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) {
uint32 numberOfTracks, numberOfSectors, sectorSize;
@ -276,6 +374,10 @@ static t_stat set_geom(UNIT *uptr, int32 val, char *cptr, void *desc) {
return SCPE_ARG;
if (uptr == NULL)
return SCPE_IERR;
if (((uptr -> flags) & UNIT_ATT) == 0) {
printf("Cannot set geometry for not attached unit %i.\n", find_unit_index(uptr));
return SCPE_ARG;
}
result = sscanf(cptr, "%d/%d/%d%n", &numberOfTracks, &numberOfSectors, &sectorSize, &n);
if ((result != 3) || (result == EOF) || (cptr[n] != 0)) {
result = sscanf(cptr, "T:%d/N:%d/S:%d%n", &numberOfTracks, &numberOfSectors, &sectorSize, &n);
@ -311,6 +413,10 @@ static t_stat set_format(UNIT *uptr, int32 val, char *cptr, void *desc) {
return SCPE_IERR;
if (sscanf(cptr, "%" QUOTE2(DPB_NAME_LENGTH) "s", fmtname) == 0)
return SCPE_ARG;
if (((uptr -> flags) & UNIT_ATT) == 0) {
printf("Cannot set format for not attached unit %i.\n", find_unit_index(uptr));
return SCPE_ARG;
}
for (i = 0; dpb[i].capac != 0; i++) {
if (strncmp(fmtname, dpb[i].name, strlen(fmtname)) == 0) {
uptr -> HDSK_FORMAT_TYPE = i;
@ -444,12 +550,13 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) {
/* check the parameters and return TRUE iff parameters are correct or have been repaired */
static int32 checkParameters(void) {
UNIT *uptr = &hdsk_dev.units[selectedDisk];
UNIT *uptr;
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i does not exist, will use HDSK0 instead." NLP,
selectedDisk, PCX, selectedDisk));
selectedDisk = 0;
}
uptr = &hdsk_dev.units[selectedDisk];
if ((hdsk_dev.units[selectedDisk].flags & UNIT_ATT) == 0) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Disk %i is not attached." NLP,
selectedDisk, PCX, selectedDisk));
@ -475,28 +582,33 @@ static int32 checkParameters(void) {
return TRUE;
}
/* pre-condition: checkParameters has been executed to repair any faulty parameters */
static int32 doSeek(void) {
UNIT *uptr = &hdsk_dev.units[selectedDisk];
if (fseek(uptr -> fileref,
(uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) * selectedTrack +
(uptr -> HDSK_SECTOR_SIZE * selectedSector), SEEK_SET)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d Track=%04d." NLP,
selectedDisk, PCX, selectedSector, selectedTrack));
int32 hostSector = (dpb[uptr -> HDSK_FORMAT_TYPE].skew == NULL) ?
selectedSector : dpb[uptr -> HDSK_FORMAT_TYPE].skew[selectedSector];
int32 sectorSize = (dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize == 0) ?
uptr -> HDSK_SECTOR_SIZE : dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize;
if (sim_fseek(uptr -> fileref,
sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) +
dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not access Sector=%02d[=%02d] Track=%04d." NLP,
selectedDisk, PCX, selectedSector, hostSector, selectedTrack));
return CPM_ERROR;
}
else
return CPM_OK;
}
uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */
/* pre-condition: checkParameters has been executed to repair any faulty parameters */
static int32 doRead(void) {
int32 i;
UNIT *uptr = &hdsk_dev.units[selectedDisk];
if (doSeek())
return CPM_ERROR;
if (fread(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
hdskbuf[i] = CPM_EMPTY;
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not read Sector=%02d Track=%04d." NLP,
@ -508,18 +620,20 @@ static int32 doRead(void) {
return CPM_OK;
}
/* pre-condition: checkParameters has been executed to repair any faulty parameters */
static int32 doWrite(void) {
int32 i;
size_t rtn;
UNIT *uptr = &hdsk_dev.units[selectedDisk];
if (((uptr -> flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */
if (doSeek())
return CPM_ERROR;
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
hdskbuf[i] = GetBYTEWrapper(selectedDMA + i);
if (fwrite(hdskbuf, uptr -> HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d." NLP,
selectedDisk, PCX, selectedSector, selectedTrack));
rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref);
if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Could not write Sector=%02d Track=%04d Result=%zd." NLP,
selectedDisk, PCX, selectedSector, selectedTrack, rtn));
return CPM_ERROR;
}
}
@ -531,57 +645,59 @@ static int32 doWrite(void) {
return CPM_OK;
}
static int32 hdsk_in(const int32 port) {
UNIT *uptr = &hdsk_dev.units[selectedDisk];
#define PARAMETER_BLOCK_SIZE 19
static uint8 parameterBlock[PARAMETER_BLOCK_SIZE];
int32 result;
static int32 hdsk_in(const int32 port) {
if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) {
result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR;
int32 result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR;
hdskLastCommand = HDSK_NONE;
hdskCommandPosition = 0;
return result;
} else if (hdskLastCommand == HDSK_PARAM) {
DPB current = dpb[uptr -> HDSK_FORMAT_TYPE];
uint8 params[17];
params[ 0] = current.spt & 0xff; params[ 1] = (current.spt >> 8) & 0xff;
params[ 2] = current.bsh;
params[ 3] = current.blm;
params[ 4] = current.exm;
params[ 5] = current.dsm & 0xff; params[ 6] = (current.dsm >> 8) & 0xff;
params[ 7] = current.drm & 0xff; params[ 8] = (current.drm >> 8) & 0xff;
params[ 9] = current.al0;
params[10] = current.al1;
params[11] = current.cks & 0xff; params[12] = (current.cks >> 8) & 0xff;
params[13] = current.off & 0xff; params[14] = (current.off >> 8) & 0xff;
params[15] = current.psh;
params[16] = current.phm;
if (++paramcount >= 19)
}
if (hdskLastCommand == HDSK_PARAM) {
if (++parameterCount >= PARAMETER_BLOCK_SIZE)
hdskLastCommand = HDSK_NONE;
if (paramcount <= 17)
return params[paramcount - 1];
else if (paramcount == 18)
return (uptr -> HDSK_SECTOR_SIZE & 0xff);
else if (paramcount == 19)
return (uptr -> HDSK_SECTOR_SIZE >> 8);
else {
printf("HDSK%d: " ADDRESS_FORMAT " Get parameter error." NLP,
selectedDisk, PCX);
return parameterBlock[parameterCount - 1];
}
}
else {
TRACE_PRINT(VERBOSE_MSG, ("HDSK%d: " ADDRESS_FORMAT " Illegal IN command detected (port=%03xh, cmd=%d, pos=%d)." NLP,
selectedDisk, PCX, port, hdskLastCommand, hdskCommandPosition));
}
return CPM_OK;
}
static int32 hdsk_out(const int32 port, const int32 data) {
int32 thisDisk;
UNIT *uptr;
DPB current;
switch(hdskLastCommand) {
case HDSK_PARAM:
paramcount = 0;
selectedDisk = data;
parameterCount = 0;
thisDisk = (0 <= data) && (data < HDSK_NUMBER) ? data : 0;
uptr = &hdsk_dev.units[thisDisk];
if ((uptr -> flags) & UNIT_ATT) {
current = dpb[uptr -> HDSK_FORMAT_TYPE];
parameterBlock[17] = uptr -> HDSK_SECTOR_SIZE & 0xff;
parameterBlock[18] = (uptr -> HDSK_SECTOR_SIZE >> 8) & 0xff;
}
else {
current = dpb[0];
parameterBlock[17] = 128;
parameterBlock[18] = 0;
}
parameterBlock[ 0] = current.spt & 0xff; parameterBlock[ 1] = (current.spt >> 8) & 0xff;
parameterBlock[ 2] = current.bsh;
parameterBlock[ 3] = current.blm;
parameterBlock[ 4] = current.exm;
parameterBlock[ 5] = current.dsm & 0xff; parameterBlock[ 6] = (current.dsm >> 8) & 0xff;
parameterBlock[ 7] = current.drm & 0xff; parameterBlock[ 8] = (current.drm >> 8) & 0xff;
parameterBlock[ 9] = current.al0;
parameterBlock[10] = current.al1;
parameterBlock[11] = current.cks & 0xff; parameterBlock[12] = (current.cks >> 8) & 0xff;
parameterBlock[13] = current.off & 0xff; parameterBlock[14] = (current.off >> 8) & 0xff;
parameterBlock[15] = current.psh;
parameterBlock[16] = current.phm;
break;
case HDSK_READ:

View file

@ -1,6 +1,6 @@
/* altairz80_net.c: networking capability
Copyright (c) 2002-2008, Peter Schorn
Copyright (c) 2002-2010, Peter Schorn
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -290,7 +290,7 @@ int32 netData(const int32 port, const int32 io, const int32 data) {
return 0;
net_svc(&net_unit);
for (i = 0; i <= MAX_CONNECTIONS; i++)
if (serviceDescriptor[i].Z80DataPort == port)
if (serviceDescriptor[i].Z80DataPort == port) {
if (io == 0) { /* IN */
if (serviceDescriptor[i].inputSize == 0) {
printf("re-read from %i" NLP, port);
@ -323,5 +323,6 @@ int32 netData(const int32 port, const int32 io, const int32 data) {
(32 <= data) && (data <= 127) ? data : '?'));
return 0;
}
}
return 0;
}

View file

@ -3,7 +3,7 @@
* $Id: flashwriter2.c 1941 2008-06-13 05:31:03Z hharte $ *
* *
* Copyright (c) 2007-2008 Howard M. Harte. *
* http:/*www.hartetec.com *
* http://www.hartetec.com *
* *
* Permission is hereby granted, free of charge, to any person obtaining *
* a copy of this software and associated documentation files (the *

View file

@ -149,9 +149,6 @@ extern uint8 GetByteDMA(const uint32 Addr);
#define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE)
#define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
#define I8272_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
/* Intel 8272 Commands */
#define I8272_READ_TRACK 0x02
@ -307,8 +304,8 @@ t_stat i8272_attach(UNIT *uptr, char *cptr)
i8272_info->drive[i].ready = 0;
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(strncmp(header, "IMD", 3)) {
char *rtn = fgets(header, 4, uptr->fileref);
if((rtn != NULL) && strncmp(header, "IMD", 3)) {
printf("I8272: Only IMD disk images are supported\n");
i8272_info->drive[i].uptr = NULL;
return SCPE_OPENERR;
@ -414,8 +411,7 @@ uint8 I8272_Read(const uint32 Addr)
return 0xFF;
}
cData = 0x00;
/* the switch statement ensures that cData is set in all cases! */
switch(Addr & 0x3) {
case I8272_FDC_MSR:
cData = i8272_info->fdc_msr | I8272_MSR_RQM;

View file

@ -86,7 +86,6 @@ static void i86_intr_handle(PC_ENV *m)
if (intr & INTR_SYNCH) /* raised by something */
{
intno = m->intno;
tmp = (uint16) mem_access_word(m, intno * 4);
{
tmp = m->R_FLG;
push_word(m, tmp);

View file

@ -108,7 +108,7 @@ extern uint32 in(const uint32 Port);
So, without further ado, ...
*/
extern char parity_tab[];
extern uint8 parity_tab[];
static void i86op_illegal_op(PC_ENV *m)
{
@ -3823,7 +3823,6 @@ static void i86op_ret_far(PC_ENV *m)
static void i86op_int3(PC_ENV *m)
{
uint16 tmp;
tmp = (uint16) mem_access_word(m, 3 * 4);
/* access the segment register */
{
tmp = m->R_FLG;
@ -3855,7 +3854,6 @@ static void i86op_int_IMM(PC_ENV *m)
uint16 tmp;
uint8 intnum;
intnum = fetch_byte_imm(m);
tmp = mem_access_word(m, intnum * 4);
{
tmp = m->R_FLG;
push_word(m, tmp);
@ -3886,7 +3884,6 @@ static void i86op_into(PC_ENV *m)
uint16 tmp;
if (ACCESS_FLAG(m,F_OF))
{
tmp = mem_access_word(m, 4 * 4);
{
tmp = m->R_FLG;
push_word(m, tmp);
@ -4150,8 +4147,7 @@ static void i86op_aam(PC_ENV *m)
/* opcode=0xd5*/
static void i86op_aad(PC_ENV *m)
{ uint8 a;
a = fetch_byte_imm(m);
{
m->R_AX = aad_word(m,m->R_AX);
DECODE_CLEAR_SEGOVR(m);
}
@ -5050,22 +5046,19 @@ static void i86op_esc_coprocess_d8(PC_ENV *m)
static void i86op_esc_coprocess_d9(PC_ENV *m)
{
uint16 mod,rl,rh;
uint16 destoffset;
uint8 stkelem;
FETCH_DECODE_MODRM(m,mod,rh,rl);
switch (mod)
{
case 0:
destoffset=decode_rm00_address(m,rl);
decode_rm00_address(m,rl);
break;
case 1:
destoffset=decode_rm01_address(m,rl);
decode_rm01_address(m,rl);
break;
case 2:
destoffset=decode_rm10_address(m,rl);
decode_rm10_address(m,rl);
break;
case 3: /* register to register */
stkelem = (uint8) rl;
break;
}
DECODE_CLEAR_SEGOVR(m);
@ -5075,22 +5068,19 @@ static void i86op_esc_coprocess_d9(PC_ENV *m)
static void i86op_esc_coprocess_da(PC_ENV *m)
{
uint16 mod,rl,rh;
uint16 destoffset;
uint8 stkelem;
FETCH_DECODE_MODRM(m,mod,rh,rl);
switch (mod)
{
case 0:
destoffset=decode_rm00_address(m,rl);
decode_rm00_address(m,rl);
break;
case 1:
destoffset=decode_rm01_address(m,rl);
decode_rm01_address(m,rl);
break;
case 2:
destoffset=decode_rm10_address(m,rl);
decode_rm10_address(m,rl);
break;
case 3: /* register to register */
stkelem = (uint8) rl;
break;
}
DECODE_CLEAR_SEGOVR(m);
@ -5100,19 +5090,17 @@ static void i86op_esc_coprocess_da(PC_ENV *m)
static void i86op_esc_coprocess_db(PC_ENV *m)
{
uint16 mod,rl,rh;
uint16 destoffset;
/* uint8 stkelem;*/
FETCH_DECODE_MODRM(m,mod,rh,rl);
switch (mod)
{
case 0:
destoffset=decode_rm00_address(m,rl);
decode_rm00_address(m,rl);
break;
case 1:
destoffset=decode_rm01_address(m,rl);
decode_rm01_address(m,rl);
break;
case 2:
destoffset=decode_rm10_address(m,rl);
decode_rm10_address(m,rl);
break;
case 3: /* register to register */
break;
@ -5124,22 +5112,19 @@ static void i86op_esc_coprocess_db(PC_ENV *m)
static void i86op_esc_coprocess_dc(PC_ENV *m)
{
uint16 mod,rl,rh;
uint16 destoffset;
uint8 stkelem;
FETCH_DECODE_MODRM(m,mod,rh,rl);
switch (mod)
{
case 0:
destoffset=decode_rm00_address(m,rl);
decode_rm00_address(m,rl);
break;
case 1:
destoffset=decode_rm01_address(m,rl);
decode_rm01_address(m,rl);
break;
case 2:
destoffset=decode_rm10_address(m,rl);
decode_rm10_address(m,rl);
break;
case 3: /* register to register */
stkelem = (uint8) rl;
break;
}
DECODE_CLEAR_SEGOVR(m);
@ -5149,22 +5134,19 @@ static void i86op_esc_coprocess_dc(PC_ENV *m)
static void i86op_esc_coprocess_dd(PC_ENV *m)
{
uint16 mod,rl,rh;
uint16 destoffset;
uint8 stkelem;
FETCH_DECODE_MODRM(m,mod,rh,rl);
switch (mod)
{
case 0:
destoffset=decode_rm00_address(m,rl);
decode_rm00_address(m,rl);
break;
case 1:
destoffset=decode_rm01_address(m,rl);
decode_rm01_address(m,rl);
break;
case 2:
destoffset=decode_rm10_address(m,rl);
decode_rm10_address(m,rl);
break;
case 3: /* register to register */
stkelem = (uint8) rl;
break;
}
DECODE_CLEAR_SEGOVR(m);
@ -5174,22 +5156,19 @@ static void i86op_esc_coprocess_dd(PC_ENV *m)
static void i86op_esc_coprocess_de(PC_ENV *m)
{
uint16 mod,rl,rh;
uint16 destoffset;
uint8 stkelem;
FETCH_DECODE_MODRM(m,mod,rh,rl);
switch (mod)
{
case 0:
destoffset=decode_rm00_address(m,rl);
decode_rm00_address(m,rl);
break;
case 1:
destoffset=decode_rm01_address(m,rl);
decode_rm01_address(m,rl);
break;
case 2:
destoffset=decode_rm10_address(m,rl);
decode_rm10_address(m,rl);
break;
case 3: /* register to register */
stkelem = (uint8) rl;
break;
}
DECODE_CLEAR_SEGOVR(m);
@ -5199,22 +5178,19 @@ static void i86op_esc_coprocess_de(PC_ENV *m)
static void i86op_esc_coprocess_df(PC_ENV *m)
{
uint16 mod,rl,rh;
uint16 destoffset;
uint8 stkelem;
FETCH_DECODE_MODRM(m,mod,rh,rl);
switch (mod)
{
case 0:
destoffset=decode_rm00_address(m,rl);
decode_rm00_address(m,rl);
break;
case 1:
destoffset=decode_rm01_address(m,rl);
decode_rm01_address(m,rl);
break;
case 2:
destoffset=decode_rm10_address(m,rl);
decode_rm10_address(m,rl);
break;
case 3: /* register to register */
stkelem = (uint8) rl;
break;
}
DECODE_CLEAR_SEGOVR(m);

View file

@ -1106,7 +1106,6 @@ uint8 shr_byte(PC_ENV *m, uint8 d, uint8 s)
uint16 shr_word(PC_ENV *m, uint16 d, uint16 s)
{
uint32 cnt,res,cf,mask;
res = d;
if (s < 16)
{
cnt = s % 16;

View file

@ -130,9 +130,6 @@ static SECTOR_FORMAT sdata;
#define UNIT_V_MFDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_MFDC_VERBOSE (1 << UNIT_V_MFDC_VERBOSE)
#define MFDC_CAPACITY (77*16*MFDC_SECTOR_LEN) /* Default Micropolis Disk Capacity */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
static t_stat mfdc_reset(DEVICE *mfdc_dev);
static t_stat mfdc_attach(UNIT *uptr, char *cptr);
@ -237,7 +234,6 @@ t_stat mfdc_reset(DEVICE *dptr)
/* Attach routine */
t_stat mfdc_attach(UNIT *uptr, char *cptr)
{
char header[4];
t_stat r;
unsigned int i = 0;
@ -258,16 +254,10 @@ t_stat mfdc_attach(UNIT *uptr, char *cptr)
uptr->u3 = IMAGE_TYPE_DSK;
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(!strcmp(header, "IMD")) {
uptr->u3 = IMAGE_TYPE_IMD;
} else if(!strcmp(header, "CPT")) {
printf("CPT images not yet supported\n");
uptr->u3 = IMAGE_TYPE_CPT;
r = assignDiskType(uptr);
if (r != SCPE_OK) {
mfdc_detach(uptr);
return SCPE_OPENERR;
} else {
uptr->u3 = IMAGE_TYPE_DSK;
return r;
}
}
@ -386,6 +376,7 @@ static uint8 MFDC_Read(const uint32 Addr)
{
uint8 cData;
MFDC_DRIVE_INFO *pDrive;
int32 rtn;
cData = 0x00;
@ -482,10 +473,13 @@ static uint8 MFDC_Read(const uint32 Addr)
} else {
sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
#ifdef USE_VGI
fread(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref);
rtn = sim_fread(sdata.raw, 1, MFDC_SECTOR_LEN, (pDrive->uptr)->fileref);
if (rtn != MFDC_SECTOR_LEN)
#else
fread(sdata.u.data, 256, 1, (pDrive->uptr)->fileref);
rtn = sim_fread(sdata.u.data, 1, 256, (pDrive->uptr)->fileref);
if (rtn != 256)
#endif /* USE_VGI */
printf("%s: sim_fread error. Result = %d." NLP, __FUNCTION__, rtn);
}
break;
case IMAGE_TYPE_CPT:
@ -603,9 +597,9 @@ static uint8 MFDC_Write(const uint32 Addr, uint8 cData)
} else {
sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
#ifdef USE_VGI
fwrite(sdata.raw, MFDC_SECTOR_LEN, 1, (pDrive->uptr)->fileref);
sim_fwrite(sdata.raw, 1, MFDC_SECTOR_LEN, (pDrive->uptr)->fileref);
#else
fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref);
sim_fwrite(sdata.u.data, 1, 256, (pDrive->uptr)->fileref);
#endif /* USE_VGI */
}
break;

View file

@ -165,7 +165,7 @@ static t_stat n8vem_reset(DEVICE *dptr)
{
PNP_INFO *pnp = (PNP_INFO *)dptr->ctxt;
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reset." NLP));
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reset.\n"));
if(dptr->flags & DEV_DIS) { /* Disconnect I/O Ports */
sim_map_resource(pnp->io_base, pnp->io_size, RESOURCE_TYPE_IO, &n8vemdev, TRUE);
@ -196,7 +196,7 @@ static t_stat n8vem_reset(DEVICE *dptr)
static t_stat n8vem_boot(int32 unitno, DEVICE *dptr)
{
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Boot." NLP));
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Boot.\n"));
/* Clear the RAM and ROM mapping registers */
n8vem_info->mpcl_ram = 0;
@ -211,7 +211,7 @@ static t_stat n8vem_boot(int32 unitno, DEVICE *dptr)
static t_stat n8vem_attach(UNIT *uptr, char *cptr)
{
t_stat r;
int32 i = 0;
int32 i = 0, rtn;
i = find_unit_index(uptr);
@ -226,7 +226,7 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr)
/* Determine length of this disk */
uptr->capac = sim_fsize(uptr->fileref);
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Attach %s." NLP, i == 0 ? "ROM" : "RAM"));
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Attach %s.\n", i == 0 ? "ROM" : "RAM"));
if(i == 0) { /* Attaching ROM */
n8vem_info->rom_attached = TRUE;
@ -239,8 +239,10 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr)
if (uptr->capac > N8VEM_ROM_SIZE)
uptr->capac = N8VEM_ROM_SIZE;
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into ROM.\n", uptr->capac));
fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref);
rtn = fread((void *)(n8vem_info->rom), uptr->capac, 1, uptr->fileref);
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into ROM."
" Result = %ssuccessful.\n",
uptr->capac, rtn == 1 ? "" : "not "));
}
} else { /* attaching RAM */
/* Erase RAM */
@ -251,8 +253,10 @@ static t_stat n8vem_attach(UNIT *uptr, char *cptr)
if(uptr->capac > N8VEM_RAM_SIZE)
uptr->capac = N8VEM_RAM_SIZE;
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into RAM.\n", uptr->capac));
fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref);
rtn = fread((void *)(n8vem_info->ram), uptr->capac, 1, uptr->fileref);
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Reading %d bytes into RAM."
" Result = %ssuccessful.\n",
uptr->capac, rtn == 1 ? "" : "not "));
}
}
return r;
@ -270,7 +274,7 @@ static t_stat n8vem_detach(UNIT *uptr)
return (SCPE_IERR);
}
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Detach %s." NLP, i == 0 ? "ROM" : "RAM"));
TRACE_PRINT(VERBOSE_MSG, ("N8VEM: Detach %s.\n", i == 0 ? "ROM" : "RAM"));
/* rewind to the beginning of the file. */
sim_fseek(uptr->fileref, 0, SEEK_SET);

View file

@ -132,9 +132,6 @@ extern void raise_ss1_interrupt(uint8 intnum);
#define UNIT_V_DISK2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_DISK2_VERBOSE (1 << UNIT_V_DISK2_VERBOSE)
#define DISK2_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
static t_stat disk2_reset(DEVICE *disk2_dev);
static t_stat disk2_attach(UNIT *uptr, char *cptr);
@ -226,7 +223,6 @@ static t_stat disk2_attach(UNIT *uptr, char *cptr)
{
t_stat r = SCPE_OK;
DISK2_DRIVE_INFO *pDrive;
char header[4];
int i = 0;
i = find_unit_index(uptr);
@ -260,16 +256,10 @@ static t_stat disk2_attach(UNIT *uptr, char *cptr)
uptr->u3 = IMAGE_TYPE_DSK;
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(!strcmp(header, "IMD")) {
uptr->u3 = IMAGE_TYPE_IMD;
} else if(!strcmp(header, "CPT")) {
printf("CPT images not yet supported\n");
uptr->u3 = IMAGE_TYPE_CPT;
r = assignDiskType(uptr);
if (r != SCPE_OK) {
disk2_detach(uptr);
return SCPE_OPENERR;
} else {
uptr->u3 = IMAGE_TYPE_DSK;
return r;
}
}
@ -395,6 +385,7 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
uint8 i;
long file_offset;
DISK2_DRIVE_INFO *pDrive;
size_t rtn;
pDrive = &disk2_info->drive[disk2_info->sel_drive];
@ -457,7 +448,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET);
for(i=0;i<pDrive->nsectors;i++) {
/* Read sector */
fread(sdata.raw, (pDrive->sectsize + 3), 1, (pDrive->uptr)->fileref);
rtn = sim_fread(sdata.raw, 1, (pDrive->sectsize + 3), (pDrive->uptr)->fileref);
if (rtn != (size_t)(pDrive->sectsize + 3)) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_DATA: sim_fread error." NLP, PCX));
}
if(sdata.u.header[2] == disk2_info->sector) {
if(sdata.u.header[0] != disk2_info->cyl) { /*pDrive->track) { */
printf("DISK2: " ADDRESS_FORMAT " READ_DATA Incorrect header: track" NLP, PCX);
@ -497,7 +491,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
for(i=0;i<pDrive->nsectors;i++) {
/* Read sector */
file_offset = ftell((pDrive->uptr)->fileref);
fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref);
rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref);
if (rtn != 3) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX));
}
if(sdata.u.header[2] == disk2_info->sector) {
if(sdata.u.header[0] != disk2_info->cyl) {
printf("DISK2: " ADDRESS_FORMAT " WRITE_DATA Incorrect header: track" NLP, PCX);
@ -510,10 +507,13 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
selchan_dma(sdata.u.data, pDrive->sectsize);
sim_fseek((pDrive->uptr)->fileref, file_offset+3, SEEK_SET);
fwrite(sdata.u.data, (pDrive->sectsize), 1, (pDrive->uptr)->fileref);
sim_fwrite(sdata.u.data, 1, (pDrive->sectsize), (pDrive->uptr)->fileref);
break;
}
fread(sdata.raw, pDrive->sectsize, 1, (pDrive->uptr)->fileref);
rtn = sim_fread(sdata.raw, 1, pDrive->sectsize, (pDrive->uptr)->fileref);
if (rtn != (size_t)(pDrive->sectsize)) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " WRITE_DATA: sim_fread error." NLP, PCX));
}
if(i == pDrive->nsectors) {
printf("DISK2: " ADDRESS_FORMAT " Sector not found" NLP, PCX);
disk2_info->timeout = 1;
@ -532,7 +532,7 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
i = disk2_info->hdr_sector;
selchan_dma(sdata.raw, 3);
sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * (pDrive->sectsize + 3) * pDrive->nsectors) + (i * (pDrive->sectsize + 3)), SEEK_SET);
fwrite(sdata.raw, 3, 1, (pDrive->uptr)->fileref);
sim_fwrite(sdata.raw, 1, 3, (pDrive->uptr)->fileref);
disk2_info->hdr_sector++;
if(disk2_info->hdr_sector >= pDrive->nsectors) {
@ -544,7 +544,10 @@ static uint8 DISK2_Write(const uint32 Addr, uint8 cData)
track_offset = pDrive->track * pDrive->nheads * pDrive->nsectors * (pDrive->sectsize + 3);
TRACE_PRINT(CMD_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER Command" NLP, PCX));
sim_fseek((pDrive->uptr)->fileref, track_offset + (disk2_info->head_sel * pDrive->nsectors * (pDrive->sectsize + 3)), SEEK_SET);
fread(sdata.raw, 3, 1, (pDrive->uptr)->fileref);
rtn = sim_fread(sdata.raw, 1, 3, (pDrive->uptr)->fileref);
if (rtn != 3) {
TRACE_PRINT(ERROR_MSG, ("DISK2: " ADDRESS_FORMAT " READ_HEADER: sim_fread error." NLP, PCX));
}
selchan_dma(sdata.raw, 3);
break;

View file

@ -193,9 +193,6 @@ extern uint8 GetByteDMA(const uint32 Addr);
#define UNIT_V_DISK3_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_DISK3_VERBOSE (1 << UNIT_V_DISK3_VERBOSE)
#define DISK3_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
static t_stat disk3_reset(DEVICE *disk3_dev);
static t_stat disk3_attach(UNIT *uptr, char *cptr);
@ -293,8 +290,7 @@ static t_stat disk3_attach(UNIT *uptr, char *cptr)
{
t_stat r = SCPE_OK;
DISK3_DRIVE_INFO *pDrive;
char header[4];
unsigned int i = 0;
int i = 0;
i = find_unit_index(uptr);
if (i == -1) {
@ -326,16 +322,10 @@ static t_stat disk3_attach(UNIT *uptr, char *cptr)
uptr->u3 = IMAGE_TYPE_DSK;
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(!strcmp(header, "IMD")) {
uptr->u3 = IMAGE_TYPE_IMD;
} else if(!strcmp(header, "CPT")) {
printf("CPT images not yet supported\n");
uptr->u3 = IMAGE_TYPE_CPT;
r = assignDiskType(uptr);
if (r != SCPE_OK) {
disk3_detach(uptr);
return SCPE_OPENERR;
} else {
uptr->u3 = IMAGE_TYPE_DSK;
return r;
}
}
@ -517,6 +507,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
uint32 file_offset;
uint32 xfr_count = 0;
uint8 *dataBuffer;
size_t rtn;
if(disk3_info->mode == DISK3_MODE_ABS) {
TRACE_PRINT(ERROR_MSG, ("DISK3: Absolute addressing not supported." NLP));
@ -539,16 +530,19 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET);
if(disk3_info->iopb[DISK3_IOPB_ARG1] == 1) { /* Read */
TRACE_PRINT(RD_DATA_MSG, ("DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d" NLP,
rtn = sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref);
TRACE_PRINT(RD_DATA_MSG,
("DISK3[%d]: " ADDRESS_FORMAT " READ @0x%05x T:%04d/S:%04d/#:%d %s" NLP,
disk3_info->sel_drive,
PCX,
disk3_info->dma_addr,
pDrive->cur_track,
pDrive->cur_sect,
pDrive->xfr_nsects
pDrive->xfr_nsects,
rtn == (size_t)xfr_len ? "OK" : "NOK"
));
fread(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref);
/* Perform DMA Transfer */
for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) {
@ -569,7 +563,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
dataBuffer[xfr_count] = GetByteDMA(disk3_info->dma_addr + xfr_count);
}
fwrite(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref);
sim_fwrite(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref);
}
free(dataBuffer);
@ -618,7 +612,7 @@ static uint8 DISK3_Write(const uint32 Addr, uint8 cData)
memset(fmtBuffer, disk3_info->iopb[DISK3_IOPB_ARG2], data_len);
sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET);
fwrite(fmtBuffer, data_len, 1, (pDrive->uptr)->fileref);
sim_fwrite(fmtBuffer, 1, data_len, (pDrive->uptr)->fileref);
free(fmtBuffer);

View file

@ -2,7 +2,7 @@
IMSAI FIF Disk Controller by Ernie Price
Based on altairz80_dsk.c, Copyright (c) 2002-2008, Peter Schorn
Based on altairz80_dsk.c, Copyright (c) 2002-2010, Peter Schorn
Plug-n-Play added by Howard M. Harte
@ -197,6 +197,7 @@ static int DoDiskOperation(desc_t *dsc, uint8 val)
addr;
FILE *cpx;
UNIT *uptr;
int32 rtn;
#if 0
printf("%02x %02x %02x %02x %02x %02x %02x %02x \n",
@ -242,14 +243,19 @@ static int DoDiskOperation(desc_t *dsc, uint8 val)
/* write a track worth of sectors */
for (kt=0; kt < SPT; kt++) {
fwrite(blanksec, 1, sizeof(blanksec), cpx);
sim_fwrite(blanksec, 1, sizeof(blanksec), cpx);
}
break;
case READ_SEC:
addr = (dsc->track * SPT) + dsc->sector - 1;
sim_fseek(cpx, addr * SEC_SZ, SEEK_SET);
fread(blanksec, 1, SEC_SZ, cpx);
rtn = sim_fread(blanksec, 1, SEC_SZ, cpx);
if ( (rtn != SEC_SZ) && (current_disk_flags & UNIT_DSK_VERBOSE) &&
(warnAttached[current_disk] < warnLevelDSK) ) {
warnAttached[current_disk]++;
printf("FIF%i: " ADDRESS_FORMAT " sim_fread error." NLP, current_disk, PCX);
}
addr = dsc->addr_l + (dsc->addr_h << 8); /* no assumption on endianness */
for (kt = 0; kt < SEC_SZ; kt++) {
PutBYTEWrapper(addr++, blanksec[kt]);
@ -263,7 +269,7 @@ static int DoDiskOperation(desc_t *dsc, uint8 val)
for (kt = 0; kt < SEC_SZ; kt++) {
blanksec[kt] = GetBYTEWrapper(addr++);
}
fwrite(blanksec, 1, SEC_SZ, cpx);
sim_fwrite(blanksec, 1, SEC_SZ, cpx);
break;
default:
@ -447,7 +453,7 @@ uint8 FTP(int32 BC, int32 DE)
case 20:
memset(temp, 0x1a, SEC_SZ);
retval = fread(temp, 1, SEC_SZ, myfile) ? 0 : 1;
retval = sim_fread(temp, 1, SEC_SZ, myfile) ? 0 : 1;
xfero( DE, temp, SEC_SZ);
if (retval)
{

View file

@ -112,9 +112,6 @@ extern uint8 GetBYTEWrapper(const uint32 Addr);
#define UNIT_V_HDC1001_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_HDC1001_VERBOSE (1 << UNIT_V_HDC1001_VERBOSE)
#define HDC1001_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
static t_stat hdc1001_reset(DEVICE *hdc1001_dev);
static t_stat hdc1001_attach(UNIT *uptr, char *cptr);
@ -198,8 +195,7 @@ static t_stat hdc1001_attach(UNIT *uptr, char *cptr)
{
t_stat r = SCPE_OK;
HDC1001_DRIVE_INFO *pDrive;
char header[4];
unsigned int i = 0;
int i = 0;
i = find_unit_index(uptr);
if (i == -1) {
@ -231,16 +227,10 @@ static t_stat hdc1001_attach(UNIT *uptr, char *cptr)
uptr->u3 = IMAGE_TYPE_DSK;
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(!strcmp(header, "IMD")) {
uptr->u3 = IMAGE_TYPE_IMD;
} else if(!strcmp(header, "CPT")) {
printf("CPT images not yet supported\n");
uptr->u3 = IMAGE_TYPE_CPT;
r = assignDiskType(uptr);
if (r != SCPE_OK) {
hdc1001_detach(uptr);
return SCPE_OPENERR;
} else {
uptr->u3 = IMAGE_TYPE_DSK;
return r;
}
}
@ -372,7 +362,6 @@ static uint8 HDC1001_Write(const uint32 Addr, uint8 cData)
switch(Addr & 0x07) {
case TF_SDH:
hdc1001_info->sel_drive = (cData >> 3) & 0x03;
pDrive = &hdc1001_info->drive[hdc1001_info->sel_drive];
case TF_DATA:
case TF_ERROR:
case TF_SECNT:
@ -393,14 +382,10 @@ static uint8 HDC1001_Write(const uint32 Addr, uint8 cData)
hdc1001_info->taskfile[TF_SDH] & 0x07,
hdc1001_info->taskfile[TF_SECNO],
pDrive->xfr_nsects));
break;
default:
break;
}
return 0;
}
@ -541,7 +526,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
pDrive->xfr_nsects
));
fread(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref);
sim_fread(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref);
/* Perform DMA Transfer */
for(xfr_count = 0;xfr_count < xfr_len; xfr_count++) {
@ -562,7 +547,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
dataBuffer[xfr_count] = GetBYTEWrapper(hdc1001_info->dma_addr + xfr_count);
}
fwrite(dataBuffer, xfr_len, 1, (pDrive->uptr)->fileref);
sim_fwrite(dataBuffer, 1, xfr_len, (pDrive->uptr)->fileref);
}
free(dataBuffer);
@ -593,7 +578,7 @@ static uint8 HDC1001_Read(const uint32 Addr)
memset(fmtBuffer, hdc1001_info->iopb[4], data_len);
sim_fseek((pDrive->uptr)->fileref, file_offset, SEEK_SET);
fwrite(fmtBuffer, data_len, 1, (pDrive->uptr)->fileref);
sim_fwrite(fmtBuffer, 1, data_len, (pDrive->uptr)->fileref);
free(fmtBuffer);

View file

@ -42,6 +42,7 @@
/*#define DBG_MSG*/
#include "altairz80_defs.h"
#include "sim_imd.h"
#if defined (_WIN32)
#include <windows.h>
@ -160,8 +161,6 @@ static SECTOR_FORMAT sdata;
#define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE)
#define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN) /* Default North Star Disk Capacity */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
/* MDS-AD Controller Subcases */
#define MDSAD_READ_ROM 0
@ -325,8 +324,8 @@ t_stat mdsad_attach(UNIT *uptr, char *cptr)
uptr->u3 = IMAGE_TYPE_DSK;
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(!strcmp(header, "CPT")) {
char *rtn = fgets(header, 4, uptr->fileref);
if((rtn != NULL) && (strncmp(header, "CPT", 3) == 0)) {
printf("CPT images not yet supported\n");
uptr->u3 = IMAGE_TYPE_CPT;
mdsad_detach(uptr);
@ -338,7 +337,7 @@ t_stat mdsad_attach(UNIT *uptr, char *cptr)
if (uptr->flags & UNIT_MDSAD_VERBOSE)
printf("MDSAD%d, attached to '%s', type=%s, len=%d\n", i, cptr,
uptr->u3 == uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",
uptr->u3 == IMAGE_TYPE_CPT ? "CPT" : "DSK",
uptr->capac);
return SCPE_OK;
@ -450,6 +449,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
uint8 cData;
uint8 ds;
MDSAD_DRIVE_INFO *pDrive;
int32 rtn;
cData = 0x00;
@ -502,7 +502,7 @@ static uint8 MDSAD_Read(const uint32 Addr)
printf(".fileref is NULL!" NLP);
} else {
sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
fwrite(sdata.u.data, MDSAD_SECTOR_LEN, 1,
sim_fwrite(sdata.u.data, 1, MDSAD_SECTOR_LEN,
(pDrive->uptr)->fileref);
}
break;
@ -735,8 +735,11 @@ static uint8 MDSAD_Read(const uint32 Addr)
} else {
sim_fseek((pDrive->uptr)->fileref,
sec_offset, SEEK_SET);
fread(&sdata.u.data[0], MDSAD_SECTOR_LEN,
1, (pDrive->uptr)->fileref);
rtn = sim_fread(&sdata.u.data[0], 1, MDSAD_SECTOR_LEN,
(pDrive->uptr)->fileref);
if (rtn != MDSAD_SECTOR_LEN) {
TRACE_PRINT(ERROR_MSG, ("MDSAD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX));
}
}
break;
case IMAGE_TYPE_CPT:

View file

@ -63,8 +63,11 @@
#endif
/* use NLP for new line printing while the simulation is running */
#define UNIX_PLATFORM (defined (__linux) || defined(__NetBSD__) \
|| defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__))
#if defined (__linux) || defined(__NetBSD__) || defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__APPLE__)
#define UNIX_PLATFORM 1
#else
#define UNIX_PLATFORM 0
#endif
#if UNIX_PLATFORM
#define NLP "\r\n"
@ -72,7 +75,7 @@
#define NLP "\n"
#endif
#if defined (__MWERKS__) && defined (macintosh)
#if (defined (__MWERKS__) && defined (macintosh)) || defined(__DECC)
#define __FUNCTION__ __FILE__
#endif
@ -174,7 +177,7 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose)
do {
DBG_PRINT(("start of track %d at file offset %ld" NLP, myDisk->ntracks, ftell(myDisk->file)));
fread(&imd, 1, 5, myDisk->file);
sim_fread(&imd, 1, 5, myDisk->file);
if (feof(myDisk->file))
break;
sectorSize = 128 << imd.sectsize;
@ -197,7 +200,10 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose)
myDisk->track[imd.cyl][imd.head].nsects = imd.nsects;
myDisk->track[imd.cyl][imd.head].sectsize = sectorSize;
fread(sectorMap, 1, imd.nsects, myDisk->file);
if (sim_fread(sectorMap, 1, imd.nsects, myDisk->file) != imd.nsects) {
printf("SIM_IMD: Corrupt file [Sector Map]." NLP);
return (SCPE_OPENERR);
}
myDisk->track[imd.cyl][imd.head].start_sector = imd.nsects;
DBG_PRINT(("\tSector Map: "));
for(i=0;i<imd.nsects;i++) {
@ -209,7 +215,10 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose)
DBG_PRINT((", Start Sector=%d", myDisk->track[imd.cyl][imd.head].start_sector));
if(sectorHeadwithFlags & IMD_FLAG_SECT_HEAD_MAP) {
fread(sectorHeadMap, 1, imd.nsects, myDisk->file);
if (sim_fread(sectorHeadMap, 1, imd.nsects, myDisk->file) != imd.nsects) {
printf("SIM_IMD: Corrupt file [Sector Head Map]." NLP);
return (SCPE_OPENERR);
}
DBG_PRINT(("\tSector Head Map: "));
for(i=0;i<imd.nsects;i++) {
DBG_PRINT(("%d ", sectorHeadMap[i]));
@ -223,7 +232,10 @@ static t_stat diskParse(DISK_INFO *myDisk, uint32 isVerbose)
}
if(sectorHeadwithFlags & IMD_FLAG_SECT_CYL_MAP) {
fread(sectorCylMap, 1, imd.nsects, myDisk->file);
if (sim_fread(sectorCylMap, 1, imd.nsects, myDisk->file) != imd.nsects) {
printf("SIM_IMD: Corrupt file [Sector Cyl Map]." NLP);
return (SCPE_OPENERR);
}
DBG_PRINT(("\tSector Cyl Map: "));
for(i=0;i<imd.nsects;i++) {
DBG_PRINT(("%d ", sectorCylMap[i]));
@ -541,7 +553,9 @@ t_stat sectRead(DISK_INFO *myDisk,
case SECT_RECORD_NORM_DAM: /* Normal Data with deleted address mark */
/* DBG_PRINT(("Uncompressed Data" NLP)); */
fread(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file);
if (sim_fread(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file) != myDisk->track[Cyl][Head].sectsize) {
printf("SIM_IMD[%s]: sim_fread error for SECT_RECORD_NORM_DAM." NLP, __FUNCTION__);
}
*readlen = myDisk->track[Cyl][Head].sectsize;
break;
case SECT_RECORD_NORM_COMP_ERR: /* Compressed Normal Data */
@ -641,7 +655,7 @@ t_stat sectWrite(DISK_INFO *myDisk,
}
fputc(sectRecordType, myDisk->file);
fwrite(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file);
sim_fwrite(buf, 1, myDisk->track[Cyl][Head].sectsize, myDisk->file);
*writelen = myDisk->track[Cyl][Head].sectsize;
return(SCPE_OK);
@ -729,9 +743,9 @@ t_stat trackWrite(DISK_INFO *myDisk,
track_header.sectsize = sectorLen;
/* Forward to end of the file, write track header and sector map. */
fseek(myDisk->file, 0, SEEK_END);
fwrite(&track_header, sizeof(IMD_HEADER), 1, fileref);
fwrite(sectorMap, 1, numSectors, fileref);
sim_fseek(myDisk->file, 0, SEEK_END);
sim_fwrite(&track_header, 1, sizeof(IMD_HEADER), fileref);
sim_fwrite(sectorMap, 1, numSectors, fileref);
/* Compute data length, and fill a sector buffer with the
* sector record type as the first byte, and fill the sector
@ -744,7 +758,7 @@ t_stat trackWrite(DISK_INFO *myDisk,
/* For each sector on the track, write the record type and sector data. */
for(i=0;i<numSectors;i++) {
fwrite(sectorData, 1, dataLen, fileref);
sim_fwrite(sectorData, 1, dataLen, fileref);
}
/* Flush the file, and free the sector buffer. */
@ -756,3 +770,25 @@ t_stat trackWrite(DISK_INFO *myDisk,
return(SCPE_OK);
}
/* Utility function to set the image type for a unit to the correct value.
* Prints an error message in case a CPT image is presented and returns
* SCPE_OPENERR in this case. Otherwise the return value is SCPE_OK
*/
t_stat assignDiskType(UNIT *uptr) {
t_stat result = SCPE_OK;
char header[4];
if (fgets(header, 4, uptr->fileref) == NULL)
uptr->u3 = IMAGE_TYPE_DSK;
else if (strncmp(header, "IMD", 3) == 0)
uptr->u3 = IMAGE_TYPE_IMD;
else if(strncmp(header, "CPT", 3) == 0) {
printf("CPT images not yet supported.\n");
uptr->u3 = IMAGE_TYPE_CPT;
result = SCPE_OPENERR;
}
else
uptr->u3 = IMAGE_TYPE_DSK;
return result;
}

View file

@ -85,6 +85,10 @@ typedef struct {
#define IMD_MODE_FM(x) (x <= IMD_MODE_250K_FM)
#define IMD_MODE_MFM(x) (x >= IMD_MODE_500K_MFM)
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
typedef struct {
uint8 mode;
uint8 nsects;
@ -121,3 +125,4 @@ extern t_stat trackWrite(DISK_INFO *myDisk,
uint8 mode,
uint8 fillbyte,
uint32 *flags);
extern t_stat assignDiskType(UNIT *uptr);

View file

@ -146,9 +146,6 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ
#define UNIT_V_VFDHD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
#define UNIT_VFDHD_VERBOSE (1 << UNIT_V_VFDHD_VERBOSE)
#define VFDHD_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
static t_stat vfdhd_reset(DEVICE *vfdhd_dev);
static t_stat vfdhd_attach(UNIT *uptr, char *cptr);
@ -230,7 +227,6 @@ static t_stat vfdhd_reset(DEVICE *dptr)
/* Attach routine */
static t_stat vfdhd_attach(UNIT *uptr, char *cptr)
{
char header[4];
t_stat r;
unsigned int i = 0;
@ -252,16 +248,10 @@ static t_stat vfdhd_attach(UNIT *uptr, char *cptr)
}
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(!strcmp(header, "IMD")) {
uptr->u3 = IMAGE_TYPE_IMD;
} else if(!strcmp(header, "CPT")) {
printf("CPT images not yet supported\n");
uptr->u3 = IMAGE_TYPE_CPT;
r = assignDiskType(uptr);
if (r != SCPE_OK) {
vfdhd_detach(uptr);
return SCPE_OPENERR;
} else {
uptr->u3 = IMAGE_TYPE_DSK;
return r;
}
} else {
/* creating file, must be DSK format. */
@ -542,6 +532,7 @@ static void VFDHD_Command(void)
uint32 sec_offset;
uint32 flags;
int32 rtn;
pDrive = &(vfdhd_info->drive[vfdhd_info->sel_drive]);
@ -604,7 +595,10 @@ static void VFDHD_Command(void)
printf(".fileref is NULL!" NLP);
} else {
sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
fread(&sdata.u.sync, 274, /*VFDHD_SECTOR_LEN,*/ 1, (pDrive->uptr)->fileref);
rtn = sim_fread(&sdata.u.sync, 1, 274, /*VFDHD_SECTOR_LEN,*/ (pDrive->uptr)->fileref);
if (rtn != 274) {
TRACE_PRINT(ERROR_MSG, ("VFDHD: " ADDRESS_FORMAT " READ: sim_fread error." NLP, PCX));
}
memset(&sdata.u.preamble, 0, 40);
memset(&sdata.u.ecc, 0, 5); /* Clear out the ECC and ECC Valid bytes */
@ -670,9 +664,9 @@ static void VFDHD_Command(void)
vfdhd_info->sector));
sim_fseek((pDrive->uptr)->fileref, sec_offset, SEEK_SET);
#ifdef USE_VGI
fwrite(&sdata.u.sync, VFDHD_SECTOR_LEN, 1, (pDrive->uptr)->fileref);
sim_fwrite(&sdata.u.sync, 1, VFDHD_SECTOR_LEN, (pDrive->uptr)->fileref);
#else
fwrite(sdata.u.data, 256, 1, (pDrive->uptr)->fileref);
sim_fwrite(sdata.u.data, 1, 256, (pDrive->uptr)->fileref);
#endif /* USE_VGI */
}
break;

View file

@ -152,6 +152,7 @@ extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
extern int32 find_unit_index (UNIT *uptr);
t_stat wd179x_svc (UNIT *uptr);
@ -165,9 +166,6 @@ extern uint8 GetBYTEWrapper(const uint32 Addr);
#define UNIT_WD179X_VERBOSE (1 << UNIT_V_WD179X_VERBOSE)
#define WD179X_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
#define WD179X_CAPACITY_SSSD (77*1*26*128) /* Single-sided Single Density IBM Diskette1 */
#define IMAGE_TYPE_DSK 1 /* Flat binary "DSK" image file. */
#define IMAGE_TYPE_IMD 2 /* ImageDisk "IMD" image file. */
#define IMAGE_TYPE_CPT 3 /* CP/M Transfer "CPT" image file. */
/* Write Track (format) Statemachine states */
#define FMT_GAP1 1
@ -197,7 +195,6 @@ extern uint8 GetBYTEWrapper(const uint32 Addr);
static int32 wd179xdev(const int32 port, const int32 io, const int32 data);
static t_stat wd179x_reset(DEVICE *dptr);
int32 find_unit_index (UNIT *uptr);
uint8 floorlog2(unsigned int n);
WD179X_INFO wd179x_info_data = { { 0x0, 0, 0x30, 4 } };
@ -278,8 +275,6 @@ static t_stat wd179x_reset(DEVICE *dptr)
return SCPE_OK;
}
extern int32 find_unit_index (UNIT *uptr);
void wd179x_external_restore(void)
{
WD179X_DRIVE_INFO *pDrive;
@ -330,8 +325,8 @@ t_stat wd179x_attach(UNIT *uptr, char *cptr)
wd179x_info->drive[i].ready = 0;
if(uptr->capac > 0) {
fgets(header, 4, uptr->fileref);
if(strncmp(header, "IMD", 3)) {
char *rtn = fgets(header, 4, uptr->fileref);
if ((rtn != NULL) && strncmp(header, "IMD", 3)) {
printf("WD179X: Only IMD disk images are supported\n");
wd179x_info->drive[i].uptr = NULL;
return SCPE_OPENERR;

View file

@ -1,6 +1,6 @@
/* h316_cpu.c: Honeywell 316/516 CPU simulator
Copyright (c) 1999-2008, Robert M. Supnik
Copyright (c) 1999-2010, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
cpu H316/H516 CPU
10-Jan-10 RMS Fixed bugs in LDX, STX introduced in 3.8-1 (from Theo Engel)
28-Apr-07 RMS Removed clock initialization
03-Apr-06 RMS Fixed bugs in LLL, LRL (from Theo Engel)
22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
@ -614,13 +615,13 @@ switch (I_GETOP (MB)) { /* case on <1:6> */
break;
case 015: case 055: /* STX */
if (reason = Ea (MB, &Y)) /* eff addr */
if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */
break;
Write (Y, XR); /* store XR */
break;
case 035: case 075: /* LDX */
if (reason = Ea (MB, &Y)) /* eff addr */
if (reason = Ea (MB & ~IDX, &Y)) /* eff addr */
break;
XR = Read (Y); /* load XR */
break;

View file

@ -1,6 +1,6 @@
/* hp2100_cpu.h: HP 2100 CPU definitions
Copyright (c) 2005-2008, Robert M. Supnik
Copyright (c) 2005-2010, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
03-Jan-10 RMS Changed declarations of mp_control, mp_mefvv, for VMS compiler
15-Jul-08 JDB Rearranged declarations with hp2100_cpu.c and hp2100_defs.h
26-Jun-08 JDB Added mp_control to CPU state externals
24-Apr-08 JDB Added calc_defer() prototype
@ -285,10 +286,10 @@ extern uint32 dms_enb;
extern uint32 dms_ump;
extern uint32 dms_sr;
extern uint32 dms_vr;
extern uint32 mp_control;
extern FLIP_FLOP mp_control;
extern uint32 mp_fence;
extern uint32 mp_viol;
extern uint32 mp_mevff;
extern FLIP_FLOP mp_mevff;
extern uint32 iop_sp;
extern t_bool ion_defer;
extern uint32 intaddr;

View file

@ -1,6 +1,6 @@
/* i1401_cd.c: IBM 1402 card reader/punch
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2010, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -35,6 +35,8 @@
Cards are represented as ASCII text streams terminated by newlines.
This allows cards to be created and edited as normal files.
24-Mar-09 RMS Fixed read stacker operation in column binary mode
Fixed punch stacker operation (from Van Snyder)
28-Jun-07 RMS Added support for SS overlap modifiers
19-Jan-07 RMS Added UNIT_TEXT flag
20-Sep-05 RMS Revised for new code tables, compatible colbinary treatment
@ -59,10 +61,16 @@ extern int32 ind[64], ssa, iochk;
extern int32 conv_old;
int32 s1sel, s2sel, s4sel, s8sel;
char rbuf[2 * CBUFSIZE]; /* > CDR_WIDTH */
char cdr_buf[(2 * CBUFSIZE) + 1]; /* > CDR_WIDTH */
char cdp_buf[(2 * CDP_WIDTH) + 1]; /* + null */
int32 cdp_buf_full = 0; /* punch buf full? */
t_stat cdr_svc (UNIT *uptr);
t_stat cdr_boot (int32 unitno, DEVICE *dptr);
t_stat cdr_attach (UNIT *uptr, char *cptr);
t_stat cdp_attach (UNIT *uptr, char *cptr);
t_stat cdp_detach (UNIT *uptr);
t_stat cdp_npr (UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cd_reset (DEVICE *dptr);
int32 bcd2asc (int32 c, UNIT *uptr);
char colbin_to_bcd (uint32 cb);
@ -85,7 +93,7 @@ REG cdr_reg[] = {
{ FLDATA (S2, s2sel, 0) },
{ DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT },
{ DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT },
{ BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) },
{ BRDATA (BUF, cdr_buf, 8, 8, CDR_WIDTH * 2) },
{ NULL }
};
@ -112,12 +120,17 @@ REG cdp_reg[] = {
{ FLDATA (S4, s4sel, 0) },
{ FLDATA (S8, s8sel, 0) },
{ DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT },
{ BRDATA (BUF, cdp_buf, 8, 8, CDP_WIDTH * 2) },
{ FLDATA (FULL, cdp_buf_full, 0) },
{ NULL }
};
MTAB cdp_mod[] = {
{ UNIT_PCH, 0, "business set", "BUSINESS" },
{ UNIT_PCH, UNIT_PCH, "Fortran set", "FORTRAN" },
{ MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "NPR",
&cdp_npr, NULL },
{ 0 }
};
@ -125,7 +138,7 @@ DEVICE cdp_dev = {
"CDP", &cdp_unit, cdp_reg, cdp_mod,
1, 10, 31, 1, 8, 7,
NULL, NULL, &cd_reset,
NULL, NULL, NULL
NULL, &cdp_attach, &cdp_detach
};
/* Stacker data structures
@ -152,7 +165,7 @@ REG stack_reg[] = {
};
DEVICE stack_dev = {
"STKR", stack_unit, stack_reg, cdp_mod,
"STKR", stack_unit, stack_reg, NULL,
5, 10, 31, 1, 8, 7,
NULL, NULL, &cd_reset,
NULL, NULL, NULL
@ -178,9 +191,9 @@ if ((cdr_unit.flags & UNIT_ATT) == 0) /* attached? */
return SCPE_UNATT;
ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */
cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */
for (i = 0; i < 2 * CBUFSIZE; i++) /* clear extended buf */
rbuf[i] = 0;
fgets (rbuf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */
for (i = 0; i < (2 * CBUFSIZE) + 1; i++) /* clear extended buf */
cdr_buf[i] = 0;
fgets (cdr_buf, (cbn)? 2 * CBUFSIZE: CBUFSIZE, /* rd bin/char card */
cdr_unit.fileref);
if (feof (cdr_unit.fileref)) /* eof? */
return STOP_NOCD;
@ -202,12 +215,12 @@ if (ssa) { /* if last cd on */
if (cbn) { /* column binary */
for (i = 0; i < CDR_WIDTH; i++) {
if (conv_old) {
c1 = ascii2bcd (rbuf[i]);
c2 = ascii2bcd (rbuf[CDR_WIDTH + i]);
c1 = ascii2bcd (cdr_buf[i]);
c2 = ascii2bcd (cdr_buf[CDR_WIDTH + i]);
}
else {
c1 = ascii2bcd (rbuf[2 * i]);
c2 = ascii2bcd (rbuf[(2 * i) + 1]);
c1 = ascii2bcd (cdr_buf[2 * i]);
c2 = ascii2bcd (cdr_buf[(2 * i) + 1]);
}
M[CD_CBUF1 + i] = (M[CD_CBUF1 + i] & WM) | c1;
M[CD_CBUF2 + i] = (M[CD_CBUF2 + i] & WM) | c2;
@ -216,8 +229,8 @@ if (cbn) { /* column binary */
} /* end if col bin */
else { /* normal read */
for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */
rbuf[i] = ascii2bcd (rbuf[i]);
M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | rbuf[i];
c1 = ascii2bcd (cdr_buf[i]);
M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | c1;
}
}
M[CDR_BUF - 1] = 060; /* mem mark */
@ -228,12 +241,15 @@ return SCPE_OK;
/* Card reader service. If a stacker select is active, copy to the
selected stacker. Otherwise, copy to the normal stacker. If the
unit is unattached, simply exit.
The original card buffer (cdr_buf) has not been changed from its input
format (ASCII text), with its newline attached. There is a guaranteed
null at the end, because the buffer was zeroed prior to the read, and
is one character longer than the maximum string length.
*/
t_stat cdr_svc (UNIT *uptr)
{
int32 i;
if (s1sel) /* stacker 1? */
uptr = &stack_unit[1];
else if (s2sel) /* stacker 2? */
@ -241,13 +257,7 @@ else if (s2sel) /* stacker 2? */
else uptr = &stack_unit[0]; /* then default */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_OK;
for (i = 0; i < CDR_WIDTH; i++)
rbuf[i] = bcd2ascii (rbuf[i], uptr->flags & UNIT_PCH);
for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--)
rbuf[i] = 0;
rbuf[CDR_WIDTH] = 0; /* null at end */
fputs (rbuf, uptr->fileref); /* write card */
fputc ('\n', uptr->fileref); /* plus new line */
fputs (cdr_buf, uptr->fileref); /* write card */
uptr->pos = ftell (uptr->fileref); /* update position */
if (ferror (uptr->fileref)) { /* error? */
perror ("Card stacker I/O error");
@ -262,23 +272,22 @@ return SCPE_OK;
Modifiers have been checked by the caller
C modifier is recognized (column binary is implemented)
- Run out any previously buffered card
- Clear stacker select
- Copy card from memory buffer to punch buffer
*/
t_stat punch_card (int32 ilnt, int32 mod)
{
int32 i, cbn, c1, c2;
static char pbuf[(2 * CDP_WIDTH) + 1]; /* + null */
t_bool use_h;
UNIT *uptr;
t_stat r;
if (s8sel) /* stack 8? */
uptr = &stack_unit[2];
else if (s4sel) /* stack 4? */
uptr = &stack_unit[4];
else uptr = &cdp_unit; /* normal output */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_UNATT;
use_h = uptr->flags & UNIT_PCH;
r = cdp_npr (NULL, 0, NULL, NULL); /* write card */
if (r != SCPE_OK)
return r;
use_h = cdp_unit.flags & UNIT_PCH;
ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */
cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */
@ -288,26 +297,46 @@ if (cbn) { /* column binary */
c1 = bcd2ascii (M[CD_CBUF1 + i] & CHAR, use_h);
c2 = bcd2ascii (M[CD_CBUF2 + i] & CHAR, use_h);
if (conv_old) {
pbuf[i] = c1;
pbuf[i + CDP_WIDTH] = c2;
cdp_buf[i] = c1;
cdp_buf[i + CDP_WIDTH] = c2;
}
else {
pbuf[2 * i] = c1;
pbuf[(2 * i) + 1] = c2;
cdp_buf[2 * i] = c1;
cdp_buf[(2 * i) + 1] = c2;
}
}
for (i = 2 * CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--)
pbuf[i] = 0;
pbuf[2 * CDP_WIDTH] = 0; /* trailing null */
for (i = (2 * CDP_WIDTH) - 1; (i >= 0) && (cdp_buf[i] == ' '); i--)
cdp_buf[i] = 0;
cdp_buf[2 * CDP_WIDTH] = 0; /* trailing null */
}
else { /* normal */
for (i = 0; i < CDP_WIDTH; i++)
pbuf[i] = bcd2ascii (M[CDP_BUF + i] & CHAR, use_h);
for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--)
pbuf[i] = 0;
pbuf[CDP_WIDTH] = 0; /* trailing null */
cdp_buf[i] = bcd2ascii (M[CDP_BUF + i] & CHAR, use_h);
for (i = CDP_WIDTH - 1; (i >= 0) && (cdp_buf[i] == ' '); i--)
cdp_buf[i] = 0;
cdp_buf[CDP_WIDTH] = 0; /* trailing null */
}
fputs (pbuf, uptr->fileref); /* output card */
cdp_buf_full = 1; /* card buffer full */
return SCPE_OK;
}
/* Punch buffered card (also handles non-process runout button) */
t_stat cdp_npr (UNIT *notused, int32 val, char *cptr, void *desc)
{
UNIT *uptr;
if (cdp_buf_full == 0) /* any card? */
return SCPE_OK; /* no, done */
cdp_buf_full = 0; /* buf empty */
if (s8sel) /* stack 8? */
uptr = &stack_unit[2];
else if (s4sel) /* stack 4? */
uptr = &stack_unit[4];
else uptr = &cdp_unit; /* normal output */
if ((uptr->flags & UNIT_ATT) == 0) /* attached? */
return SCPE_UNATT;
fputs (cdp_buf, uptr->fileref); /* output card */
fputc ('\n', uptr->fileref); /* plus new line */
uptr->pos = ftell (uptr->fileref); /* update position */
if (ferror (uptr->fileref)) { /* error? */
@ -380,6 +409,26 @@ saved_IS = BOOT_START;
return SCPE_OK;
}
/* Card punch attach */
t_stat cdp_attach (UNIT *uptr, char *cptr)
{
cdp_buf_full = 0;
return attach_unit (uptr, cptr);
}
/* Card punch detach */
t_stat cdp_detach (UNIT *uptr)
{
t_stat r;
r = cdp_npr (NULL, 0, NULL, NULL);
if (r != SCPE_OK)
return r;
return detach_unit (uptr);
}
/* Column binary to BCD
This is based on documentation in the IBM 1620 manual and may not be

View file

@ -1,6 +1,6 @@
/* i1401_cpu.c: IBM 1401 CPU simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2010, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
24-Apr-10 RMS Revised divide algorithm (from Van Snyder)
11-Jul-08 RMS Added missing A magtape modifier (from Van Snyder)
Fixed tape indicator implementation (from Bob Abeles)
Fixed bug in ZA and ZS (from Bob Abeles)
@ -210,8 +211,8 @@ t_stat cpu_show_conv (FILE *st, UNIT *uptr, int32 val, void *desc);
int32 store_addr_h (int32 addr);
int32 store_addr_t (int32 addr);
int32 store_addr_u (int32 addr);
int32 div_add (int32 ap, int32 bp, int32 aend);
int32 div_sub (int32 ap, int32 bp, int32 aend);
int32 div_add (int32 ap, int32 bp);
int32 div_sub (int32 ap, int32 bp);
void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp);
t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr);
t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod);
@ -518,7 +519,7 @@ int32 IS, ilnt, flags;
int32 op, xa, t, wm, ioind, dev, unit;
int32 a, b, i, k, asave, bsave;
int32 carry, lowprd, sign, ps;
int32 quo, ahigh, qs;
int32 quo, qs;
int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal;
t_stat reason, r1, r2;
@ -1432,19 +1433,16 @@ CHECK_LENGTH:
- AS points to the low order divisor digit.
- BS points to the high order dividend digit.
- The low order dividend digit is identified by sign (zone) bits.
- To the left of the dividend is a zero field of length LS + 1.
The low quotient is at low dividend - LS - 1. As BS points to the
high dividend, the low dividend is at BS + LD - 1, so the low
quotient is at BS + LD - LS - 2. The longest possible quotient is
LD - LS + 1, so the first possible non-zero quotient bit will be
found as BS - 2.
- To the left of the dividend is a (zero) field of length LS + 1.
So the quotient starts as BS - LS - 1.
The divide process starts with a subdividend that begins at BS - LS
and ends at BS. (Note that the subdividend is one digit wider than
the divisor, to allow for borrows during the divide process.) This
means that non-zero digits in the "zero" field to the left of the
dividend CAN affect the divide.
This pointer calculation assumes that the divisor has no leading zeroes.
For each leading zero, the start of the quotient will be one position
further left.
Start by locating the high order non-zero digit of the divisor. This
also tests for a divide by zero.
Start by computing the length of the divisor and testing for divide
by zero.
Instruction lengths:
@ -1458,17 +1456,17 @@ CHECK_LENGTH:
case OP_DIV:
asave = AS;
ahigh = -1;
do {
t = 0; /* assume all 0's */
do { /* scan divisor */
a = M[AS]; /* get dvr char */
if ((a & CHAR) != BCD_ZERO) /* mark non-zero */
ahigh = AS;
if ((bcd_to_bin[a & DIGIT]) != 0) /* mark non-zero */
t = 1;
MM (AS);
}
while ((a & WM) == 0);
if (reason) /* address err? */
break;
if (ahigh < 0) { /* div by zero? */
if (t == 0) { /* div by zero? */
ind[IN_OVF] = 1; /* set ovf indic */
qs = bsave = BS; /* quo, dividend */
do {
@ -1485,15 +1483,15 @@ CHECK_LENGTH:
BS = (BS - 2) - (asave - (AS + 1)); /* final bs */
break;
}
bsave = BS + (asave - ahigh); /* end subdivd */
qs = (BS - 2) - (ahigh - (AS + 1)); /* quo start */
bsave = BS; /* end subdivd */
qs = BS - (asave - AS) - 1; /* quo start */
/* Divide loop - done with subroutines to keep the code clean.
In the loop,
asave = low order divisor
bsave = low order subdividend
qs = current quotient digit
asave = low order divisor (constant)
bsave = low order subdividend (increments)
qs = current quotient digit (increments)
*/
do {
@ -1504,11 +1502,13 @@ CHECK_LENGTH:
}
b = M[bsave]; /* save low divd */
do {
t = div_sub (asave, bsave, ahigh); /* subtract */
t = div_sub (asave, bsave); /* subtract */
quo++; /* incr quo digit */
} while (t == 0); /* until borrow */
div_add (asave, bsave, ahigh); /* restore */
div_add (asave, bsave); /* restore */
quo--;
if (quo > 9) /* overflow? */
ind[IN_OVF] = 1; /* set ovf indic */
M[qs] = (M[qs] & WM) | sum_table[quo]; /* store quo digit */
bsave++; /* adv divd, quo */
qs++;
@ -1695,7 +1695,7 @@ return bin_to_bcd[addr % 10] | (thous << (V_ZONE - 2));
/* div_add - add string for divide */
int32 div_add (int32 ap, int32 bp, int32 aend)
int32 div_add (int32 ap, int32 bp)
{
int32 a, b, c, r;
@ -1709,13 +1709,13 @@ do {
M[bp] = sum_table[r]; /* store result */
ap--;
bp--;
} while (ap >= aend);
} while ((a & WM) == 0);
return c;
}
/* div_sub - substract string for divide */
int32 div_sub (int32 ap, int32 bp, int32 aend)
int32 div_sub (int32 ap, int32 bp)
{
int32 a, b, c, r;
@ -1729,9 +1729,9 @@ do {
M[bp] = sum_table[r + 10]; /* store result */
ap--;
bp--;
} while (ap >= aend);
b = M[bp] & CHAR; /* borrow position */
if (b && (b != BCD_ZERO)) { /* non-zero? */
} while ((a & WM) == 0);
b = M[bp]; /* borrow position */
if (bcd_to_bin[b & DIGIT] != 0) { /* non-zero? */
r = bcd_to_bin[b & DIGIT] - c; /* subtract borrow */
M[bp] = sum_table[r]; /* store result */
return 0; /* subtract worked */

View file

@ -1,6 +1,6 @@
/* i1401_mt.c: IBM 1401 magnetic tape simulator
Copyright (c) 1993-2008, Robert M. Supnik
Copyright (c) 1993-2010, Robert M. Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),

View file

@ -7,7 +7,7 @@
2005.03.08 - Started
* (C) Copyright 2005, Brian Knittel.
* (C) Copyright 2005-2010, Brian Knittel.
* You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
* RISK basis, there is no warranty of fitness for any purpose, and the rest of the
* usual yada-yada. Please keep this notice and the copyright in any distributions
@ -343,7 +343,7 @@ static void sca_flush (void)
#endif
if (sca_sock != INVALID_SOCKET) {
nbytes = sim_write_sock(sca_sock, sca_sendbuf, sca_n2send);
nbytes = sim_write_sock(sca_sock, (char *) sca_sendbuf, sca_n2send);
if (nbytes == SOCKET_ERROR)
sca_socket_error();
@ -655,7 +655,7 @@ static void sca_check_indata (void)
#else
/* read socket; 0 is returned if no data is available */
nbytes = sim_read_sock(sca_sock, sca_rcvbuf, SCA_RCVBUF_SIZE);
nbytes = sim_read_sock(sca_sock, (char *) sca_rcvbuf, SCA_RCVBUF_SIZE);
#endif

View file

@ -1,6 +1,6 @@
/* pdp11_cr.c: CR/CM/CD-11 card reader simulator
Copyright (c) 2005-2007, John A. Dundas III
Copyright (c) 2005-2010, John A. Dundas III
Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu
Portions derived from work by Robert M Supnik
@ -87,6 +87,7 @@
Revision History:
03-Jan-10 JAD Eliminate gcc warnings
01-Feb-07 RMS Added PDP-10 support
12-May-06 JAD Modify the DEBUG code to use the SIMH DEBUG_x
macros. Modify the UNIT structure to include

View file

@ -1,6 +1,6 @@
/* pdp11_kg.c - Communications Arithmetic Option KG11-A
Copyright (c) 2007-2008, John A. Dundas III
Copyright (c) 2007-2010, John A. Dundas III
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
kg KG11-A Communications Arithmetic Option (M7251)
03-Jan-10 JAD Eliminate gcc warnings
08-Jan-08 JAD First public release integrated with SIMH V3.7-3.
09-Dec-07 JAD SIMH-style debugging.
Finished validating against real hardware.
@ -178,7 +179,7 @@ static t_stat set_units (UNIT *, int32, char *, void *);
/* 16-bit rotate right */
#define ROR(n,v) (((v >> n) & DMASK) | (v << (16 - n)) & DMASK)
#define ROR(n,v) (((v >> n) & DMASK) | ((v << (16 - n)) & DMASK))
/* 8-bit rotate right */

View file

@ -1,6 +1,6 @@
/* pdp11_rk.c: RK11/RKV11 cartridge disk simulator
Copyright (c) 1993-2008, Robert M Supnik
Copyright (c) 1993-2009, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
rk RK11/RKV11/RK05 cartridge disk
20-Mar-09 RMS Fixed bug in read header (from Walter F Mueller)
16-Aug-05 RMS Fixed C++ declaration and cast problems
07-Jul-05 RMS Removed extraneous externs
30-Sep-04 RMS Revised Unibus interface
@ -533,7 +534,7 @@ if (wc && (err == 0)) { /* seek ok? */
wc = i; /* trim transfer */
break;
}
rkxb[i] = (cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC);
rkxb[i] = ((cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC)) << RKDA_V_CYL;
cda = cda + RK_NUMWD; /* next sector */
} /* end for wc */
} /* end if format */

View file

@ -1,6 +1,6 @@
/* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator
Copyright (c) 1993-2008, Robert M Supnik
Copyright (c) 1993-2009, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,7 @@
rl RL11(RLV12)/RL01/RL02 cartridge disk
10-Oct-09 RMS Added debug support
22-Sep-05 RMS Fixed declarations (from Sterling Garwood)
16-Aug-05 RMS Fixed C++ declaration and cast problems
07-Jul-05 RMS Removed extraneous externs
@ -192,6 +193,7 @@ extern uint32 cpu_opt;
#define RLBAE_IMP 0000077 /* implemented */
extern int32 int_req[IPL_HLVL];
extern FILE *sim_deb;
uint16 *rlxb = NULL; /* xfer buffer */
int32 rlcs = 0; /* control/status */
@ -283,7 +285,7 @@ DEVICE rl_dev = {
RL_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16,
NULL, NULL, &rl_reset,
&rl_boot, &rl_attach, NULL,
&rl_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS
&rl_dib, DEV_DEBUG | DEV_DISABLE | DEV_UBUS | DEV_QBUS
};
/* I/O dispatch routines, I/O addresses 17774400 - 17774407
@ -333,6 +335,9 @@ switch ((PA >> 1) & 07) { /* decode PA<2:1> */
break;
} /* end switch */
if (DEBUG_PRS (rl_dev))
fprintf (sim_deb, ">>RL read: reg%d=%o\n", (PA >> 1) & 07, *data);
return SCPE_OK;
}
@ -341,6 +346,9 @@ t_stat rl_wr (int32 data, int32 PA, int32 access)
int32 curr, offs, newc, maxc;
UNIT *uptr;
if (DEBUG_PRS (rl_dev))
fprintf (sim_deb, ">>RL write: reg%d=%o\n", (PA >> 1) & 07, data);
switch ((PA >> 1) & 07) { /* decode PA<2:1> */
case 0: /* RLCS */

View file

@ -1,6 +1,6 @@
/* pdp11_rq.c: MSCP disk controller simulator
Copyright (c) 2002-2008, Robert M Supnik
Copyright (c) 2002-2010, Robert M Supnik
Derived from work by Stephen F. Shirron
Permission is hereby granted, free of charge, to any person obtaining a
@ -26,6 +26,7 @@
rq RQDX3 disk controller
14-Jan-09 JH Added support for RD32 disc drive
18-Jun-07 RMS Added UNIT_IDLE flag to timer thread
31-Oct-05 RMS Fixed address width for large files
16-Aug-05 RMS Fixed C++ declaration and cast problems
@ -127,7 +128,7 @@ extern int32 cpu_opt;
#define UNIT_V_WLK (UNIT_V_UF + 1) /* hwre write lock */
#define UNIT_V_ATP (UNIT_V_UF + 2) /* attn pending */
#define UNIT_V_DTYPE (UNIT_V_UF + 3) /* drive type */
#define UNIT_M_DTYPE 0xF
#define UNIT_M_DTYPE 0x1F
#define UNIT_ONL (1 << UNIT_V_ONL)
#define UNIT_WLK (1 << UNIT_V_WLK)
#define UNIT_ATP (1 << UNIT_V_ATP)
@ -219,7 +220,7 @@ struct rqpkt {
RD51 18 4 306 4 1 36*4 21600
RD31 17 4 615 4 1 3*8 41560
RD52 17 8 512 8 1 4*8 60480
x RD32 17 6 820 ? ? ? 83236
RD32 17 6 820 6 1 4*8 83204
x RD33 17 7 1170 ? ? ? 138565
RD53 17 7 1024 7 1 5*8 138672
RD54 17 15 1225 15 1 7*8 311200
@ -505,6 +506,22 @@ x RA73 70(+1) 21 2667+ 21 1 ? 3920490
#define RA71_MED 0x25641047
#define RA71_FLGS RQDF_SDI
#define RD32_DTYPE 16
#define RD32_SECT 17
#define RD32_SURF 6
#define RD32_CYL 820
#define RD32_TPG RD32_SURF
#define RD32_GPC 1
#define RD32_XBN 54
#define RD32_DBN 48
#define RD32_LBN 83204
#define RD32_RCTS 4
#define RD32_RCTC 8
#define RD32_RBN 200
#define RD32_MOD 15
#define RD32_MED 0x25644020
#define RD32_FLGS 0
struct drvtyp {
int32 sect; /* sectors */
int32 surf; /* surfaces */
@ -539,6 +556,7 @@ static struct drvtyp drv_tab[] = {
{ RQ_DRV (RA90), "RA90" }, { RQ_DRV (RA92), "RA92" },
{ RQ_DRV (RA8U), "RAUSER" }, { RQ_DRV (RA60), "RA60" },
{ RQ_DRV (RA81), "RA81" }, { RQ_DRV (RA71), "RA71" },
{ RQ_DRV (RD32), "RD32" },
{ 0 }
};
@ -724,6 +742,8 @@ MTAB rq_mod[] = {
&rq_set_type, NULL, NULL },
{ MTAB_XTD | MTAB_VUN, RD31_DTYPE, NULL, "RD31",
&rq_set_type, NULL, NULL },
{ MTAB_XTD | MTAB_VUN, RD32_DTYPE, NULL, "RD32",
&rq_set_type, NULL, NULL },
{ MTAB_XTD | MTAB_VUN, RD51_DTYPE, NULL, "RD51",
&rq_set_type, NULL, NULL },
{ MTAB_XTD | MTAB_VUN, RD52_DTYPE, NULL, "RD52",

View file

@ -1,6 +1,6 @@
/* pdp11_vh.c: DHQ11 asynchronous terminal multiplexor simulator
Copyright (c) 2004-2008, John A. Dundas III
Copyright (c) 2004-2010, John A. Dundas III
Portions derived from work by Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
@ -26,6 +26,7 @@
vh DHQ11 asynch multiplexor for SIMH
03-Jan-10 JAD Eliminate gcc warnings
19-Nov-08 RMS Revised for common TMXR show routines
18-Jun-07 RMS Added UNIT_IDLE flag
29-Oct-06 RMS Synced poll and clock
@ -258,13 +259,13 @@ static const int32 bitmask[4] = { 037, 077, 0177, 0377 };
/* RX FIFO state */
static int32 rbuf_idx[VH_MUXES] = { 0 };/* index into vh_rbuf */
static uint32 vh_rbuf[VH_MUXES][FIFO_SIZE] = { 0 };
static uint32 vh_rbuf[VH_MUXES][FIFO_SIZE] = { { 0 } };
/* TXQ state */
#define TXQ_SIZE (16)
static int32 txq_idx[VH_MUXES] = { 0 };
static uint32 vh_txq[VH_MUXES][TXQ_SIZE] = { 0 };
static uint32 vh_txq[VH_MUXES][TXQ_SIZE] = { { 0 } };
/* Need to extend the TMLN structure */
@ -279,9 +280,9 @@ typedef struct {
uint16 txchar; /* single character I/O */
} TMLX;
static TMLN vh_ldsc[VH_MUXES * VH_LINES] = { 0 };
static TMLN vh_ldsc[VH_MUXES * VH_LINES] = { { 0 } };
static TMXR vh_desc = { VH_MUXES * VH_LINES, 0, 0, vh_ldsc };
static TMLX vh_parm[VH_MUXES * VH_LINES] = { 0 };
static TMLX vh_parm[VH_MUXES * VH_LINES] = { { 0 } };
/* Forward references */
static t_stat vh_rd (int32 *data, int32 PA, int32 access);
@ -675,7 +676,7 @@ static void vh_getc ( int32 vh )
for (i = 0; i < VH_LINES; i++) {
lp = &vh_parm[(vh * VH_LINES) + i];
while (c = tmxr_getc_ln (lp->tmln)) {
while ((c = tmxr_getc_ln (lp->tmln)) != 0) {
if (c & SCPE_BREAK) {
fifo_put (vh, lp,
RBUF_FRAME_ERR | RBUF_PUTLINE (i));
@ -786,7 +787,7 @@ static t_stat vh_wr ( int32 data,
if (access == WRITEB)
data = (PA & 1) ?
(vh_csr[vh] & 0377) | (data << 8) :
(vh_csr[vh] & ~0377) | data & 0377;
(vh_csr[vh] & ~0377) | (data & 0377);
if (data & CSR_MASTER_RESET) {
if ((vh_unit[vh].flags & UNIT_MODEDHU) && (data & CSR_SKIP))
data &= ~CSR_MASTER_RESET;
@ -877,7 +878,7 @@ static t_stat vh_wr ( int32 data,
if (access == WRITEB)
data = (PA & 1) ?
(lp->lpr & 0377) | (data << 8) :
(lp->lpr & ~0377) | data & 0377;
(lp->lpr & ~0377) | (data & 0377);
/* Modify only if CSR<3:0> == 0 */
if (CSR_GETCHAN (vh_csr[vh]) != 0)
data &= ~LPR_DISAB_XRPT;
@ -926,7 +927,7 @@ static t_stat vh_wr ( int32 data,
if (access == WRITEB)
data = (PA & 1) ?
(lp->lnctrl & 0377) | (data << 8) :
(lp->lnctrl & ~0377) | data & 0377;
(lp->lnctrl & ~0377) | (data & 0377);
/* catch the abort TX transition */
if (!(lp->lnctrl & LNCTRL_TX_ABORT) &&
(data & LNCTRL_TX_ABORT)) {
@ -993,7 +994,7 @@ static t_stat vh_wr ( int32 data,
if (access == WRITEB)
data = (PA & 1) ?
(lp->tbuf1 & 0377) | (data << 8) :
(lp->tbuf1 & ~0377) | data & 0377;
(lp->tbuf1 & ~0377) | (data & 0377);
lp->tbuf1 = data;
break;
case 6: /* TBUFFAD2 */
@ -1008,7 +1009,7 @@ static t_stat vh_wr ( int32 data,
if (access == WRITEB)
data = (PA & 1) ?
(lp->tbuf2 & 0377) | (data << 8) :
(lp->tbuf2 & ~0377) | data & 0377;
(lp->tbuf2 & ~0377) | (data & 0377);
lp->tbuf2 = data;
/* if starting a DMA, clear DMA_ERR */
if (vh_unit[vh].flags & UNIT_FASTDMA) {
@ -1028,7 +1029,7 @@ static t_stat vh_wr ( int32 data,
if (access == WRITEB)
data = (PA & 1) ?
(lp->tbuffct & 0377) | (data << 8) :
(lp->tbuffct & ~0377) | data & 0377;
(lp->tbuffct & ~0377) | (data & 0377);
lp->tbuffct = data;
break;
default:

View file

@ -1,6 +1,6 @@
/* pdp8_fpp.c: PDP-8 floating point processor (FPP8A)
Copyright (c) 2007-2008, Robert M Supnik
Copyright (c) 2007-2010, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,27 @@
fpp FPP8A floating point processor
03-Jan-10 RMS Initialized variables statically, for VMS compiler
19-Apr-09 RHM FPICL does not clear all command and status reg bits
modify fpp_reset to conform with FPP
27-Mar-09 RHM Fixed handling of Underflow fix (zero FAC on underflow)
Implemented FPP division and multiplication algorithms
FPP behavior on traps - FEXIT does not update APT
Follow FPP settings for OPADD
Correct detection of DP add/sub overflow
Detect and handle add/sub overshift
Single-step mode made consistent with FPP
Write calculation results prior to traps
24-Mar-09 RMS Many fixes from Rick Murphy:
Fix calculation of ATX shift amount
Added missing () to read, write XR macros
Fixed indirect address calculation
Fixed == written as = in normalization
Fixed off-by-one count bug in multiplication
Removed extraneous ; in divide
Fixed direction of compare in divide
Fixed count direction bug in alignment
Floating point formats:
00 01 02 03 04 05 06 07 08 09 10 11
@ -85,8 +106,8 @@ extern UNIT cpu_unit;
/* Index registers are in memory */
#define fpp_read_xr(xr) fpp_read (fpp_xra + xr)
#define fpp_write_xr(xr,d) fpp_write (fpp_xra +xr, d)
#define fpp_read_xr(xr) fpp_read (fpp_xra + (xr))
#define fpp_write_xr(xr,d) fpp_write (fpp_xra + (xr), d)
/* Command register */
@ -112,8 +133,7 @@ extern UNIT cpu_unit;
#define FPS_IOVX 00200 /* int ovf exit */
#define FPS_FOVX 00100 /* flt ovf exit */
#define FPS_UNF 00040 /* underflow */
#define FPS_UNFX 00020 /* undf exit */
#define FPS_XXXM 00010 /* FADDM/FMULM */
#define FPS_XXXM 00020 /* FADDM/FMULM */
#define FPS_LOCK (FPC_LOCK) /* lockout */
#define FPS_EP 00004 /* ext prec */
#define FPS_PAUSE 00002 /* paused */
@ -124,24 +144,28 @@ extern UNIT cpu_unit;
#define FPN_FRSIGN 04000
#define FPN_NFR_FP 2 /* std precision */
#define FPN_NFR_EP 5 /* ext precision */
#define FPN_NFR_MDS 6 /* mul/div precision */
#define EXACT (uint32)((fpp_sta & FPS_EP)? FPN_NFR_EP: FPN_NFR_FP)
#define EXTEND ((uint32) FPN_NFR_EP)
typedef struct {
int32 exp;
uint32 fr[FPN_NFR_EP];
uint32 fr[FPN_NFR_MDS+1];
} FPN;
uint32 fpp_apta; /* APT pointer */
uint32 fpp_aptsvf; /* APT saved field */
uint32 fpp_opa; /* operand pointer */
uint32 fpp_fpc; /* FP PC */
uint32 fpp_bra; /* base reg pointer */
uint32 fpp_xra; /* indx reg pointer */
uint32 fpp_cmd; /* command */
uint32 fpp_sta; /* status */
uint32 fpp_flag; /* flag */
uint32 fpp_apta = 0; /* APT pointer */
uint32 fpp_aptsvf = 0; /* APT saved field */
uint32 fpp_opa = 0; /* operand pointer */
uint32 fpp_fpc = 0; /* FP PC */
uint32 fpp_bra = 0; /* base reg pointer */
uint32 fpp_xra = 0; /* indx reg pointer */
uint32 fpp_cmd = 0; /* command */
uint32 fpp_sta = 0; /* status */
uint32 fpp_flag = 0; /* flag */
FPN fpp_ac; /* FAC */
uint32 fpp_ssf = 0; /* single-step flag */
uint32 fpp_last_lockbit = 0; /* last lockbit */
static FPN fpp_zero = { 0, { 0, 0, 0, 0, 0 } };
static FPN fpp_one = { 1, { 02000, 0, 0, 0, 0 } };
@ -155,13 +179,13 @@ uint32 fpp_2wd_dir (uint32 ir);
uint32 fpp_indir (uint32 ir);
uint32 fpp_ad15 (uint32 hi);
uint32 fpp_adxr (uint32 ir, uint32 base_ad);
t_bool fpp_add (FPN *a, FPN *b, uint32 sub);
t_bool fpp_mul (FPN *a, FPN *b);
t_bool fpp_div (FPN *a, FPN *b);
void fpp_add (FPN *a, FPN *b, uint32 sub);
void fpp_mul (FPN *a, FPN *b);
void fpp_div (FPN *a, FPN *b);
t_bool fpp_imul (FPN *a, FPN *b);
uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b);
void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b);
void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b);
uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b, uint32 cnt);
void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b, uint32 cnt);
void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b, t_bool fix);
t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b);
uint32 fpp_fr_neg (uint32 *a, uint32 cnt);
int32 fpp_fr_cmp (uint32 *a, uint32 *b, uint32 cnt);
@ -214,6 +238,8 @@ REG fpp_reg[] = {
{ ORDATA (BRA, fpp_bra, 15) },
{ ORDATA (XRA, fpp_xra, 15) },
{ ORDATA (OPA, fpp_opa, 15) },
{ ORDATA (SSF, fpp_ssf, 12) },
{ ORDATA (LASTLOCK, fpp_last_lockbit, 12) },
{ FLDATA (FLAG, fpp_flag, 0) },
{ NULL }
};
@ -242,6 +268,7 @@ switch (IR & 07) { /* decode IR<9:11> */
case 3: /* FPCOM */
if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */
fpp_cmd = AC; /* load cmd */
fpp_last_lockbit = fpp_cmd & FPS_LOCK; /* remember lock state */
fpp_sta = (fpp_sta & ~FPC_STA) | /* copy flags */
(fpp_cmd & FPC_STA); /* to status */
}
@ -251,16 +278,25 @@ switch (IR & 07) { /* decode IR<9:11> */
if (fpp_sta & FPS_RUN) { /* running? */
if (fpp_sta & FPS_PAUSE) /* paused? */
fpp_fpc = (fpp_fpc - 1) & ADDRMASK; /* decr FPC */
fpp_sta &= ~FPS_PAUSE; /* no longer paused */
sim_cancel (&fpp_unit); /* stop execution */
fpp_dump_apt (fpp_apta, FPS_HLTX); /* dump APT */
fpp_ssf = 1; /* assume sstep */
}
else sim_activate (&fpp_unit, 0); /* single step */
else if (!fpp_flag)
fpp_ssf = 1; /* FPST sing steps */
if (fpp_sta & FPS_DVZX) /* fix diag timing */
fpp_sta |= FPS_HLTX;
break;
case 5: /* FPST */
if (!fpp_flag && !(fpp_sta & FPS_RUN)) { /* flag clr, !run? */
if (fpp_ssf)
fpp_sta |= fpp_last_lockbit;
fpp_sta &= ~FPS_HLTX; /* Clear halted */
fpp_apta = (FPC_GETAPTF (fpp_cmd) << 12) | AC;
fpp_load_apt (fpp_apta); /* load APT */
fpp_opa = fpp_fpc;
sim_activate (&fpp_unit, 0); /* start unit */
return IOT_SKP | AC;
}
@ -278,7 +314,7 @@ switch (IR & 07) { /* decode IR<9:11> */
if (fpp_flag) { /* if flag set */
uint32 old_sta = fpp_sta;
fpp_flag = 0; /* clr flag, status */
fpp_sta = 0;
fpp_sta &= ~(FPS_DP|FPS_EP|FPS_TRPX|FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF);
int_req &= ~INT_FPP; /* clr int req */
return IOT_SKP | old_sta; /* ret old status */
}
@ -296,8 +332,10 @@ int32 fpp56 (int32 IR, int32 AC)
switch (IR & 07) { /* decode IR<9:11> */
case 7: /* FPEP */
if ((AC & 04000) && !(fpp_sta & FPS_RUN)) /* if AC0, not run, */
if ((AC & 04000) && !(fpp_sta & FPS_RUN)) { /* if AC0, not run, */
fpp_sta = (fpp_sta | FPS_EP) & ~FPS_DP; /* set ep */
AC = 0;
}
break;
default:
@ -314,6 +352,7 @@ t_stat fpp_svc (UNIT *uptr)
FPN x;
uint32 ir, op, op2, op3, ad, ea, wd;
uint32 i;
int32 sc;
fpp_ac.exp = SEXT12 (fpp_ac.exp); /* sext AC exp */
do { /* repeat */
@ -332,6 +371,10 @@ do { /* repeat */
switch (op3) { /* case on subsubop */
case 0: /* FEXIT */
/* if already trapped, don't update APT, just update status */
if (fpp_sta & (FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF))
fpp_sta |= FPS_HLTX;
else
fpp_dump_apt (fpp_apta, 0);
break;
@ -351,7 +394,6 @@ do { /* repeat */
if (!(fpp_sta & FPS_DP)) { /* fp or ep only */
fpp_copy (&x, &fpp_ac); /* copy AC */
fpp_norm (&x, EXACT); /* do exact length */
if (!fpp_test_xp (&x)) /* no trap? */
fpp_copy (&fpp_ac, &x); /* copy back */
}
break;
@ -360,7 +402,6 @@ do { /* repeat */
if (fpp_sta & FPS_EP) { /* if ep, */
fpp_copy (&x, &fpp_ac); /* copy AC */
fpp_round (&x); /* round */
if (!fpp_test_xp (&x)) /* no trap? */
fpp_copy (&fpp_ac, &x); /* copy back */
}
fpp_sta &= ~(FPS_DP|FPS_EP);
@ -377,17 +418,22 @@ do { /* repeat */
break;
case 001: /* ALN */
if (op3 != 0) /* if xr, */
if (op3 != 0) { /* if xr, */
wd = fpp_read_xr (op3); /* use val */
fpp_opa = fpp_xra + op3;
}
else wd = 027; /* else 23 */
if (!(fpp_sta & FPS_DP)) { /* fp or ep? */
int32 t = wd - fpp_ac.exp; /* alignment */
sc = (SEXT12(wd) - fpp_ac.exp) & 07777; /* alignment */
sc = SEXT12 (sc);
fpp_ac.exp = SEXT12(wd); /* new exp */
wd = t & 07777;
}
if (wd & 04000) /* left? */
fpp_fr_lshn (fpp_ac.fr, 04000 - wd, EXACT);
else fpp_fr_algn (fpp_ac.fr, wd, EXACT);
else sc = SEXT12 (wd); /* dp - simple cnt */
if (sc < 0) /* left? */
fpp_fr_lshn (fpp_ac.fr, -sc, EXACT);
else fpp_fr_algn (fpp_ac.fr, sc, EXACT);
if (fpp_fr_test (fpp_ac.fr, 0, EXACT) == 0) /* zero? */
fpp_ac.exp = 0; /* clean exp */
break;
case 002: /* ATX */
@ -395,10 +441,10 @@ do { /* repeat */
fpp_write_xr (op3, fpp_ac.fr[1]); /* xr<-FAC<12:23> */
else {
fpp_copy (&x, &fpp_ac); /* copy AC */
wd = (fpp_ac.exp - 027) & 07777; /* shift amt */
if (wd & 04000) /* left? */
fpp_fr_lshn (x.fr, 04000 - wd, EXACT);
else fpp_fr_algn (x.fr, wd, EXACT);
sc = 027 - x.exp; /* shift amt */
if (sc < 0) /* left? */
fpp_fr_lshn (x.fr, -sc, EXACT);
else fpp_fr_algn (x.fr, sc, EXACT);
fpp_write_xr (op3, x.fr[1]); /* xr<-val<12:23> */
}
break;
@ -411,10 +457,11 @@ do { /* repeat */
x.exp = 027; /* standard exp */
if (!(fpp_sta & FPS_DP)) { /* fp or ep? */
fpp_norm (&x, EXACT); /* normalize */
if (fpp_test_xp (&x)) /* exception? */
break;
}
fpp_copy (&fpp_ac, &x); /* result to AC */
if (fpp_sta & FPS_DP) /* dp skips exp */
fpp_ac.exp = x.exp; /* so force copy */
fpp_opa = fpp_xra + op3;
break;
case 004: /* NOP */
@ -431,12 +478,14 @@ do { /* repeat */
case 010: /* LDX */
wd = fpp_ad15 (0); /* load XR immed */
fpp_write_xr (op3, wd);
fpp_opa = fpp_xra + op3;
break;
case 011: /* ADDX */
wd = fpp_ad15 (0);
wd = wd + fpp_read_xr (op3); /* add to XR immed */
fpp_write_xr (op3, wd); /* trims to 12b */
fpp_opa = fpp_xra + op3;
break;
default:
@ -452,6 +501,9 @@ do { /* repeat */
case 002:
ea = fpp_2wd_dir (ir);
fpp_read_op (ea, &fpp_ac);
if (fpp_sta & FPS_DP)
fpp_opa = ea + 1;
else fpp_opa = ea + 2;
break;
case 003:
@ -481,12 +533,13 @@ do { /* repeat */
fpp_write (ad, 01030 + (fpp_fpc >> 12)); /* save return */
fpp_write (ad + 1, fpp_fpc); /* trims to 12b */
fpp_fpc = (ad + 2) & ADDRMASK;
fpp_opa = fpp_fpc - 1;
break;
case 013: /* JSR */
fpp_write (fpp_bra + 1, 01030 + (fpp_fpc >> 12));
fpp_write (fpp_bra + 2, fpp_fpc); /* trims to 12b */
fpp_fpc = ad;
fpp_opa = fpp_fpc = ad;
break;
default:
@ -512,17 +565,18 @@ do { /* repeat */
fpp_add (&fpp_ac, &x, 0);
break;
case 010: /* JNX */
case 010: { /* JNX */
uint32 xrn = op2 & 07;
ad = fpp_ad15 (op3); /* get 15b addr */
wd = fpp_read_xr (op2 & 07); /* read xr */
if (ir & 00100) { /* inc? */
wd = fpp_read_xr (xrn); /* read xr */
if (op2 & 010) { /* inc? */
wd = (wd + 1) & 07777;
fpp_write_xr (op2 & 07, wd); /* ++xr */
fpp_write_xr (xrn, wd); /* ++xr */
}
if (wd != 0) /* xr != 0? */
fpp_fpc = ad; /* jump */
break;
}
case 011: /* FSUB */
ea = fpp_1wd_dir (ir);
fpp_read_op (ea, &x);
@ -591,7 +645,7 @@ do { /* repeat */
fpp_sta |= FPS_XXXM;
ea = fpp_1wd_dir (ir);
fpp_read_op (ea, &x);
if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */
fpp_add (&x, &fpp_ac, 0);
fpp_write_op (ea, &x); /* store result */
break;
@ -599,7 +653,7 @@ do { /* repeat */
fpp_sta |= FPS_XXXM;
ea = fpp_2wd_dir (ir);
fpp_read_op (ea, &x);
if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */
fpp_add (&x, &fpp_ac, 0);
fpp_write_op (ea, &x); /* store result */
break;
@ -607,7 +661,7 @@ do { /* repeat */
fpp_sta |= FPS_XXXM;
ea = fpp_indir (ir);
fpp_read_op (ea, &x);
if (!fpp_add (&x, &fpp_ac, 0)) /* no trap? */
fpp_add (&x, &fpp_ac, 0);
fpp_write_op (ea, &x); /* store result */
break;
@ -649,6 +703,7 @@ do { /* repeat */
fpp_sta = (fpp_sta | FPS_DP) & ~FPS_EP; /* set dp */
fpp_ac.fr[0] = (ea >> 12) & 07;
fpp_ac.fr[1] = ea & 07777;
fpp_opa = ea;
}
break;
@ -656,7 +711,7 @@ do { /* repeat */
fpp_sta |= FPS_XXXM;
ea = fpp_1wd_dir (ir);
fpp_read_op (ea, &x);
if (!fpp_mul (&x, &fpp_ac)) /* no trap? */
fpp_mul (&x, &fpp_ac);
fpp_write_op (ea, &x); /* store result */
break;
@ -664,7 +719,7 @@ do { /* repeat */
fpp_sta |= FPS_XXXM;
ea = fpp_2wd_dir (ir);
fpp_read_op (ea, &x);
if (!fpp_mul (&x, &fpp_ac)) /* no trap? */
fpp_mul (&x, &fpp_ac);
fpp_write_op (ea, &x); /* store result */
break;
@ -672,11 +727,16 @@ do { /* repeat */
fpp_sta |= FPS_XXXM;
ea = fpp_indir (ir);
fpp_read_op (ea, &x);
if (!fpp_mul (&x, &fpp_ac)) /* no trap? */
fpp_mul (&x, &fpp_ac);
fpp_write_op (ea, &x); /* store result */
break;
} /* end sw op+mode */
if (fpp_ssf) {
fpp_dump_apt (fpp_apta, FPS_HLTX); /* dump APT */
fpp_ssf = 0;
}
if (sim_interval)
sim_interval = sim_interval - 1;
} while ((sim_interval > 0) &&
@ -696,7 +756,11 @@ uint32 ad;
ad = fpp_bra + ((ir & 0177) * 3); /* base + 3*7b off */
if (fpp_sta & FPS_DP) /* dp? skip exp */
ad = ad + 1;
return ad & ADDRMASK;
ad = ad & ADDRMASK;
if (fpp_sta & FPS_DP)
fpp_opa = ad + 1;
else fpp_opa = ad + 2;
return ad;
}
uint32 fpp_2wd_dir (uint32 ir)
@ -709,13 +773,18 @@ return fpp_adxr (ir, ad); /* do indexing */
uint32 fpp_indir (uint32 ir)
{
uint32 ad, iad, wd1, wd2;
uint32 ad, wd1, wd2;
ad = fpp_bra + ((ir & 07) * 3); /* base + 3*3b off */
iad = fpp_adxr (ir, ad); /* do indexing */
wd1 = fpp_read (iad + 1); /* read wds 2,3 */
wd2 = fpp_read (iad + 2);
return ((wd1 & 07) << 12) | wd2; /* return addr */
wd1 = fpp_read (ad + 1); /* bp+off points to */
wd2 = fpp_read (ad + 2);
ad = ((wd1 & 07) << 12) | wd2; /* indirect ptr */
ad = fpp_adxr (ir, ad); /* do indexing */
if (fpp_sta & FPS_DP)
fpp_opa = ad + 1;
else fpp_opa = ad + 2;
return ad;
}
uint32 fpp_ad15 (uint32 hi)
@ -738,8 +807,10 @@ if (ir & 0100) { /* increment? */
fpp_write_xr (xr, wd);
}
if (xr != 0) { /* indexed? */
if (fpp_sta & FPS_EP) wd = wd * 6; /* scale by len */
else if (fpp_sta & FPS_DP) wd = wd * 2;
if (fpp_sta & FPS_EP)
wd = wd * 6; /* scale by len */
else if (fpp_sta & FPS_DP)
wd = wd * 2;
else wd = wd * 3;
return (base_ad + wd) & ADDRMASK; /* return index */
}
@ -748,22 +819,28 @@ else return base_ad & ADDRMASK; /* return addr */
/* Computation routines */
/* Fraction/floating add - return true if overflow */
/* Fraction/floating add */
t_bool fpp_add (FPN *a, FPN *b, uint32 sub)
void fpp_add (FPN *a, FPN *b, uint32 sub)
{
FPN x, y, z;
uint32 ediff, c;
uint32 c, ediff;
fpp_zcopy (&x, a); /* copy opnds */
fpp_zcopy (&y, b);
if (sub) /* subtract? */
fpp_fr_neg (y.fr, EXACT); /* neg B, exact */
if (fpp_sta & FPS_DP) { /* dp? */
fpp_fr_add (z.fr, x.fr, y.fr); /* z = a + b */
if ((~x.fr[0] ^ y.fr[0]) & (x.fr[0] ^ z.fr[0]) & FPN_FRSIGN) {
uint32 cout = fpp_fr_add (z.fr, x.fr, y.fr, EXTEND);/* z = a + b */
uint32 zsign = z.fr[0] & FPN_FRSIGN;
cout = (cout? 04000: 0); /* make sign bit */
/* overflow is indicated when signs are equal and overflow does not
match the result sign bit */
fpp_copy (a, &z); /* result is z */
if (!((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) && (cout != zsign)) {
fpp_copy (a, &z); /* copy out result */
fpp_dump_apt (fpp_apta, FPS_IOVX); /* int ovf? */
return TRUE;
return;
}
}
else { /* fp or ep */
@ -778,11 +855,11 @@ else { /* fp or ep */
y = z;
}
ediff = x.exp - y.exp; /* exp diff */
if (ediff <= (uint32) ((fpp_sta & FPS_EP)? 59: 24)) { /* any add? */
z.exp = x.exp; /* result exp */
if (ediff <= (fpp_sta & FPS_EP)? 59: 24) { /* any add? */
if (ediff != 0) /* any align? */
fpp_fr_algn (y.fr, ediff, EXTEND); /* align, 60b */
c = fpp_fr_add (z.fr, x.fr, y.fr); /* add fractions */
c = fpp_fr_add (z.fr, x.fr, y.fr, EXTEND); /* add fractions */
if ((((x.fr[0] ^ y.fr[0]) & FPN_FRSIGN) == 0) && /* same signs? */
(c || /* carry out? */
((~x.fr[0] & z.fr[0] & FPN_FRSIGN)))) { /* + to - change? */
@ -790,57 +867,66 @@ else { /* fp or ep */
z.exp = z.exp + 1; /* incr exp */
} /* end same signs */
} /* end in range */
else z = x; /* ovrshift */
} /* end ops != 0 */
if (fpp_norm (&z, EXTEND)) /* norm, !exact? */
fpp_round (&z); /* round */
if (fpp_test_xp (&z)) /* ovf, unf? */
return TRUE;
fpp_copy (a, &z); /* copy out */
fpp_test_xp (&z); /* ovf, unf? */
} /* end else */
fpp_copy (a, &z); /* result is z */
return FALSE;
return;
}
/* Fraction/floating multiply - return true if overflow */
/* Fraction/floating multiply */
t_bool fpp_mul (FPN *a, FPN *b)
void fpp_mul (FPN *a, FPN *b)
{
FPN x, y, z;
fpp_zcopy (&x, a); /* copy opnds */
fpp_zcopy (&y, b);
if ((fpp_fr_test(y.fr, 0, EXACT-1) == 0) && (y.fr[EXACT-1] < 2)) {
y.exp = 0;
y.fr[EXACT-1] = 0;
}
if (fpp_sta & FPS_DP) /* dp? */
fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */
fpp_fr_mul (z.fr, x.fr, y.fr, TRUE); /* mult frac */
else { /* fp or ep */
fpp_norm (&x, EXACT);
fpp_norm (&y, EXACT);
z.exp = x.exp + y.exp; /* add exp */
fpp_fr_mul (z.fr, x.fr, y.fr); /* mult frac */
fpp_fr_mul (z.fr, x.fr, y.fr, TRUE); /* mult frac */
if (fpp_norm (&z, EXTEND)) /* norm, !exact? */
fpp_round (&z); /* round */
if (fpp_test_xp (&z)) /* ovf, unf? */
return TRUE;
fpp_copy (a, &z);
if (z.exp > 2047)
fpp_dump_apt (fpp_apta, FPS_FOVX); /* trap */
return;
}
fpp_copy (a, &z); /* result is z */
return FALSE;
return;
}
/* Fraction/floating divide - return true if div by zero or overflow */
/* Fraction/floating divide */
t_bool fpp_div (FPN *a, FPN *b)
void fpp_div (FPN *a, FPN *b)
{
FPN x, y, z;
if (fpp_fr_test (b->fr, 0, EXACT) == 0) { /* divisor 0? */
fpp_dump_apt (fpp_apta, FPS_DVZX); /* error */
return TRUE;
return;
}
if (fpp_fr_test (a->fr, 0, EXACT) == 0) /* dividend 0? */
return FALSE; /* quotient is 0 */
return; /* quotient is 0 */
fpp_zcopy (&x, a); /* copy opnds */
fpp_zcopy (&y, b);
if (fpp_sta & FPS_DP) { /* dp? */
if (fpp_fr_div (z.fr, x.fr, y.fr)) { /* fr div, ovflo? */
fpp_dump_apt (fpp_apta, FPS_IOVX); /* error */
return TRUE;
return;
}
fpp_copy (a, &z); /* result is z */
}
else { /* fp or ep */
fpp_norm (&y, EXACT); /* norm divisor */
@ -856,11 +942,15 @@ else { /* fp or ep */
}
if (fpp_norm (&z, EXTEND)) /* norm, !exact? */
fpp_round (&z); /* round */
if (fpp_test_xp (&z)) /* ovf, unf? */
return TRUE;
fpp_copy (a, &z);
if (z.exp > 2048) { /* underflow? */
if (fpp_cmd & FPC_UNFX) { /* trap? */
fpp_dump_apt (fpp_apta, FPS_UNF);
return;
}
fpp_copy (a, &z); /* result is z */
return FALSE;
}
}
return;
}
/* Integer multiply - returns true if overflow */
@ -872,15 +962,17 @@ FPN x, y, z;
fpp_zcopy (&x, a); /* copy args */
fpp_zcopy (&y, b);
fpp_fr_mul (z.fr, x.fr, y.fr); /* mult fracs */
fpp_fr_mul (z.fr, x.fr, y.fr, FALSE); /* mult fracs */
a->fr[0] = z.fr[1]; /* low 24b */
a->fr[1] = z.fr[2];
if ((a->fr[0] == 0) && (a->fr[1] == 0)) /* fpp zeroes exp */
a->exp = 0; /* even in dp mode */
sext = (z.fr[2] & FPN_FRSIGN)? 07777: 0;
if (((z.fr[0] | z.fr[1] | sext) != 0) && /* hi 25b == 0 */
((z.fr[0] & z.fr[1] & sext) != 07777)) { /* or 777777774? */
fpp_dump_apt (fpp_apta, FPS_IOVX);
return TRUE;
}
a->fr[0] = z.fr[2]; /* low 24b */
a->fr[1] = z.fr[3];
return FALSE;
}
@ -926,7 +1018,7 @@ if (fpp_fr_test (a->fr, 0, cnt) == 0) { /* zero? */
return FALSE; /* don't round */
}
while (((a->fr[0] == 0) && !(a->fr[1] & 04000)) || /* lead 13b same? */
((a->fr[0] = 07777) && (a->fr[1] & 04000))) {
((a->fr[0] == 07777) && (a->fr[1] & 04000))) {
fpp_fr_lsh12 (a->fr, cnt); /* move word */
a->exp = a->exp - 12;
}
@ -967,6 +1059,8 @@ for (i = 0; i < FPN_NFR_EP; i++) {
a->fr[i] = b->fr[i];
else a->fr[i] = 0;
}
a->fr[i++] = 0;
a->fr[i] = 0;
return;
}
@ -979,9 +1073,8 @@ if (a->exp > 2047) { /* overflow? */
return TRUE;
}
if (a->exp < -2048) { /* underflow? */
fpp_sta |= FPS_UNF; /* set flag */
if (fpp_sta & FPS_UNFX) { /* trap? */
fpp_dump_apt (fpp_apta, FPS_UNFX);
if (fpp_cmd & FPC_UNFX) { /* trap? */
fpp_dump_apt (fpp_apta, FPS_UNF);
return TRUE;
}
fpp_copy (a, &fpp_zero); /* flush to 0 */
@ -1015,13 +1108,14 @@ return;
/* N-precision integer routines */
/* Fraction add/sub - always carried out to 60b */
/* Fraction add/sub */
uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b, uint32 cnt)
uint32 fpp_fr_add (uint32 *c, uint32 *a, uint32 *b)
{
uint32 i, cin;
for (i = FPN_NFR_EP, cin = 0; i > 0; i--) {
for (i = cnt, cin = 0; i > 0; i--) {
c[i - 1] = a[i - 1] + b[i - 1] + cin;
cin = (c[i - 1] >> 12) & 1;
c[i - 1] = c[i - 1] & 07777;
@ -1029,11 +1123,11 @@ for (i = FPN_NFR_EP, cin = 0; i > 0; i--) {
return cin;
}
void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b)
void fpp_fr_sub (uint32 *c, uint32 *a, uint32 *b, uint32 cnt)
{
uint32 i, cin;
for (i = FPN_NFR_EP, cin = 0; i > 0; i--) {
for (i = cnt, cin = 0; i > 0; i--) {
c[i - 1] = a[i - 1] - b[i - 1] - cin;
cin = (c[i - 1] >> 12) & 1;
c[i - 1] = c[i - 1] & 07777;
@ -1062,25 +1156,48 @@ return;
If a-sign != c-sign, shift-in = result-sign
*/
void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b)
void fpp_fr_mul (uint32 *c, uint32 *a, uint32 *b, t_bool fix)
{
uint32 i, cnt, lo, c_old, cin;
uint32 i, cnt, lo, wc, fill, b_sign;
fpp_fr_fill (c, 0, EXTEND); /* clr answer */
b_sign = b[0] & FPN_FRSIGN; /* remember b's sign */
fpp_fr_fill (c, 0, FPN_NFR_MDS); /* clr answer */
if (fpp_sta & FPS_EP) /* ep? */
lo = FPN_NFR_EP - 1; /* test <59> */
else lo = FPN_NFR_FP - 1; /* sp, test <23> */
cnt = (lo + 1) * 12; /* # iterations */
for (i = 0; i < cnt; i++) { /* loop thru mpcd */
c_old = c[0];
if (b[lo] & 1) /* mpcd bit set? */
fpp_fr_add (c, a, c); /* add mpyr */
cin = (((a[0] ^ c_old) & FPN_FRSIGN)? c[0]: a[0]) & FPN_FRSIGN;
fpp_fr_rsh1 (c, cin, EXTEND); /* shift answer */
fpp_fr_rsh1 (b, 0, EXACT); /* shift mpcd */
lo = FPN_NFR_EP; /* low order mpyr word */
else
lo = FPN_NFR_FP; /* low order mpyr word */
if (fix)
fpp_fr_algn (a, 12, FPN_NFR_MDS + 1); /* fill left with sign */
wc = 2; /* 3 words at start */
fill = 0;
cnt = lo * 12; /* total steps */
for (i = 0; i < cnt; i++) {
if ((i % 12) == 0) {
wc++; /* do another word */
lo--; /* and next mpyr word */
fpp_fr_algn (c, 24, wc + 1);
c[wc] = 0;
c[0] = c[1] = fill; /* propagate sign */
}
if (a[0] & FPN_FRSIGN) /* mpyr negative? */
fpp_fr_sub (c, c, a); /* adjust result */
if (b[lo] & FPN_FRSIGN) /* mpyr bit set? */
fpp_fr_add(c, a, c, wc);
fill = ((c[0] & FPN_FRSIGN) ? 07777 : 0); /* remember sign */
fpp_fr_lsh1 (c, wc); /* shift the result */
fpp_fr_lsh1 (b + lo, 1); /* shift mpcd */
}
if (!fix) /* imul shifts result */
fpp_fr_rsh1 (c, c[0] & FPN_FRSIGN, EXACT + 1); /* result is 1 wd right */
if (b_sign) { /* if mpyr was negative */
if (fix)
fpp_fr_lsh12 (a, FPN_NFR_MDS+1); /* restore a */
fpp_fr_sub (c, c, a, EXACT); /* adjust result */
fpp_fr_sub (c, c, a, EXACT);
}
return;
}
@ -1088,29 +1205,35 @@ return;
t_bool fpp_fr_div (uint32 *c, uint32 *a, uint32 *b)
{
uint32 i, old_c, lo, cnt, sign;
uint32 i, old_c, lo, cnt, sign, b_sign, addsub, limit;
/* Number of words processed by each divide step */
static uint32 limits[7] = {6, 6, 5, 4, 3, 3, 2};
fpp_fr_fill (c, 0, EXTEND); /* clr answer */
fpp_fr_fill (c, 0, FPN_NFR_MDS); /* clr answer */
sign = (a[0] ^ b[0]) & FPN_FRSIGN; /* sign of result */
b_sign = (b[0] & FPN_FRSIGN);
if (a[0] & FPN_FRSIGN) /* |a| */
fpp_fr_neg (a, EXACT);
if (b[0] & FPN_FRSIGN); /* |b| */
fpp_fr_neg (b, EXACT);
if (fpp_sta & FPS_EP) /* ep? 5 words */
if (fpp_sta & FPS_EP) /* ep? 6 words */
lo = FPN_NFR_EP-1;
else lo = FPN_NFR_FP; /* fp, dp? 3 words */
else lo = FPN_NFR_FP-1; /* fp, dp? 3 words */
cnt = (lo + 1) * 12;
addsub = 04000; /* setup first op */
for (i = 0; i < cnt; i++) { /* loop */
fpp_fr_lsh1 (c, EXTEND); /* shift quotient */
if (fpp_fr_cmp (a, b, EXTEND) >= 0) { /* sub work? */
fpp_fr_sub (a, a, b); /* divd - divr */
if (a[0] & FPN_FRSIGN) /* sign flip? */
return TRUE; /* no, overflow */
limit = limits[i / 12]; /* how many wds this time */
fpp_fr_lsh1 (c, FPN_NFR_MDS); /* shift quotient */
if (addsub ^ b_sign) /* diff signs, subtr */
fpp_fr_sub (a, a, b, limit); /* divd - divr */
else
fpp_fr_add (a, a, b, limit); /* restore */
if (!(a[0] & FPN_FRSIGN)) {
c[lo] |= 1; /* set quo bit */
addsub = 04000; /* sign for nxt loop */
}
fpp_fr_lsh1 (a, EXTEND); /* shift dividend */
else addsub = 0;
fpp_fr_lsh1 (a, limit); /* shift dividend */
}
old_c = c[0]; /* save hi quo */
old_c = c[0]; /* save ho quo */
if (sign) /* expect neg ans? */
fpp_fr_neg (c, EXTEND); /* -quo */
if (old_c & FPN_FRSIGN) /* sign set before */
@ -1126,7 +1249,7 @@ uint32 i, cin;
for (i = cnt, cin = 1; i > 0; i--) {
a[i - 1] = (~a[i - 1] + cin) & 07777;
cin = (a[i - 1] == 0);
cin = (cin != 0 && a[i - 1] == 0);
}
return cin;
}
@ -1244,7 +1367,7 @@ if (sc >= (cnt * 12)) { /* out of range? */
return;
}
while (sc >= 12) {
for (i = cnt - 1; i > 0; i++)
for (i = cnt - 1; i > 0; i--)
a[i] = a[i - 1];
a[0] = sign;
sc = sc - 12;
@ -1263,7 +1386,6 @@ void fpp_read_op (uint32 ea, FPN *a)
{
uint32 i;
fpp_opa = ea;
if (!(fpp_sta & FPS_DP)) {
a->exp = fpp_read (ea++);
a->exp = SEXT12 (a->exp);
@ -1277,7 +1399,7 @@ void fpp_write_op (uint32 ea, FPN *a)
{
uint32 i;
fpp_opa = ea;
fpp_opa = ea + 2;
if (!(fpp_sta & FPS_DP))
fpp_write (ea++, a->exp);
for (i = 0; i < EXACT; i++)
@ -1328,7 +1450,7 @@ fpp_fpc = ((wd0 & 07) << 12) | apt_read (ad++);
if (FPC_GETFAST (fpp_cmd) != 017) {
fpp_xra = ((wd0 & 00070) << 9) | apt_read (ad++);
fpp_bra = ((wd0 & 00700) << 6) | apt_read (ad++);
ad++;
fpp_opa = ((wd0 & 07000) << 3) | apt_read (ad++);
fpp_ac.exp = apt_read (ad++);
for (i = 0; i < EXACT; i++)
fpp_ac.fr[i] = apt_read (ad++);
@ -1370,9 +1492,8 @@ return;
t_stat fpp_reset (DEVICE *dptr)
{
sim_cancel (&fpp_unit);
fpp_sta = 0;
fpp_cmd = 0;
fpp_flag = 0;
fpp_last_lockbit = 0;
int_req &= ~INT_FPP;
if (sim_switches & SWMASK ('P')) {
fpp_apta = 0;
@ -1382,6 +1503,14 @@ if (sim_switches & SWMASK ('P')) {
fpp_xra = 0;
fpp_opa = 0;
fpp_ac = fpp_zero;
fpp_ssf = 0;
fpp_sta = 0;
fpp_cmd = 0;
}
else {
fpp_sta &= ~(FPS_DP|FPS_EP|FPS_TRPX|FPS_DVZX|FPS_IOVX|FPS_FOVX|FPS_UNF);
fpp_cmd &= (FPC_DP|FPC_UNFX|FPC_IE);
}
return SCPE_OK;
}

View file

@ -1,6 +1,6 @@
/* pdp8_sys.c: PDP-8 simulator interface
Copyright (c) 1993-2008, Robert M Supnik
Copyright (c) 1993-2009, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -23,6 +23,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from Robert M Supnik.
24-Mar-09 RMS Added link to FPP
24-Jun-08 RMS Fixed bug in new rim loader (found by Don North)
24-May-08 RMS Fixed signed/unsigned declaration inconsistency
03-Sep-07 RMS Added FPP8 support
@ -52,6 +53,7 @@
extern DEVICE cpu_dev;
extern UNIT cpu_unit;
extern DEVICE tsc_dev;
extern DEVICE fpp_dev;
extern DEVICE ptr_dev, ptp_dev;
extern DEVICE tti_dev, tto_dev;
extern DEVICE clk_dev, lpt_dev;
@ -91,6 +93,7 @@ int32 sim_emax = 4;
DEVICE *sim_devices[] = {
&cpu_dev,
&tsc_dev,
&fpp_dev,
&clk_dev,
&ptr_dev,
&ptp_dev,

View file

@ -1,6 +1,6 @@
/* vax_cpu.c: VAX CPU
Copyright (c) 1998-2008, Robert M Supnik
Copyright (c) 1998-2010, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -25,6 +25,8 @@
cpu VAX central processor
24-Apr-10 RMS Added OLDVMS idle timer option
Fixed bug in SET CPU IDLE
21-May-08 RMS Removed inline support
28-May-08 RMS Inlined instruction prefetch, physical memory routines
13-Aug-07 RMS Fixed bug in read access g-format indexed specifiers
@ -173,6 +175,8 @@
#define UNIT_CONH (1u << UNIT_V_CONH)
#define UNIT_MSIZE (1u << UNIT_V_MSIZE)
#define GET_CUR acc = ACC_MASK (PSL_GETCUR (PSL))
#define VAX_IDLE_DFLT 1000
#define OLD_IDLE_DFLT 200
#define OPND_SIZE 16
#define INST_SIZE 52
@ -259,7 +263,7 @@ int32 ibufl, ibufh; /* prefetch buf */
int32 ibcnt, ppc; /* prefetch ctl */
uint32 cpu_idle_ipl_mask = 0x8; /* idle if on IPL 3 */
uint32 cpu_idle_type = 1; /* default to VMS */
int32 cpu_idle_wait = 1000; /* for these cycles */
int32 cpu_idle_wait = VAX_IDLE_DFLT; /* for these cycles */
jmp_buf save_env;
REG *pcq_r = NULL; /* PC queue reg ptr */
int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */
@ -3377,15 +3381,17 @@ return more;
struct os_idle {
char *name;
uint32 mask;
int32 value;
};
static struct os_idle os_tab[] = {
{ "VMS", 0x8 },
{ "NETBSD", 0x2 },
{ "ULTRIX", 0x2 },
{ "OPENBSD", 0x1 },
{ "32V", 0x1 },
{ NULL, 0 }
{ "VMS", 0x8, VAX_IDLE_DFLT },
{ "NETBSD", 0x2, VAX_IDLE_DFLT },
{ "ULTRIX", 0x2, VAX_IDLE_DFLT },
{ "OPENBSD", 0x1, VAX_IDLE_DFLT },
{ "32V", 0x1, VAX_IDLE_DFLT },
{ "OLDVMS", 0xB, OLD_IDLE_DFLT },
{ NULL, 0, 0 }
};
/* Set and show idle */
@ -3399,7 +3405,8 @@ if (cptr != NULL) {
if (strcmp (os_tab[i].name, cptr) == 0) {
cpu_idle_type = i + 1;
cpu_idle_ipl_mask = os_tab[i].mask;
return sim_set_idle (uptr, val, cptr, desc);
cpu_idle_wait = os_tab[i].value;
return sim_set_idle (uptr, val, NULL, desc);
}
}
return SCPE_ARG;

View file

@ -2,6 +2,7 @@
# Written By: Robert Alan Byer / byer@mail.ourservers.net
# Modified By: Mark Pizzolato / mark@infocomm.com
# Norman Lastovica / norman.lastovica@oracle.com
# Camiel Vanderhoeven / camiel@camicom.com
#
# This MMS/MMK build script is used to compile the various simulators in
# the SIMH package for OpenVMS using DEC C v6.0-001(AXP), v6.5-001(AXP),
@ -182,21 +183,24 @@ ALTAIR_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIR_DIR))/DEF=($(CC_DEFS))
# MITS Altair Z80 Simulator Definitions.
#
ALTAIRZ80_DIR = SYS$DISK:[.ALTAIRZ80]
ALTAIRZ80_LIB = $(LIB_DIR)ALTAIRZ80-$(ARCH).OLB
ALTAIRZ80_SOURCE = $(ALTAIRZ80_DIR)/ALTAIRZ80_CPU.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_CPU_NOMMU.C,\
$(ALTAIRZ80_DIR)/ALTAIRZ80_DSK.C,$(ALTAIRZ80_DIR)/DISASM.C,\
$(ALTAIRZ80_DIR)/ALTAIRZ80_SIO.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_SYS.C,\
$(ALTAIRZ80_DIR)/ALTAIRZ80_HDSK.C,$(ALTAIRZ80_DIR)/ALTAIRZ80_NET.C,\
$(ALTAIRZ80_DIR)/FLASHWRITER2.C,$(ALTAIRZ80_DIR)/I86_DECODE.C,\
$(ALTAIRZ80_DIR)/I86_OPS.C,$(ALTAIRZ80_DIR)/I86_PRIM_OPS.C,\
$(ALTAIRZ80_DIR)/I8272.C,$(ALTAIRZ80_DIR)/INSNSA.C,$(ALTAIRZ80_DIR)/INSNSD.C,\
$(ALTAIRZ80_DIR)/MFDC.C,$(ALTAIRZ80_DIR)/N8VEM.C,$(ALTAIRZ80_DIR)/VFDHD.C,\
$(ALTAIRZ80_DIR)/S100_DISK1A.C,$(ALTAIRZ80_DIR)/S100_DISK2.C,\
$(ALTAIRZ80_DIR)/S100_FIF.C,$(ALTAIRZ80_DIR)/S100_MDRIVEH.C,\
$(ALTAIRZ80_DIR)/S100_MDSAD.C,$(ALTAIRZ80_DIR)/S100_SELCHAN.C,\
$(ALTAIRZ80_DIR)/S100_SS1.C,$(ALTAIRZ80_DIR)/S100_64FDC.C,\
$(ALTAIRZ80_DIR)/S100_SCP300F.C,$(ALTAIRZ80_DIR)/SIM_IMD.C,\
$(ALTAIRZ80_DIR)/WD179X.C
ALTAIRZ80_LIB1 = $(LIB_DIR)ALTAIRZ80L1-$(ARCH).OLB
ALTAIRZ80_SOURCE1 = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.C,$(ALTAIRZ80_DIR)ALTAIRZ80_CPU_NOMMU.C,\
$(ALTAIRZ80_DIR)ALTAIRZ80_DSK.C,$(ALTAIRZ80_DIR)DISASM.C,\
$(ALTAIRZ80_DIR)ALTAIRZ80_SIO.C,$(ALTAIRZ80_DIR)ALTAIRZ80_SYS.C,\
$(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C,$(ALTAIRZ80_DIR)ALTAIRZ80_NET.C,\
$(ALTAIRZ80_DIR)FLASHWRITER2.C,$(ALTAIRZ80_DIR)I86_DECODE.C,\
$(ALTAIRZ80_DIR)I86_OPS.C,$(ALTAIRZ80_DIR)I86_PRIM_OPS.C,\
$(ALTAIRZ80_DIR)I8272.C,$(ALTAIRZ80_DIR)INSNSA.C,$(ALTAIRZ80_DIR)INSNSD.C,\
$(ALTAIRZ80_DIR)MFDC.C,$(ALTAIRZ80_DIR)N8VEM.C,$(ALTAIRZ80_DIR)VFDHD.C
ALTAIRZ80_LIB2 = $(LIB_DIR)ALTAIRZ80L2-$(ARCH).OLB
ALTAIRZ80_SOURCE2 = $(ALTAIRZ80_DIR)S100_DISK1A.C,$(ALTAIRZ80_DIR)S100_DISK2.C,\
$(ALTAIRZ80_DIR)S100_FIF.C,$(ALTAIRZ80_DIR)S100_MDRIVEH.C,\
$(ALTAIRZ80_DIR)S100_MDSAD.C,$(ALTAIRZ80_DIR)S100_SELCHAN.C,\
$(ALTAIRZ80_DIR)S100_SS1.C,$(ALTAIRZ80_DIR)S100_64FDC.C,\
$(ALTAIRZ80_DIR)S100_SCP300F.C,$(ALTAIRZ80_DIR)SIM_IMD.C,\
$(ALTAIRZ80_DIR)WD179X.C,$(ALTAIRZ80_DIR)S100_DISK3.C,\
$(ALTAIRZ80_DIR)S100_ADCS6.C,$(ALTAIRZ80_DIR)S100_HDC1001.C,\
$(ALTAIRZ80_DIR)S100_IF3.C
ALTAIRZ80_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIRZ80_DIR))/DEF=($(CC_DEFS))
#
@ -256,8 +260,8 @@ H316_OPTIONS = /INCL=($(SIMH_DIR),$(H316_DIR))/DEF=($(CC_DEFS))
# Hewlett-Packard HP-2100 Simulator Definitions.
#
HP2100_DIR = SYS$DISK:[.HP2100]
HP2100_LIB = $(LIB_DIR)HP2100-$(ARCH).OLB
HP2100_SOURCE = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\
HP2100_LIB1 = $(LIB_DIR)HP2100L1-$(ARCH).OLB
HP2100_SOURCE1 = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\
$(HP2100_DIR)HP2100_DQ.C,$(HP2100_DIR)HP2100_DR.C,\
$(HP2100_DIR)HP2100_LPS.C,$(HP2100_DIR)HP2100_MS.C,\
$(HP2100_DIR)HP2100_MT.C,$(HP2100_DIR)HP2100_MUX.C,\
@ -267,8 +271,9 @@ HP2100_SOURCE = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\
$(HP2100_DIR)HP2100_CPU0.C,$(HP2100_DIR)HP2100_CPU1.C,\
$(HP2100_DIR)HP2100_CPU2.C,$(HP2100_DIR)HP2100_CPU3.C,\
$(HP2100_DIR)HP2100_CPU4.C,$(HP2100_DIR)HP2100_CPU5.C,\
$(HP2100_DIR)HP2100_CPU6.C,$(HP2100_DIR)HP2100_CPU7.C,\
$(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C,\
$(HP2100_DIR)HP2100_CPU6.C,$(HP2100_DIR)HP2100_CPU7.C
HP2100_LIB2 = $(LIB_DIR)HP2100L2-$(ARCH).OLB
HP2100_SOURCE2 = $(HP2100_DIR)HP2100_FP1.C,$(HP2100_DIR)HP2100_BACI.C,\
$(HP2100_DIR)HP2100_MPX.C,$(HP2100_DIR)HP2100_PIF.C
.IF ALPHA_OR_IA64
HP2100_OPTIONS = /INCL=($(SIMH_DIR),$(HP2100_DIR))\
@ -362,7 +367,7 @@ PDP8_SOURCE = $(PDP8_DIR)PDP8_CPU.C,$(PDP8_DIR)PDP8_CLK.C,\
$(PDP8_DIR)PDP8_SYS.C,$(PDP8_DIR)PDP8_TT.C,\
$(PDP8_DIR)PDP8_TTX.C,$(PDP8_DIR)PDP8_RL.C,\
$(PDP8_DIR)PDP8_TSC.C,$(PDP8_DIR)PDP8_TD.C,\
$(PDP8_DIR)PDP8_CT.C
$(PDP8_DIR)PDP8_CT.C,$(PDP8_DIR)PDP8_FPP.C
PDP8_OPTIONS = /INCL=($(SIMH_DIR),$(PDP8_DIR))/DEF=($(CC_DEFS))
#
@ -509,14 +514,14 @@ I7094_OPTIONS = /INCL=($(SIMH_DIR),$(I7094_DIR))/DEF=($(CC_DEFS))
ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI LGP H316 HP2100 I1401 I1620 IBM1130 ID16 \
ID32 NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 VAX VAX780 SDS \
I7094
@CONTINUE
$! No further actions necessary
.ELSE
#
# Else We Are On VAX And Build Everything EXCEPT the 64b simulators
#
ALL : ALTAIR ALTAIRZ80 GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \
NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 VAX VAX780 SDS
@CONTINUE
$! No further actions necessary
.ENDIF
CLEAN :
@ -559,9 +564,20 @@ $(ALTAIR_LIB) : $(ALTAIR_SOURCE)
$ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
$(ALTAIRZ80_LIB) : $(ALTAIRZ80_SOURCE)
$(ALTAIRZ80_LIB1) : $(ALTAIRZ80_SOURCE1)
$!
$! Building The $(ALTAIRZ80_LIB) Library.
$! Building The $(ALTAIRZ80_LIB1) Library.
$!
$ $(CC)$(ALTAIRZ80_OPTIONS) -
/OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST)
$ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN -
LIBRARY/CREATE $(MMS$TARGET)
$ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
$(ALTAIRZ80_LIB2) : $(ALTAIRZ80_SOURCE2)
$!
$! Building The $(ALTAIRZ80_LIB2) Library.
$!
$ $(CC)$(ALTAIRZ80_OPTIONS) -
/OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST)
@ -628,9 +644,20 @@ $(H316_LIB) : $(H316_SOURCE)
$ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
$(HP2100_LIB) : $(HP2100_SOURCE)
$(HP2100_LIB1) : $(HP2100_SOURCE1)
$!
$! Building The $(HP2100_LIB) Library.
$! Building The $(HP2100_LIB1) Library.
$!
$ $(CC)$(HP2100_OPTIONS) -
/OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST)
$ IF (F$SEARCH("$(MMS$TARGET)").EQS."") THEN -
LIBRARY/CREATE $(MMS$TARGET)
$ LIBRARY/REPLACE $(MMS$TARGET) $(BLD_DIR)*.OBJ
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
$(HP2100_LIB2) : $(HP2100_SOURCE2)
$!
$! Building The $(HP2100_LIB2) Library.
$!
$ $(CC)$(HP2100_OPTIONS) -
/OBJ=$(BLD_DIR) $(MMS$CHANGED_LIST)
@ -918,13 +945,14 @@ ALTAIR : $(SIMH_LIB) $(ALTAIR_LIB)
$(BLD_DIR)SCP.OBJ,$(ALTAIR_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB)
ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB1) $(ALTAIRZ80_LIB2)
$!
$! Building The $(BIN_DIR)ALTAIRZ80-$(ARCH).EXE Simulator.
$!
$ $(CC)$(ALTAIRZ80_OPTIONS)/OBJ=$(BLD_DIR) SCP.C
$ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ALTAIRZ80-$(ARCH).EXE -
$(BLD_DIR)SCP.OBJ,$(ALTAIRZ80_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY
$(BLD_DIR)SCP.OBJ,$(ALTAIRZ80_LIB1)/LIBRARY, -
$(ALTAIRZ80_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
#
@ -976,13 +1004,14 @@ H316 : $(SIMH_LIB) $(H316_LIB)
$(BLD_DIR)SCP.OBJ,$(H316_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
HP2100 : $(SIMH_LIB) $(HP2100_LIB)
HP2100 : $(SIMH_LIB) $(HP2100_LIB1) $(HP2100_LIB2)
$!
$! Building The $(BIN_DIR)HP2100-$(ARCH).EXE Simulator.
$!
$ $(CC)$(HP2100_OPTIONS)/OBJ=$(BLD_DIR) SCP.C
$ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)HP2100-$(ARCH).EXE -
$(BLD_DIR)SCP.OBJ,$(HP2100_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY
$(BLD_DIR)SCP.OBJ,$(HP2100_LIB1)/LIBRARY, -
$(HP2100_LIB2)/LIBRARY,$(SIMH_LIB)/LIBRARY
$ DELETE/NOLOG/NOCONFIRM $(BLD_DIR)*.OBJ;*
I1401 : $(SIMH_LIB) $(I1401_LIB)

View file

@ -251,13 +251,19 @@ SDS = ${SDSD}/sds_cpu.c ${SDSD}/sds_drm.c ${SDSD}/sds_dsk.c ${SDSD}/sds_io.c \
${SDSD}/sds_stddev.c ${SDSD}/sds_sys.c
SDS_OPT = -I ${SDSD}
SWTPD = SWTP
SWTP = ${SWTPD}/swtp_cpu.c ${SWTPD}/swtp_dsk.c ${SWTPD}/swtp_sio.c \
${SWTPD}/swtp_sys.c
SWTP_OPT = -I ${SWTPD}
#
# Build everything
#
ALL = pdp1 pdp4 pdp7 pdp8 pdp9 pdp15 pdp11 pdp10 \
vax vax780 nova eclipse hp2100 i1401 i1620 s3 \
altair altairz80 gri i1620 i7094 ibm1130 id16 \
id32 sds lgp h316
id32 sds lgp h316 swtp
all : ${ALL}
@ -400,3 +406,8 @@ sds : ${BIN}sds${EXE}
${BIN}sds${EXE} : ${SDS} ${SIM}
${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ ${LDFLAGS}
swtp : ${BIN}swtp${EXE}
${BIN}swtp${EXE} : ${SWTP} ${SIM}
${CC} ${SWTP} ${SIM} ${SWTP_OPT} -o $@ ${LDFLAGS}

View file

@ -1,6 +1,6 @@
/* sim_rev.h: simulator revisions and current rev level
Copyright (c) 1993-2008, Robert M Supnik
Copyright (c) 1993-2010, Robert M Supnik
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -29,13 +29,45 @@
#define SIM_MAJOR 3
#define SIM_MINOR 8
#define SIM_PATCH 1
#define SIM_PATCH 2
#define SIM_DELTA 0
/* V3.8 revision history
patch date module(s) and fix(es)
2 tbd h316_cpu.c:
- fixed bugs in MPY, DIV introduced in 3.8-1
i1401_cd.c:
- fixed read stacker operation in column binary mode
- fixed punch stacker operation (from Van Snyder)
1401_cpu.c:
- revised divide algorithm (from Van Snyder)
i1401_mt.c:
- added no rewind option (from Van Snyder)
pdp11_rk.c:
- fixed bug in read header (from Walter F Mueller)
pdp11_rl.c:
- added debug support
pdp11_rq.c:
- added RD32 support
pdp8_fpp.c:
- many bug fixes (all from Rick Murphy); now functional
pdp8_sys.c:
- added link to FPP
vax_cpu.c:
- added OLDVMS idle timer option
- fixed bug in SET CPU IDLE
1 08-Feb-09 scp.c:
- revised RESTORE unit logic for consistency
- "detach_all" ignores error status returns if shutting down (from Dave Bryan)

BIN
swtp/6800boot.dsk Normal file

Binary file not shown.

BIN
swtp/6800work.dsk Normal file

Binary file not shown.

BIN
swtp/swtp Normal file

Binary file not shown.

100
swtp/swtp.txt Normal file
View file

@ -0,0 +1,100 @@
SWTP 6800 Emulator
=====================
1. Background.
The Southwest Technical Products (SWTP) SWTP 6800 was announced 1n the 1976 SWTP Catalog, which boasted you could buy and build this powerful computer kit for only $395. The kit consisted at that time of only the parts to build a case, power supply, mother board, CPU card, serial card with RS-232 or 20 ma loop interface, and memory card with 2048 *bytes* of static memory.
2. Hardware
We are simulating a fairly "loaded" SWTP 6800 from about 1978, with the following configuration:
device simulates
name(s)
CPU SWTP MP-A with Motorola 6080 CPU board, 62KB of RAM, 2K of EPROM with start boot ROM.
SIO SWTP MP-S Dual Serial Interface Board. Port 1 is assumed to be connected to a serial "glass TTY" that is your terminal running the Simulator.
PTR Second serial port of SIO is assumed to be connected to the paper tap reader/punch.
PTP Second serial port of SIO is assumed to be connected to the paper tap reader/punch.
DSK SWTP DC-4 Floppy Disk controller with up to four drives.
2.1 The CPU Card (MP-A)
We allow you to select memory sizes, but be aware that some sample software requires the full 32K (i.e. FLEX). We emulate the SWTP SWTBUG boot rom.
SET CPU ITRAP Causes the simulator to halt if an invalid 8080 Opcode is detected.
SET CPU NOITRAP Does not stop on an invalid Opcode. This is how the real 6800 operates.
SET CPU MTRAP Causes the simulator to halt if an invalid address is accessed.
SET CPU NOMTRAP Does not stop on invalid address access. This is how a real 6800 operates.
SET CPU 4K
SET CPU 8K
SET CPU 12K
SET CPU 16K
......
SET CPU 32K All these set various CPU memory configurations.
The 2K EPROM at the high end of memory is always present and will always boot.
SET CPU MA000 Enable 8 K bytes of memory at $A000-$BFFF. Otherwise, only 128 bytes re available at $A000.
SET CPU NOMA000 Enable only 128 bytes of memory at $A000.
The SWTBUG EPROM maps to both addresses $E000-E3FF and $FC00-FFFF.
The real 6800, on receiving a HLT (Halt) instruction, freezes the processor and only an interrupt or CPU hardware reset will restore it. The simulator is a lot nicer, it will halt but send you back to the simulator command line.
CPU Registers include the following:
name size comments
PC 16 Program Counter
A 8 Accumulator A
B 8 Accumulator B
IX 16 Index Register
C 1 Carry flag
Z 1 Zero Flag
H 1 Half-Carry flag
I 1 Interrupt flag
N 1 Negative flag
V 1 Overflao Flag
2.2 The Serial I/O Card (MP-S)
This simple programmed I/O device provides 2 serial ports to the outside world, which could be hardware jumpered to support RS-232 plugs or a TTY current loop interface. The standard I/O addresses assigned by SWTP was $8004-8005 for the first port, and $8006-8007 for the second. We follow this standard in the Simulator.
The simulator directs I/O to/from the first port to the screen. The second port reads from an attachable "tape reader" file on input, and writes to an attachable "punch file" on output. These files are considered a simple stream of 8-bit bytes.
2.3 The Floppy Disk controller (DC4)
The SWTP DC4 is a simple programmed I/O interface to the SWTP MF-68 5-inch dual floppy drive, which was basically a pair of Shugart SA-400s with a power supply and buffer board builtin. The controller supports neither interrupts nor DMA, so floppy access required the sustained attention of the CPU. The standard I/O addresses were $8018-801B, and we follow the standard. Details on controlling this hardware are in the swtp_dsk.c source file.
3. Sample Software
Running an SWTP 6800 in 1978 you would be running the FLEX Version 2.0 Operating System from Technical Systems Consultants, Inc.
3.1 CP/M Version 2.2
This version is a port of the standard FLEX Version 2.0 to the SWTP 6800.
To boot FLEX:
sim> set cpu hex
sim> set cpu itrap
sim> set cpu mtrap
sim> att dsk 6800boot.dsk
sim> att dsk1 6800work.dsk
sim> set cpu MA000
sim> set dsk1 rw
sim> go
$D ; Capital D causes SWTBUG to boot Flex
FLEX 2.0
DATE (MM,DD,YY)? 03,09,99 ; Must enter a date from last century!
+++ ;Flex prompt!

9
swtp/swtp6800 Normal file
View file

@ -0,0 +1,9 @@
reset
set cpu hex
set cpu itrap
set cpu mtrap
att dsk 6800boot.dsk
att dsk1 6800work.dsk
set cpu MA000
set dsk1 rw
g

2293
swtp/swtp_cpu.c Normal file

File diff suppressed because it is too large Load diff

46
swtp/swtp_defs.h Normal file
View file

@ -0,0 +1,46 @@
/* swtp_defs.h: SWTP 6800 simulator definitions
Copyright (c) 2005, 2007, William Beech
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of William A Beech shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from William A Beech.
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
*/
#include "../sim_defs.h" // simulator defs
/* Memory */
#define MAXMEMSIZE 65536 // max memory size
#define MEMSIZE (cpu_unit.capac)// actual memory size
#define ADDRMASK (MAXMEMSIZE - 1)// address mask
#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE)
/* Simulator stop codes */
#define STOP_RSRV 1 // must be 1
#define STOP_HALT 2 // HALT-really WAI
#define STOP_IBKPT 3 // breakpoint
#define STOP_OPCODE 4 // invalid opcode
#define STOP_MEMORY 5 // invalid memory address

506
swtp/swtp_dsk.c Normal file
View file

@ -0,0 +1,506 @@
/* swtp_dc4_dsk.c: SWTP DC-4 DISK Simulator
Copyright (c) 2005, William A. Beech
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
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.
Except as contained in this notice, the name of William A. Beech shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from William A. Beech.
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
The DC-4 is a 5-inch floppy controller which can control up
to 4 daisy-chained 5-inch floppy drives. The controller is based on
the Western Digital 1797 Floppy Disk Controller (FDC) chip. This
file only emulates the minimum DC-4 functionality to interface with
the virtual disk file.
The floppy controller is interfaced to the CPU by use of 5 memory
addreses. These are device numbers 5 and 6 (0x8014-0x801B).
Address Mode Function
------- ---- --------
0x8014 Read Returns FDC interrupt status
0x8014 Write Selects the drive/head/motor control
0x8018 Read Returns status of FDC
0x8018 Write FDC command register
0x8019 Read Returns FDC track register
0x8019 Write Set FDC track register
0x801A Read Returns FDC sector register
0x801A Write Set FDC sector register
0x801B Read Read data
0x801B Write Write data
Drive Select Read (0x8014):
+---+---+---+---+---+---+---+---+
| I | D | X | X | X | X | X | X |
+---+---+---+---+---+---+---+---+
I = Set indicates an interrupt request from the FDC pending.
D = DRQ pending - same as bit 1 of FDC status register.
Drive Select Write (0x8014):
+---+---+---+---+---+---+---+---+
| M | S | X | X | X | X | Device|
+---+---+---+---+---+---+---+---+
M = If this bit is 1, the one-shot is triggered/retriggered to
start/keep the motors on.
S = Side select. If set, side one is selected otherwise side zero
is selected.
X = not used
Device = value 0 thru 3, selects drive 0-3 to be controlled.
Drive Status Read (0x8018):
+---+---+---+---+---+---+---+---+
| R | P | H | S | C | L | D | B |
+---+---+---+---+---+---+---+---+
B - When 1, the controller is busy.
D - When 1, index mark detected (type I) or data request - read data
ready/write data empty (type II or III).
H - When 1, track 0 (type I) or lost data (type II or III).
C - When 1, crc error detected.
S - When 1, seek (type I) or RNF (type II or III) error.
H - When 1, head is currently loaded (type I) or record type/
write fault (type II or III).
P - When 1, indicates that diskette is write-protected.
R - When 1, drive is not ready.
Drive Control Write (0x8018) for type I commands:
+---+---+---+---+---+---+---+---+
| 0 | S2| S1| S0| H | V | R1| R0|
+---+---+---+---+---+---+---+---+
R0/R1 - Selects the step rate.
V - When 1, verify on destination track.
H - When 1, loads head to drive surface.
S0/S1/S2 = 000 - home.
001 - seek track in data register.
010 - step without updating track register.
011 - step and update track register.
100 - step in without updating track register.
101 - step in and update track register.
110 - step out without updating track register.
111 - step out and update track register.
Drive Control Write (0x8018) for type II commands:
+---+---+---+---+---+---+---+---+
| 1 | 0 | T | M | S | E | B | A |
+---+---+---+---+---+---+---+---+
A - Zero for read, 1 on write deleted data mark else data mark.
B - When 1, shifts sector length field definitions one place.
E - When, delay operation 15 ms, 0 no delay.
S - When 1, select side 1, 0 select side 0.
M - When 1, multiple records, 0 for single record.
T - When 1, write command, 0 for read.
Drive Control Write (0x8018) for type III commands:
+---+---+---+---+---+---+---+---+
| 1 | 1 | T0| T1| 0 | E | 0 | 0 |
+---+---+---+---+---+---+---+---+
E - When, delay operation 15 ms, 0 no delay.
T0/T1 - 00 - read address command.
10 - read track command.
11 - write track command.
Tracks are numbered from 0 up to one minus the last track in the 1797!
Track Register Read (0x8019):
+---+---+---+---+---+---+---+---+
| Track Number |
+---+---+---+---+---+---+---+---+
Reads the current 8-bit value from the track position.
Track Register Write (0x8019):
+---+---+---+---+---+---+---+---+
| Track Number |
+---+---+---+---+---+---+---+---+
Writes the 8-bit value to the track register.
Sectors are numbers from 1 up to the last sector in the 1797!
Sector Register Read (0x801A):
+---+---+---+---+---+---+---+---+
| Sector Number |
+---+---+---+---+---+---+---+---+
Reads the current 8-bit value from the sector position.
Sector Register Write (0x801A):
+---+---+---+---+---+---+---+---+
| Sector Number |
+---+---+---+---+---+---+---+---+
Writes the 8-bit value to the sector register.
Data Register Read (0x801B):
+---+---+---+---+---+---+---+---+
| Data |
+---+---+---+---+---+---+---+---+
Reads the current 8-bit value from the data register.
Data Register Write (0x801B):
+---+---+---+---+---+---+---+---+
| Data |
+---+---+---+---+---+---+---+---+
Writes the 8-bit value to the data register.
A FLEX disk is defined as follows:
Track Sector Use
0 1 Boot sector
0 2 Boot sector (cont)
0 3 Unused
0 4 System Identity Record (explained below)
0 5 Unused
0 6-last Directory - 10 entries/sector (explained below)
1 1 First available data sector
last-1 last Last available data sector
System Identity Record
Byte Use
0x10 Volume ID (8 bytes)
0x18 ???
0x19 ???
0x1A ???
0x1B Volume number (2 bytes)
0x1D First free sector (2 bytes)
0x1F Last track minus one (byte)
0x20 Last sector (byte)
0x21 Total sectors on disk (2 bytes)
0x23 Month (byte
0x24 Day (byte)
0x25 Year (byte)
0x26 Last track minus one (byte)
0x27 Last sector (byte)
*/
#include <stdio.h>
#include "swtp_defs.h"
#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */
#define UNIT_ENABLE (1 << UNIT_V_ENABLE)
/* emulate a SS FLEX disk with 72 sectors and 80 tracks */
#define NUM_DISK 4 /* standard 1797 maximum */
#define SECT_SIZE 256 /* standard FLEX sector */
#define NUM_SECT 72 /* sectors/track */
#define TRAK_SIZE (SECT_SIZE * NUM_SECT)
#define HEADS 1 /* handle as SS with twice the sectors */
#define NUM_CYL 80 /* maximum tracks */
#define DSK_SIZE (NUM_SECT * HEADS * NUM_CYL * SECT_SIZE)
/* 1797 status bits */
#define BUSY 0x01
#define DRQ 0x02
#define WRPROT 0x40
#define NOTRDY 0x80
/* debug prints */
#define DEBUG 0
/* prototypes */
t_stat dsk_svc (UNIT *uptr);
t_stat dsk_reset (DEVICE *dptr);
int32 fdcdrv(int32 io, int32 data);
int32 fdccmd(int32 io, int32 data);
int32 fdctrk(int32 io, int32 data);
int32 fdcsec(int32 io, int32 data);
int32 fdcdata(int32 io, int32 data);
/* Global data on status */
int32 cur_dsk = NUM_DISK; /* Currently selected drive */
int32 cur_trk[NUM_DISK] = {0, 0, 0, 0};
int32 cur_sec[NUM_DISK] = {0, 0, 0, 0};
int32 cur_byt[NUM_DISK] = {0, 0, 0, 0};
int32 cur_flg[NUM_DISK] = {NOTRDY, NOTRDY, NOTRDY, NOTRDY};
/* Variables */
uint8 dskbuf[SECT_SIZE]; /* Data Buffer */
UNIT *dptr = NULL; /* fileref to write dirty buffer to */
int32 fdcbyte;
int32 intrq = 0; /* interrupt request flag */
/* DC-4 Simh Device Data Structures */
UNIT dsk_unit[] = {
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) },
{ UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) } };
REG dsk_reg[] = {
{ HRDATA (DISK, cur_dsk, 4) },
{ NULL } };
MTAB dsk_mod[] = {
{ UNIT_ENABLE, UNIT_ENABLE, "RW", "RW", NULL },
{ UNIT_ENABLE, 0, "RO", "RO", NULL },
{ 0 } };
DEVICE dsk_dev = {
"DSK", dsk_unit, dsk_reg, dsk_mod,
NUM_DISK, 16, 16, 1, 16, 8,
NULL, NULL, &dsk_reset,
NULL, NULL, NULL };
/* service routines to handle simlulator functions */
/* service routine - actually gets char & places in buffer */
t_stat dsk_svc (UNIT *uptr)
{
return SCPE_OK;
}
/* Reset routine */
t_stat dsk_reset (DEVICE *dptr)
{
cur_dsk = 0;
return SCPE_OK;
}
/* I/O instruction handlers, called from the CPU module when an
memory read or write to the proper addresses is issued.
Each function is passed an 'io' flag, where 0 means a read from
the port, and 1 means a write to the port. On input, the actual
input is passed as the return value, on output, 'data' is written
to the device.
*/
/* DC-4 drive select register routine - this register is not part of the 1797
*/
int32 fdcdrv(int32 io, int32 data)
{
/* **** probably need to grab the parameters from the SIR and set the limits */
if (io) { /* write to DC-4 drive register */
cur_dsk = data & 0x03; /* only 2 drive select bits */
#if DEBUG > 0
printf("Drive set to %d\n\r", cur_dsk);
#endif
if ((dsk_unit[cur_dsk].flags & UNIT_ENABLE) == 0)
cur_flg[cur_dsk] |= WRPROT; /* set WPROT */
return 0;
} else { /* read from DC-4 drive register */
#if DEBUG > 0
printf("Drive read as %02X\n\r", intrq);
#endif
return intrq;
}
}
/* WD 1797 FDC command register routine */
int32 fdccmd(int32 io, int32 data)
{
static int32 val = 0, val1 = NOTRDY, i;
static long pos;
UNIT *uptr;
if ((dsk_unit[cur_dsk].flags & UNIT_ATT) == 0) { /* not attached */
cur_flg[cur_dsk] |= NOTRDY; /* set not ready flag */
printf("Drive %d is not attached\n\r", cur_dsk);
return 0;
} else {
cur_flg[cur_dsk] &= ~NOTRDY; /* clear not ready flag */
}
uptr = dsk_dev.units + cur_dsk; /* get virtual drive address */
if (io) { /* write command to fdc */
switch(data) {
case 0x8C: /* read command */
case 0x9C:
#if DEBUG > 0
printf("Read of disk %d, track %d, sector %d\n\r",
cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]);
#endif
pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */
pos += SECT_SIZE * (cur_sec[cur_dsk] - 1);
#if DEBUG > 0
printf("Read pos = %ld ($%04X)\n\r", pos, pos);
#endif
sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */
sim_fread(dskbuf, 256, 1, uptr -> fileref); /* read in buffer */
cur_flg[cur_dsk] |= BUSY | DRQ; /* set DRQ & BUSY */
i = cur_byt[cur_dsk] = 0; /* clear counter */
break;
case 0xAC: /* write command */
#if DEBUG > 0
printf("Write of disk %d, track %d, sector %d\n\r",
cur_dsk, cur_trk[cur_dsk], cur_sec[cur_dsk]);
#endif
if (cur_flg[cur_dsk] & WRPROT) {
printf("Drive %d is write-protected\n\r", cur_dsk);
} else {
pos = TRAK_SIZE * cur_trk[cur_dsk]; /* calculate file offset */
pos += SECT_SIZE * (cur_sec[cur_dsk] - 1);
#if DEBUG > 1
printf("Write pos = %ld ($%04X)\n\r", pos, pos);
#endif
sim_fseek(uptr -> fileref, pos, 0); /* seek to offset */
dptr = uptr; /* save pointer for actual write */
cur_flg[cur_dsk] |= BUSY | DRQ;/* set DRQ & BUSY */
i = cur_byt[cur_dsk] = 0; /* clear counter */
}
break;
case 0x18: /* seek command */
case 0x1B:
cur_trk[cur_dsk] = fdcbyte; /* set track */
cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */
#if DEBUG > 0
printf("Seek of disk %d, track %d\n\r", cur_dsk, fdcbyte);
#endif
break;
case 0x0B: /* restore command */
cur_trk[cur_dsk] = 0; /* home the drive */
cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */
#if DEBUG > 0
printf("Drive %d homed\n\r", cur_dsk);
#endif
break;
default:
printf("Unknown FDC command %02H\n\r", data);
}
} else { /* read status from fdc */
val = cur_flg[cur_dsk]; /* set return value */
if (val1 == 0 && val == 0x03) /* delay BUSY going high */
val = 0x02; /* set DRQ first */
if (val != val1) { /* now allow BUSY after on read */
val1 = val;
#if DEBUG > 0
printf("Drive %d status=%02X\n\r", cur_dsk, cur_flg[cur_dsk]);
#endif
}
}
return val;
}
/* WD 1797 FDC track register routine */
int32 fdctrk(int32 io, int32 data)
{
if (io) {
cur_trk[cur_dsk] = data & 0xFF;
#if DEBUG > 1
printf("Drive %d track set to %d\n\r", cur_dsk, data);
#endif
} else
;
#if DEBUG > 1
printf("Drive %d track read as %d\n\r", cur_dsk, cur_trk[cur_dsk]);
#endif
return cur_trk[cur_dsk];
}
/* WD 1797 FDC sector register routine */
int32 fdcsec(int32 io, int32 data)
{
if (io) {
cur_sec[cur_dsk] = data & 0xFF;
if (cur_sec[cur_dsk] == 0) /* fix for swtp boot! */
cur_sec[cur_dsk] = 1;
#if DEBUG > 1
printf("Drive %d sector set to %d\n\r", cur_dsk, data);
#endif
} else
;
#if DEBUG > 1
printf("Drive %d sector read as %d\n\r", cur_dsk, cur_sec[cur_dsk]);
#endif
return cur_sec[cur_dsk];
}
/* WD 1797 FDC data register routine */
int32 fdcdata(int32 io, int32 data)
{
int32 i;
if (io) { /* write byte to fdc */
fdcbyte = data; /* save for seek */
if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes to buffer */
#if DEBUG > 3
printf("Writing byte %d of %02X\n\r", cur_byt[cur_dsk], data);
#endif
cur_byt[cur_dsk]++; /* step counter */
dskbuf[i] = data; /* byte into buffer */
if (cur_byt[cur_dsk] == SECT_SIZE) {
cur_flg[cur_dsk] &= ~(BUSY | DRQ);
if (dptr) { /* if initiated by FDC write command */
sim_fwrite(dskbuf, 256, 1, dptr -> fileref); /* write it */
dptr = NULL;
}
#if DEBUG > 0
printf("Sector write complete\n\r");
#endif
}
}
return 0;
} else { /* read byte from fdc */
if ((i = cur_byt[cur_dsk]) < SECT_SIZE) { /* copy bytes from buffer */
#if DEBUG > 1
printf("Reading byte %d\n\r", cur_byt[cur_dsk]);
#endif
cur_byt[cur_dsk]++; /* step counter */
if (cur_byt[cur_dsk] == SECT_SIZE) { /* done? */
cur_flg[cur_dsk] &= ~(BUSY | DRQ); /* clear flags */
#if DEBUG > 0
printf("Sector read complete\n\r");
#endif
}
return (dskbuf[i] & 0xFF);
} else
return 0;
}
}

312
swtp/swtp_sio.c Normal file
View file

@ -0,0 +1,312 @@
/* swtp_sio: SWTP serial I/O card
Copyright (c) 2005, William Beech
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
Willaim Beech BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of William A. Beech shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from William A. Beech.
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
These functions support a simulated SWTP MP-S interface card.
The card had two physical I/O ports which could be connected
to any serial I/O device that would connect to a current loop
or RS232 interface. Available baud rates were jumper selectable
for each port from 110 to 9600. The ports appear at all 4 addresses.
This fact is used by SWTBUG to determine the presence of the MP-S vice
MP-C serial card.
All I/O is via either programmed I/O or interrupt controlled I/O.
It has a status port and a data port. A write to the status port
can select some options for the device (0x03 will reset the port).
A read of the status port gets the port status:
+---+---+---+---+---+---+---+---+
| I | P | O | F |CTS|DCD|TXE|RXF|
+---+---+---+---+---+---+---+---+
RXF - A 1 in this bit position means a character has been received
on the data port and is ready to be read.
TXE - A 1 in this bit means the port is ready to receive a character
on the data port and transmit it out over the serial line.
A read to the data port gets the buffered character, a write
to the data port writes the character to the device.
*/
#include <stdio.h>
#include <ctype.h>
#include "swtp_defs.h"
#define UNIT_V_ANSI (UNIT_V_UF + 0) // ANSI mode
#define UNIT_ANSI (1 << UNIT_V_ANSI)
t_stat sio_svc (UNIT *uptr);
t_stat sio_reset (DEVICE *dptr);
t_stat ptr_svc (UNIT *uptr);
t_stat ptr_reset (DEVICE *dptr);
t_stat ptp_svc (UNIT *uptr);
t_stat ptp_reset (DEVICE *dptr);
int32 ptr_stopioe = 0, ptp_stopioe = 0; // stop on error
// MP-S Standard I/O Data Structures
UNIT sio_unit = { UDATA (&sio_svc, 0, 0),
KBD_POLL_WAIT };
REG sio_reg[] = {
{ ORDATA (DATA, sio_unit.buf, 8) },
{ ORDATA (STAT, sio_unit.u3, 8) },
{ NULL } };
MTAB sio_mod[] = {
{ UNIT_ANSI, 0, "TTY", "TTY", NULL },
{ 0 } };
DEVICE sio_dev = {
"MP-S", &sio_unit, sio_reg, sio_mod,
1, 10, 31, 1, 8, 8,
NULL, NULL, &sio_reset,
NULL, NULL, NULL };
UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
KBD_POLL_WAIT };
DEVICE ptr_dev = {
"PTR", &ptr_unit, NULL, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptr_reset,
NULL, NULL, NULL };
UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0),
KBD_POLL_WAIT };
DEVICE ptp_dev = {
"PTP", &ptp_unit, NULL, NULL,
1, 10, 31, 1, 8, 8,
NULL, NULL, &ptp_reset,
NULL, NULL, NULL };
/* Service routines to handle simulator functions */
/* service routine - actually gets char & places in buffer */
int32 ptp_rdr(int32 io, int32 data);
int32 ptp_flag = 0, ptr_flag = 0;
/* console input service routine */
int32 sio_svc (UNIT *uptr)
{
int32 temp;
sim_activate (&sio_unit, sio_unit.wait); // continue poll
if ((temp = sim_poll_kbd ()) < SCPE_KFLAG)
return temp; // no char or error?
sio_unit.buf = temp & 0xFF; // Save char
sio_unit.u3 |= 0x01; // Set RXF flag
/* Do any special character handling here */
sio_unit.pos++; // step character count
return SCPE_OK;
}
/* paper tape reader input service routine */
int32 ptr_svc (UNIT *uptr)
{
return SCPE_OK;
}
/* paper tape punch output service routine */
int32 ptp_svc (UNIT *uptr)
{
return SCPE_OK;
}
/* Reset console */
int32 sio_reset (DEVICE *dptr)
{
sio_unit.buf = 0; // Data buffer
sio_unit.u3 = 0x02; // Status buffer
sim_activate (&sio_unit, sio_unit.wait); // activate unit
return SCPE_OK;
}
/* Reset paper tape reader */
int32 ptr_reset (DEVICE *dptr)
{
ptr_unit.buf = 0;
ptr_unit.u3 = 0x02;
sim_cancel (&ptr_unit); // deactivate unit
return SCPE_OK;
}
/* Reset paper tape punch */
int32 ptp_reset (DEVICE *dptr)
{
ptp_unit.buf = 0;
ptp_unit.u3 = 0x02;
sim_cancel (&ptp_unit); // deactivate unit
return SCPE_OK;
}
/* I/O instruction handlers, called from the CPU module when a
read or write occur to addresses 0x8000-0x801F.
Each function is passed an 'io' flag, where 0 means a read from
the port, and 1 means a write to the port. On input, the actual
input is passed as the return value, on output, 'data' is written
to the device.
This code emulates a SWTP MP-S Serial Card with a Model 33 Teletype
attached. The Model 33 uses DC1-DC4 codes to enable or disable the
paper tape reader and punch. Those devices are defined in this module,
and the code built to emulate those functions if the PTP and/or PTR
are attached in the simulator.
*/
/* Port 1 (0x8004-0x8007) controls the Model 33 Teletype */
int32 ptr_flg1 = 0;
int32 odata, status;
int32 sio0s(int32 io, int32 data)
{
UNIT *uptr;
if (io == 0) { // control register read
if (ptr_flag) { // reader enabled?
if ((ptr_unit.flags & UNIT_ATT) == 0) // attached?
ptr_unit.u3 &= 0xFE; // no, clear RXF flag
else {
uptr = ptr_dev.units;// not EOF?
if (feof(uptr -> fileref))
ptr_unit.u3 &= 0xFE;
else
ptr_unit.u3 |= 0x01;
}
return (status = ptr_unit.u3); // no - done
} else {
return (status = sio_unit.u3); // return console status
}
} else { // control register write
if (data == 0x03) { // reset port!
sio_unit.u3 = 0x02; // reset console
sio_unit.buf = 0;
sio_unit.pos = 0;
ptr_unit.u3 = 0x02; // reset reader
ptr_unit.buf = 0;
ptr_unit.pos = 0;
ptp_unit.u3 = 0x02; // reset punch
ptp_unit.buf = 0;
ptp_unit.pos = 0;
}
return (status = 0); // invalid io
}
}
int32 sio0d(int32 io, int32 data)
{
UNIT *uptr;
if (io == 0) { // data register read
if (ptr_flag) { // RDR enabled?
if ((ptr_unit.flags & UNIT_ATT) == 0) // attached?
return 0; // no, done
// printf("ptr_unit.u3=%02X\n", ptr_unit.u3);
if ((ptr_unit.u3 & 0x01) == 0) { // yes, more data?
// printf("Returning old %02X\n", odata); // no, return previous byte
return (odata & 0xFF);
}
uptr = ptr_dev.units; // get data byte
if ((odata = getc(uptr -> fileref)) == EOF) { // end of file?
// printf("Got EOF\n");
ptr_unit.u3 &= 0xFE; // clear RXF flag
return (odata = 0); // no data
}
// printf("Returning new %02X\n", odata);
ptr_unit.pos++; // step character count
ptr_unit.u3 &= 0xFE; // clear RXF flag
return (odata & 0xFF); // return character
} else {
sio_unit.u3 &= 0xFE; // clear RXF flag
return (odata = sio_unit.buf); // return next char
}
} else { // data register write
if (isprint(data) || data == '\r' || data == '\n') { // printable?
sim_putchar(data); // print character on console
if (ptp_flag && ptp_unit.flags & UNIT_ATT) { // PTP enabled & attached?
uptr = ptp_dev.units; // punch character to file
putc(data, uptr -> fileref);
ptp_unit.pos++; // step character counter
}
} else { // DC1-DC4 control Reader/Punch
switch (data) {
case 0x11: // RDR on
ptr_flag = 1;
ptr_flg1 = 0;
ptr_unit.u3 |= 0x01;
// printf("Reader on\r\n");
break;
case 0x12: // PTP on
ptp_flag = 1;
ptp_unit.u3 |= 0x02;
// printf("Punch on\r\n");
break;
case 0x13: // RDR off
ptr_flag = 0;
// printf("Reader off-%d bytes read\r\n", ptr_unit.pos);
break;
case 0x14: // PTP off
ptp_flag = 0;
// printf("Punch off-%d bytes written\r\n", ptp_unit.pos);
break;
default: // ignore all other characters
break;
}
}
}
return (odata = 0);
}
/* because each port appears at 2 addresses and this fact is used
to determine if it is a MP-C or MP-S repeatedly in the SWTBUG
monitor, this code assures that reads of the high ports return
the same data as was read the last time on the low ports.
*/
int32 sio1s(int32 io, int32 data)
{
return status;
}
int32 sio1d(int32 io, int32 data)
{
return odata;
}

425
swtp/swtp_sys.c Normal file
View file

@ -0,0 +1,425 @@
/* swtp_sys.c: SWTP 6800 system interface
Copyright (c) 2005, William Beech
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of William A. Beech shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from William A. Beech.
Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005
*/
#include <ctype.h>
#include <string.h>
#include "swtp_defs.h"
/* externals */
extern DEVICE cpu_dev;
extern DEVICE dsk_dev;
extern UNIT cpu_unit;
extern REG cpu_reg[];
extern DEVICE sio_dev;
extern DEVICE ptr_dev;
extern DEVICE ptp_dev;
extern DEVICE lpt_dev;
extern unsigned char M[];
extern int32 saved_PC;
extern int32 sim_switches;
//extern int32 (*sim_vm_fprint_addr)(FILE*, DEVICE*,t_addr);
/* prototypes */
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag);
int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
UNIT *uptr, int32 sw);
t_addr fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr);
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw);
void sim_special_init (void);
/* links into scp */
void (*sim_vm_init)(void) = &sim_special_init;
/* SCP data structures
sim_name simulator name string
sim_PC pointer to saved PC register descriptor
sim_emax number of words needed 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[] = "SWTP 6800";
REG *sim_PC = &cpu_reg[0];
int32 sim_emax = 16;
DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptp_dev, &ptr_dev, &dsk_dev, NULL };
const char *sim_stop_messages[] = {
"Unknown error",
"Unknown I/O Instruction",
"HALT instruction",
"Breakpoint",
"Invalid Opcode",
"Invalid Memory" };
static const char *opcode[] = {
"???", "NOP", "???", "???", //0x00
"???", "???", "TAP", "TPA",
"INX", "DEX", "CLV", "SEV",
"CLC", "SEC", "CLI", "SEI",
"SBA", "CBA", "???", "???", //0x10
"???", "???", "TAB", "TBA",
"???", "DAA", "???", "ABA",
"???", "???", "???", "???",
"BRA", "???", "BHI", "BLS", //0x20
"BCC", "BCS", "BNE", "BEQ",
"BVC", "BVS", "BPL", "BMI",
"BGE", "BLT", "BGT", "BLE",
"TSX", "INS", "PULA", "PULB", //0x30
"DES", "TXS", "PSHA", "PSHB",
"???", "RTS", "???", "RTI",
"???", "???", "WAI", "SWI",
"NEGA", "???", "???", "COMA", //0x40
"LSRA", "???", "RORA", "ASRA",
"ASLA", "ROLA", "DECA", "???",
"INCA", "TSTA", "???", "CLRA",
"NEGB", "???", "???", "COMB", //0x50
"LSRB", "???", "RORB", "ASRB",
"ASLB", "ROLB", "DECB", "???",
"INCB", "TSTB", "???", "CLRB",
"NEG", "???", "???", "COM", //0x60
"LSR", "???", "ROR", "ASR",
"ASL", "ROL", "DEC", "???",
"INC", "TST", "JMP", "CLR",
"NEG", "???", "???", "COM", //0x70
"LSR", "???", "ROR", "ASR",
"ASL", "ROL", "DEC", "???",
"INC", "TST", "JMP", "CLR",
"SUBA", "CMPA", "SBCA", "???", //0x80
"ANDA", "BITA", "LDAA", "???",
"EORA", "ADCA", "ORAA", "ADDA",
"CPX", "BSR", "LDS", "???",
"SUBA", "CMPA", "SBCA", "???", //0x90
"ANDA", "BITA", "LDAA", "STAA",
"EORA", "ADCA", "ORAA", "ADDA",
"CPX", "???", "LDS", "STS",
"SUBA", "CMPA", "SBCA", "???", //0xA0
"ANDA", "BITA", "LDAA", "STAA",
"EORA", "ADCA", "ORAA", "ADDA",
"CPX X", "JSR X", "LDS X", "STS X",
"SUBA", "CMPA", "SBCA", "???", //0xB0
"ANDA", "BITA", "LDAA", "STAA",
"EORA", "ADCA", "ORAA", "ADDA",
"CPX", "JSR", "LDS", "STS",
"SUBB", "CMPB", "SBCB", "???", //0xC0
"ANDB", "BITB", "LDAB", "???",
"EORB", "ADCB", "ORAB", "ADDB",
"???", "???", "LDX", "???",
"SUBB", "CMPB", "SBCB", "???", //0xD0
"ANDB", "BITB", "LDAB", "STAB",
"EORB", "ADCB", "ORAB", "ADDB",
"???", "???", "LDX", "STX",
"SUBB", "CMPB", "SBCB", "???", //0xE0
"ANDB", "BITB", "LDAB", "STAB",
"EORB", "ADCB", "ORAB", "ADDB",
"???", "???", "LDX", "STX",
"SUBB", "CMPB", "SBCB", "???", //0xF0
"ANDB", "BITB", "LDAB", "STAB",
"EORB", "ADCB", "ORAB", "ADDB",
"???", "???", "LDX", "STX",
};
int32 oplen[256] = {
0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00
1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0,
2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1,
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40
1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1,
2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2,
3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3,
2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80
2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2,
2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3,
2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0
2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,
2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2,
3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 };
/* This is the dumper/loader. This command uses the -h to signify a
hex dump/load vice a binary one. If no address is given to load, it
takes the address from the hex record or the current PC for binary.
*/
int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag)
{
int32 i, cnt = 0, addr = 0, start = 0x10000, end = 0, bytecnt,
cksum1, cksum, bytes[250];
char buffer[256];
sscanf(cptr," %x-%x", &start, &end);
if (flag) { // dump
if (start == 0x10000) // no address parameter
return SCPE_2FARG;
if (sim_switches & 0x80) { // hex dump
addr = start;
while (addr <= end) { // more records to write
if ((addr + 16) <= end) // how many bytes this record
bytecnt = 16 + 3;
else
bytecnt = end - addr + 4;
cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum
fprintf(fileref, "S1%02X%02X%02X", bytecnt, addr>>8, addr&0xFF); //header
for (i=0; i<bytecnt-3; i++, addr++, cnt++) { // data
fprintf(fileref, "%02X", M[addr]);
cksum -= M[addr];
}
fprintf(fileref, "%02X\r\n", cksum & 0xff); // eor
}
fprintf(fileref, "S9\r\n"); // eof
} else { // binary dump
for (addr = start; addr <= end; addr++, cnt++) {
putc(M[addr], fileref);
}
}
printf ("%d Bytes dumped starting at %04X\n", cnt, start);
} else { // load
if (sim_switches & 0x80) { // hex load
while ((fgets(buffer, 255, fileref)) != NULL) {
if (buffer[0] != 'S')
printf("Not a Motorola hex format file\n");
else {
if (buffer[0] == '0') // name record
printf("Name record found and ignored\n");
else if (buffer[1] == '1') { // another record
sscanf(buffer+2,"%2x%4x", &bytecnt, &addr);
if (start == 0x10000)
start = addr;
for (i=0; i < bytecnt-3; i++)
sscanf(buffer+8+(2*i), "%2x", &bytes[i]);
sscanf(buffer+8+(2*i), "%2x", &cksum1);
cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum
for (i=0; i < bytecnt-3; i++)
cksum -= bytes[i];
cksum &= 0xFF;
if (cksum != cksum1)
printf("Checksum error\n");
else {
for (i=0; i < bytecnt-3; i++) {
M[addr++] = bytes[i];
cnt++;
}
}
} else if (buffer[1] == '9') // end of file
printf("End of file\n");
}
}
} else { // binary load
if (start == 0x10000) // no starting address
addr = saved_PC;
else
addr = start;
start = addr;
while ((i = getc (fileref)) != EOF) {
M[addr] = i;
addr++;
cnt++;
}
}
printf ("%d Bytes loaded starting at %04X\n", cnt, start);
}
return (SCPE_OK);
}
/* Symbolic output
Inputs:
*of = output stream
addr = current PC
*val = pointer to values
*uptr = pointer to unit
sw = switches
Outputs:
status = error code
*/
int32 fprint_sym (FILE *of, int32 addr, uint32 *val,
UNIT *uptr, int32 sw)
{
int32 i, inst, inst1;
if (sw & SWMASK ('D')) { // dump memory
for (i=0; i<16; i++)
fprintf(of, "%02X ", val[i]);
fprintf(of, " ");
for (i=0; i<16; i++)
if (isprint(val[i]))
fprintf(of, "%c", val[i]);
else
fprintf(of, ".");
return -15;
} else if (sw & SWMASK ('M')) { // dump instruction mnemonic
inst = val[0];
if (!oplen[inst]) { // invalid opcode
fprintf(of, "%02X", inst);
return 0;
}
inst1 = inst & 0xF0;
fprintf (of, "%s", opcode[inst]); // mnemonic
if (strlen(opcode[inst]) == 3)
fprintf(of, " ");
if (inst1 == 0x20 || inst == 0x8D) { // rel operand
inst1 = val[1];
if (val[1] & 0x80)
inst1 |= 0xFF00;
fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK);
} else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand
if ((inst & 0x0F) < 0x0C)
fprintf(of, " #$%02X", val[1]);
else
fprintf(of, " #$%02X%02X", val[1], val[2]);
} else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand
fprintf(of, " %d,X", val[1]);
else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand
fprintf(of, " $%02X%02X", val[1], val[2]);
return (-(oplen[inst] - 1));
} else
return SCPE_ARG;
}
/* address output routine */
t_addr fprint_addr(FILE *of, DEVICE *dptr, t_addr addr)
{
fprintf(of, "%04X", addr);
return 0;
}
/* 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
*/
int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw)
{
int32 cflag, i = 0, j, r;
char gbuf[CBUFSIZE];
cflag = (uptr == NULL) || (uptr == &cpu_unit);
while (isspace (*cptr)) cptr++; /* absorb spaces */
if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */
if (cptr[0] == 0)
return SCPE_ARG; /* must have 1 char */
val[0] = (uint32) cptr[0];
return SCPE_OK;
}
if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */
if (cptr[0] == 0)
return SCPE_ARG; /* must have 1 char */
val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1];
return SCPE_OK;
}
/* An instruction: get opcode (all characters until null, comma,
or numeric (including spaces).
*/
while (1) {
if (*cptr == ',' || *cptr == '\0' ||
isdigit(*cptr))
break;
gbuf[i] = toupper(*cptr);
cptr++;
i++;
}
/* Allow for RST which has numeric as part of opcode */
if (toupper(gbuf[0]) == 'R' &&
toupper(gbuf[1]) == 'S' &&
toupper(gbuf[2]) == 'T') {
gbuf[i] = toupper(*cptr);
cptr++;
i++;
}
/* Allow for 'MOV' which is only opcode that has comma in it. */
if (toupper(gbuf[0]) == 'M' &&
toupper(gbuf[1]) == 'O' &&
toupper(gbuf[2]) == 'V') {
gbuf[i] = toupper(*cptr);
cptr++;
i++;
gbuf[i] = toupper(*cptr);
cptr++;
i++;
}
/* kill trailing spaces if any */
gbuf[i] = '\0';
for (j = i - 1; gbuf[j] == ' '; j--) {
gbuf[j] = '\0';
}
/* find opcode in table */
for (j = 0; j < 256; j++) {
if (strcmp(gbuf, opcode[j]) == 0)
break;
}
if (j > 255) /* not found */
return SCPE_ARG;
val[0] = j; /* store opcode */
if (oplen[j] < 2) /* if 1-byter we are done */
return SCPE_OK;
if (*cptr == ',') cptr++;
cptr = get_glyph(cptr, gbuf, 0); /* get address */
sscanf(gbuf, "%o", &r);
if (oplen[j] == 2) {
val[1] = r & 0xFF;
return (-1);
}
val[1] = r & 0xFF;
val[2] = (r >> 8) & 0xFF;
return (-2);
}
/* initialize optional interfaces */
void sim_special_init (void)
{
// *sim_vm_fprint_addr = &fprint_addr;
}