1
0
mirror of https://github.com/simh/simh.git synced 2026-01-11 23:52:58 +00:00

HP3000: Fourth HP 3000 release

See HP3000/hp3000_release.txt for details of the release
This commit is contained in:
Mark Pizzolato 2017-01-10 12:32:23 -08:00
parent bdb0597411
commit 629f0f0c07
22 changed files with 5362 additions and 1110 deletions

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,15 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
07-Nov-16 JDB Added SETR and SETR_X for SETR executor use;
renamed cpu_byte_to_word_ea to cpu_byte_ea
03-Nov-16 JDB Added LABEL_LOCAL for PARC/XBR/ENDP executor use
01-Nov-16 JDB Added debug flag for per-instruction trace capability
22-Oct-16 JDB Added "cpu_interrupt_pending" global from cpu_base.c
07-Oct-16 JDB Added "cpu_dev" external so executors can trace instructions
28-Sep-16 JDB Added CIS definitions
22-Sep-16 JDB Added cpu_byte_to_word_ea, STATUS_CS macro
21-Sep-16 JDB Added STATUS_CCI, UNIT_CIS, and the CIS dispatcher
12-Sep-16 JDB Added the PCN_SERIES_II and PCN_SERIES_III constants
02-Sep-16 JDB Added the POWER_STATE enumeration type, the UNIT_PFARS
flag, and the "cpu_power_state" external declaration
@ -46,28 +55,6 @@
/* Architectural constants.
The type used to represent a main memory word value is defined. An array of
this type is used to simulate the CPU main memory.
Implementation notes:
1. The MEMORY_WORD type is a 16-bit unsigned type, corresponding with the
16-bit main memory in the HP 3000. Unlike the general data type, which
is a 32-bit type for speed, main memory does not benefit from the faster
32-bit execution on IA-32 processors, as only one instruction in the
cpu_read_memory and cpu_write_memory routines has an operand override
that invokes the slower instruction fetch path. There is a negligible
difference in the Memory Pattern Test diagnostic execution speeds for the
uint32 vs. uint16 definition, whereas the VM requirements are doubled for
the former.
*/
typedef uint16 MEMORY_WORD; /* HP 16-bit memory word representation */
/* Supported breakpoint switches */
#define BP_EXEC (SWMASK ('E')) /* an execution breakpoint */
@ -80,6 +67,7 @@ typedef uint16 MEMORY_WORD; /* HP 16-bit memory word represe
#define UNIT_EIS_SHIFT (UNIT_V_UF + 1) /* the Extended Instruction Set firmware option */
#define UNIT_CALTIME_SHIFT (UNIT_V_UF + 2) /* the process clock timing mode */
#define UNIT_PFARS_SHIFT (UNIT_V_UF + 3) /* the power-fail auto-restart mode */
#define UNIT_CIS_SHIFT (UNIT_V_UF + 4) /* the COBOL II Extended Instruction Set firmware option */
#define UNIT_MODEL_MASK 0000001u /* model ID mask */
@ -90,6 +78,7 @@ typedef uint16 MEMORY_WORD; /* HP 16-bit memory word represe
#define UNIT_EIS (1u << UNIT_EIS_SHIFT) /* the Extended Instruction Set is installed */
#define UNIT_CALTIME (1u << UNIT_CALTIME_SHIFT) /* the process clock is calibrated to wall time */
#define UNIT_PFARS (1u << UNIT_PFARS_SHIFT) /* the system will auto-restart after a power failure */
#define UNIT_CIS (1u << UNIT_CIS_SHIFT) /* the COBOL II Extended Instruction Set is installed */
#define UNIT_CPU_MODEL (cpu_unit [0].flags & UNIT_MODEL)
@ -100,11 +89,12 @@ typedef uint16 MEMORY_WORD; /* HP 16-bit memory word represe
/* CPU debug flags */
#define DEB_MDATA (1u << 0) /* trace memory data accesses */
#define DEB_INSTR (1u << 1) /* trace instruction execution */
#define DEB_FETCH (1u << 2) /* trace instruction fetches */
#define DEB_REG (1u << 3) /* trace register values */
#define DEB_PSERV (1u << 4) /* trace PCLK service events */
#define DEB_ALL ~0u /* trace everything */
#define DEB_INSTR (1u << 0) /* trace instructions */
#define DEB_REG (1u << 1) /* trace register values */
#define DEB_PSERV (1u << 2) /* trace PCLK service events */
#define DEB_EXEC (1u << 3) /* trace matched instruction executions */
#define BOV_FORMAT "%02o.%06o %06o " /* bank-offset-value trace format string */
@ -118,6 +108,13 @@ typedef uint16 MEMORY_WORD; /* HP 16-bit memory word represe
#define SS_BYPASSED (1u << 31) /* stops are bypassed for this instruction */
/* Memory access macros */
#define cpu_read_memory(c,o,v) mem_read (&cpu_dev, c, o, v)
#define cpu_write_memory(c,o,v) mem_write (&cpu_dev, c, o, v)
/* System power state.
The HP 3000 power supply uses two signals to indicate its state: PON (power
@ -157,38 +154,6 @@ typedef enum {
} EXEC_STATE;
/* Memory access classifications.
The access classification determines which bank register is used with the
supplied offset to access memory, and whether or not the access is bounds
checked.
Implementation notes:
1. The "_iop" and "_sel" classifications are identical. The only difference
is which device's trace flag is checked to print debugging information.
All of the other classifications check the CPU's trace flags.
*/
typedef enum {
absolute_iop, /* absolute bank, IOP request */
dma_iop, /* DMA channel bank, IOP request */
absolute_sel, /* absolute bank, selector channel request */
dma_sel, /* DMA channel bank, selector channel request */
absolute, /* absolute bank */
absolute_checked, /* absolute bank, bounds checked */
fetch, /* program bank, instruction fetch */
fetch_checked, /* program bank, instruction fetch, bounds checked */
program, /* program bank, data access */
program_checked, /* program bank, data access, bounds checked */
data, /* data bank, data access */
data_checked, /* data bank, data access, bounds checked */
stack, /* stack bank, data access */
stack_checked /* stack bank, data access, bounds checked */
} ACCESS_CLASS;
/* CPX register flags.
The CPX1 register contains flags that designate the run-time interrupts. The
@ -435,9 +400,9 @@ typedef enum {
Condition Code:
00 = CCL (less than)
01 = CCE (equal to)
10 = CCG (greater than)
00 = CCG (greater than)
01 = CCL (less than)
10 = CCE (equal to)
11 = invalid
*/
@ -451,13 +416,18 @@ typedef enum {
#define STATUS_CCG 0000000u /* condition code greater than */
#define STATUS_CCL 0000400u /* condition code less than */
#define STATUS_CCE 0001000u /* condition code equal to */
#define STATUS_CCI 0001400u /* condition code invalid */
#define STATUS_CC_MASK 0001400u /* condition code mask */
#define STATUS_CC_SHIFT 8 /* condition code alignment */
#define STATUS_CS_MASK 0000377u /* code segment mask */
#define STATUS_CS_SHIFT 0 /* code segment alignment */
#define STATUS_CS_WIDTH 8 /* code segment mask width */
#define STATUS_CS(s) (((s) & STATUS_CS_MASK) >> STATUS_CS_SHIFT)
#define STATUS_OVTRAP (STATUS_T | STATUS_O)
#define STATUS_NPRV (STATUS_T | STATUS_O | STATUS_C | STATUS_CC_MASK)
@ -822,7 +792,7 @@ typedef enum {
#define FMEXSUBOP(v) BITS_12_15(v) /* firmware extension suboperation accessor */
/* Specific instruction accessors */
/* General instruction accessors */
#define IOOP_K_MASK 0000017u /* I/O K-field mask */
#define IOOP_K_SHIFT 0000000u /* I/O K-field alignment shift */
@ -876,18 +846,8 @@ typedef enum {
#define SDEC2(v) (((v) & SDEC2_MASK) >> SDEC_SHIFT)
#define SDEC3(v) (((v) & SDEC3_MASK) >> SDEC_SHIFT)
#define DB_FLAG 0000020u /* PB/DB base flag */
#define MVBW_CCF 0000030u /* MVBW condition code flags */
#define MVBW_N_FLAG 0000020u /* MVBW numeric flag */
#define MVBW_A_FLAG 0000010u /* MVBW alphabetic flag */
#define MVBW_S_FLAG 0000004u /* MVBW upshift flag */
#define MVBW_CCF_SHIFT 6 /* CCF alignment in MVBW instruction */
#define NABS_FLAG 0000100u /* CVDA negative absolute value flag */
#define ABS_FLAG 0000040u /* CVDA absolute value flag */
#define EIS_SDEC_SHIFT 4 /* EIS S-decrement alignment shift */
#define DB_FLAG 0000020u /* base set PB/DB base register flag */
#define CIS_DB_FLAG 0000001u /* CIS set PB/DB base register flag */
/* Explicit instruction opcodes and accessors */
@ -896,6 +856,8 @@ typedef enum {
#define QASR 0015700u /* quadruple arithmetic right shift */
#define DMUL 0020570u /* double integer multiply */
#define DDIV 0020571u /* double integer divide */
#define SETR 0027400u /* set registers (none) */
#define SETR_X 0027404u /* set registers (index) */
#define SED_1 0030041u /* set enable interrupt */
#define HALT_10 0030370u /* halt 10 */
@ -932,6 +894,26 @@ typedef enum {
#define CMD_TO(v) (((v) & CMD_TO_MASK) >> CMD_TO_SHIFT)
#define CMD_MOP(v) (((v) & CMD_MOP_MASK) >> CMD_MOP_SHIFT)
#define MVBW_CCF 0000030u /* MVBW condition code flags */
#define MVBW_N_FLAG 0000020u /* MVBW numeric flag */
#define MVBW_A_FLAG 0000010u /* MVBW alphabetic flag */
#define MVBW_S_FLAG 0000004u /* MVBW upshift flag */
#define MVBW_CCF_SHIFT 6 /* CCF alignment in MVBW instruction */
#define NABS_FLAG 0000100u /* CVDA negative absolute value flag */
#define ABS_FLAG 0000040u /* CVDA absolute value flag */
#define CVND_SC_MASK 0000016u /* CVND sign-control mask */
#define CVND_SC_SHIFT 1 /* CVND sign-control field alignment shift */
#define EIS_SDEC_MASK 0000020u /* EIS S-decrement mask */
#define EIS_SDEC_SHIFT 4 /* EIS S-decrement alignment shift */
#define CIS_SDEC_MASK 0000001u /* CIS S-decrement mask */
#define CIS_SDEC_SHIFT 0 /* CIS S-decrement alignment shift */
#define TCCS_CCF_SHIFT 8 /* CIS TCCS instruction CCF alignment */
/* PSHR/SETR instruction accessors */
@ -956,6 +938,16 @@ typedef enum {
#define PCN_SERIES_III 2 /* CPU number for the Series III */
/* EDIT instruction subprogram operation values */
#define EDIT_SUFS 013 /* highest opcode with an extended immediate operand */
#define EDIT_EXOP 017 /* extended opcode prefix */
#define EDIT_TE (EDIT_EXOP + 000) /* first extended opcode with no operand */
#define EDIT_MDWO (EDIT_EXOP + 004) /* last extended opcode with no operand */
#define EDIT_DBNZ (EDIT_EXOP + 011) /* last extended opcode */
/* Reserved memory addresses */
#define CSTB_POINTER 0000000u /* code segment table base pointer */
@ -1006,6 +998,7 @@ typedef enum {
#define LABEL_STTN_SHIFT 8 /* STT number alignment shift */
#define LABEL_SEGMENT_SHIFT 0 /* segment number alignment shift */
#define LABEL_LOCAL 0000000u /* local program label flag */
#define LABEL_UNCALLABLE 0040000u /* local program label uncallable flag */
#define LABEL_ADDRESS_MASK 0037777u /* local program label address mask */
@ -1017,7 +1010,7 @@ typedef enum {
#define LABEL_IRQ (LABEL_EXTERNAL | ISR_SEGMENT) /* label for interrupt requests */
#define LABEL_STTN_MAX (LABEL_STTN_MASK >> LABEL_STTN_SHIFT) /* STT number maximum value */
#define TO_LABEL(s,n) ((s) | (n) << LABEL_STTN_SHIFT)
#define TO_LABEL(s,n) ((s) | (n) << LABEL_STTN_SHIFT) /* s = segment number, n = STT number */
/* Stack marker accessors */
@ -1063,6 +1056,11 @@ extern HP_WORD CNTR; /* Microcode Counter */
#define RD TR [3]
/* CPU device */
extern DEVICE cpu_dev; /* Central Processing Unit */
/* CPU state */
extern jmp_buf cpu_save_env; /* saved environment for microcode aborts */
@ -1088,14 +1086,15 @@ extern void cpu_flush (void);
extern void cpu_adjust_sr (uint32 target);
extern void cpu_mark_stack (void);
extern void cpu_ea (HP_WORD mode_disp, ACCESS_CLASS *classification, HP_WORD *offset, BYTE_SELECTOR *selector);
extern void cpu_ea (HP_WORD mode_disp, ACCESS_CLASS *class, HP_WORD *offset, BYTE_SELECTOR *selector);
extern uint32 cpu_byte_ea (ACCESS_CLASS class, uint32 byte_offset, uint32 block_length);
extern void cpu_setup_irq_handler (IRQ_CLASS class, HP_WORD parameter);
extern void cpu_setup_ics_irq (IRQ_CLASS class, TRAP_CLASS trap);
extern void cpu_run_mode_interrupt (HP_WORD device_number);
extern void cpu_setup_code_segment (HP_WORD label, HP_WORD* status, HP_WORD *entry_0);
extern void cpu_setup_data_segment (HP_WORD segment_number, HP_WORD *bank, HP_WORD *address);
extern void cpu_call_procedure (HP_WORD label);
extern void cpu_call_procedure (HP_WORD label, HP_WORD offset);
extern void cpu_exit_procedure (HP_WORD new_q, HP_WORD new_sm, HP_WORD parameter);
extern void cpu_start_dispatcher (void);
extern void cpu_update_pclk (void);
@ -1103,7 +1102,8 @@ extern void cpu_update_pclk (void);
/* Global CPU instruction execution routines */
extern t_stat cpu_branch_short (t_bool check_loop);
extern t_bool cpu_interrupt_pending (t_stat *status);
extern t_stat cpu_branch_short (t_bool check_loop);
extern HP_WORD cpu_add_16 (HP_WORD augend, HP_WORD addend);
extern HP_WORD cpu_sub_16 (HP_WORD minuend, HP_WORD subtrahend);
@ -1113,3 +1113,4 @@ extern t_stat cpu_stack_op (void);
extern t_stat cpu_shift_branch_bit_op (void);
extern t_stat cpu_move_spec_fw_imm_field_reg_op (void);
extern t_stat cpu_io_cntl_prog_imm_mem_op (void);
extern t_stat cpu_cis_op (void);

View File

@ -1,6 +1,6 @@
/* hp3000_cpu_base.c: HP 3000 CPU base set instruction simulator
Copyright (c) 2016, J. David Bryan
Copyright (c) 2016-2017, J. David Bryan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -23,6 +23,15 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
08-Jan-17 JDB Fixed bug in SCAL 0/PCAL 0 if a stack overflow occurs
07-Nov-16 JDB SETR doesn't set cpu_base_changed if no register change;
renamed cpu_byte_to_word_ea to cpu_byte_ea
03-Nov-16 JDB Added zero offsets to the cpu_call_procedure calls
24-Oct-16 JDB Renamed SEXT macro to SEXT16
22-Oct-16 JDB Changed "interrupt_pending" to global for use by CIS
07-Oct-16 JDB Moved "extern cpu_dev" to hp3000_cpu.h where it belongs
22-Sep-16 JDB Moved byte_to_word_address to hp3000_cpu.c
21-Sep-16 JDB Added the COBOL II Extended Instruction Set dispatcher
12-Sep-16 JDB Use the PCN_SERIES_II and PCN_SERIES_III constants
23-Aug-16 JDB Implement the CMD instruction and module interrupts
11-Jun-16 JDB Bit mask constants are now unsigned
@ -69,14 +78,10 @@
#include "hp3000_cpu.h"
#include "hp3000_cpu_fp.h"
#include "hp3000_cpu_ims.h"
#include "hp3000_mem.h"
/* External I/O data structures */
extern DEVICE cpu_dev; /* Central Processing Unit */
/* Program constants */
#define SIO_OK 0100000u /* TIO bit 0 = SIO OK */
@ -114,9 +119,7 @@ static void shift_48_64 (HP_WORD opcode, SHIFT_TYPE shift, OPERAND_SI
static void check_stack_bounds (HP_WORD new_value);
static uint32 tcs_io (IO_COMMAND command);
static uint32 srw_io (IO_COMMAND command, HP_WORD ready_flag);
static t_bool interrupt_pending (t_stat *status);
static void decrement_stack (uint32 decrement);
static uint32 byte_to_word_address (ACCESS_CLASS class, uint32 byte_offset, uint32 block_length);
static t_stat move_words (ACCESS_CLASS source_class, uint32 source_base,
ACCESS_CLASS dest_class, uint32 dest_base,
@ -133,6 +136,80 @@ static t_stat io_control (void);
/* CPU base set global utility routines */
/* Test for a pending interrupt.
This routine is called from within an executor for an interruptible
instruction to test for a pending interrupt. It counts an event tick and
returns TRUE if the instruction should yield, either for an interrupt or for
an event error, or FALSE if the instruction should continue.
Instructions that potentially take a long time (e.g., MOVE, SCU, LLSH) test
for pending interrupts after each word or byte moved or scanned. The design
of these instructions is such that an interrupt may be serviced and the
instruction resumed without disruption. For example, the MOVE instruction
updates the source and target addresses and word count on the stack after
each word moved. If the instruction is interrupted, the values on the stack
indicate where to resume after the interrupt handler completes.
Implementation notes:
1. The routine is essentially the same sequence as is performed at the top
of the instruction execution loop in the "sim_instr" routine. The
differences are that this routine backs up P to rerun the instruction
after the interrupt is serviced, and the interrupt holdoff test necessary
for the SED instruction isn't done here, as this routine is not called by
the SED executor.
2. The event interval decrement that occurs in the main instruction loop
after each instruction execution is cancelled here if "sim_process_event"
returns an error code. This is done so that a STEP command does not
decrement sim_interval twice. Note that skipping the initial decrement
here does not help, as it's the sim_interval value AFTER the call to
sim_process_event that must be preserved.
*/
t_bool cpu_interrupt_pending (t_stat *status)
{
uint32 device_number = 0;
sim_interval = sim_interval - 1; /* count the cycle */
if (sim_interval <= 0) { /* if an event timeout expired */
*status = sim_process_event (); /* then process the event service */
if (*status != SCPE_OK) { /* if the service failed */
P = P - 1 & R_MASK; /* then back up to reenter the instruction */
sim_interval = sim_interval + 1; /* and cancel the instruction loop increment */
return TRUE; /* abort the instruction and stop the simulator */
}
}
else /* otherwise */
*status = SCPE_OK; /* indicate good status from the service */
if (sel_request) /* if a selector channel request is pending */
sel_service (1); /* then service it */
if (mpx_request_set) /* if a multiplexer channel request is pending */
mpx_service (1); /* then service it */
if (iop_interrupt_request_set && STA & STATUS_I) /* if a hardware interrupt request is pending and enabled */
device_number = iop_poll (); /* then poll to acknowledge the request */
if (CPX1 & CPX1_IRQ_SET) { /* if an interrupt is pending */
P = P - 1 & R_MASK; /* then back up to reenter the instruction */
cpu_run_mode_interrupt (device_number); /* and set up the service routine */
return TRUE; /* abort the instruction */
}
else /* otherwise */
return FALSE; /* continue with the current instruction */
}
/* Execute a short branch.
The program counter is adjusted by the displacement specified in the CIR, and
@ -259,7 +336,7 @@ HP_WORD cpu_mpy_16 (HP_WORD multiplicand, HP_WORD multiplier)
int32 product;
uint32 check;
product = SEXT (multiplicand) * SEXT (multiplier); /* sign-extend the operands and multiply */
product = SEXT16 (multiplicand) * SEXT16 (multiplier); /* sign-extend the operands and multiply */
check = (uint32) product & S16_OVFL_MASK; /* check the top 17 bits and set overflow */
SET_OVERFLOW (check != 0 && check != S16_OVFL_MASK); /* if they are not all zeros or all ones */
@ -458,7 +535,7 @@ switch (operation) { /* dispatch the stack op
case 013: /* MPYL (CCA, C, O; STUN, ARITH) */
product = SEXT (RA) * SEXT (RB); /* sign-extend the 16-bit operands and multiply */
product = SEXT16 (RA) * SEXT16 (RB); /* sign-extend the 16-bit operands and multiply */
RB = UPPER_WORD (product); /* split the MSW */
RA = LOWER_WORD (product); /* and the LSW of the product */
@ -474,7 +551,7 @@ switch (operation) { /* dispatch the stack op
case 014: /* DIVL (CCA, O; STUN, ARITH) */
dividend = INT32 (TO_DWORD (RC, RB)); /* convert the 32-bit dividend to a signed value */
divisor = SEXT (RA); /* and sign-extend the 16-bit divisor */
divisor = SEXT16 (RA); /* and sign-extend the 16-bit divisor */
RB = RA; /* delete the LSW from the stack now */
cpu_pop (); /* to conform with the microcode */
@ -482,7 +559,7 @@ switch (operation) { /* dispatch the stack op
if (RA == 0) /* if dividing by zero */
MICRO_ABORT (trap_Integer_Zero_Divide); /* then trap or set the overflow flag */
if (abs (divisor) <= abs (SEXT (RB))) /* if the divisor is <= the MSW of the dividend */
if (abs (divisor) <= abs (SEXT16 (RB))) /* if the divisor is <= the MSW of the dividend */
SET_OVERFLOW (TRUE); /* an overflow will occur on the division */
else { /* otherwise, the divisor might be large enough */
@ -558,8 +635,8 @@ switch (operation) { /* dispatch the stack op
if (RA == 0) /* if dividing by zero */
MICRO_ABORT (trap_Integer_Zero_Divide); /* then trap or set the overflow flag */
dividend = SEXT (RB); /* sign-extend the 16-bit dividend */
divisor = SEXT (RA); /* and the 16-bit divisor */
dividend = SEXT16 (RB); /* sign-extend the 16-bit dividend */
divisor = SEXT16 (RA); /* and the 16-bit divisor */
quotient = dividend / divisor; /* form the 32-bit signed quotient */
remainder = dividend % divisor; /* and 32-bit signed remainder */
@ -1142,10 +1219,10 @@ switch (operation) { /* dispatch the shift/br
case 026: /* CPRB (CCE, CCL, CCG; STUN, BNDV) */
if (SEXT (X) < SEXT (RB)) /* if X is less than the lower bound */
if (SEXT16 (X) < SEXT16 (RB)) /* if X is less than the lower bound */
SET_CCL; /* then set CCL and continue */
else if (SEXT (X) > SEXT (RA)) /* otherwise if X is greater than the upper bound */
else if (SEXT16 (X) > SEXT16 (RA)) /* otherwise if X is greater than the upper bound */
SET_CCG; /* then set CCG and continue */
else { /* otherwise lower bound <= X <= upper bound */
@ -1349,7 +1426,7 @@ switch (operation) { /* dispatch the operatio
if (divisor == 0) /* if dividing by zero */
MICRO_ABORT (trap_Integer_Zero_Divide); /* then trap or set the overflow flag */
RA = SEXT (RA) / divisor & R_MASK; /* store the quotient (which cannot overflow) on the TOS */
RA = SEXT16 (RA) / divisor & R_MASK; /* store the quotient (which cannot overflow) on the TOS */
SET_CCA (RA, 0); /* and set the condition code */
break;
@ -1549,7 +1626,7 @@ switch (operation) { /* dispatch the operatio
if (CIR & PSR_SBANK) /* if SBANK is to be set */
SBANK = new_sbank & BA_MASK; /* then update the new value now */
cpu_base_changed = TRUE; /* this instruction changed the base registers */
cpu_base_changed = (CIR != SETR && CIR != SETR_X); /* set the flag if the base registers changed */
break;
} /* all cases are handled */
@ -1656,8 +1733,14 @@ switch (operation) { /* dispatch the operatio
cpu_flush (); /* flush the TOS registers to memory */
if (SM > Z) /* if the stack limit was exceeded */
MICRO_ABORT (trap_Stack_Overflow); /* then trap for a stack overflow */
if (SM > Z) { /* if the stack limit was exceeded */
if (field == 0) { /* then if the label was on the TOS */
cpu_push (); /* then push the stack down */
RA = label; /* and restore the label to the TOS */
}
MICRO_ABORT (trap_Stack_Overflow); /* trap for a stack overflow */
}
if (label & LABEL_EXTERNAL) /* if the label is non-local */
MICRO_ABORTP (trap_STT_Violation, STA); /* then trap for an STT violation */
@ -1685,12 +1768,18 @@ switch (operation) { /* dispatch the operatio
cpu_flush (); /* flush the TOS registers to memory */
if (SM > Z) /* if the stack limit was exceeded */
MICRO_ABORT (trap_Stack_Overflow); /* then trap for a stack overflow */
if (SM > Z) { /* if the stack limit was exceeded */
if (field == 0) { /* then if the label was on the TOS */
cpu_push (); /* then push the stack down */
RA = label; /* and restore the label to the TOS */
}
MICRO_ABORT (trap_Stack_Overflow); /* trap for a stack overflow */
}
cpu_mark_stack (); /* write a stack marker */
cpu_call_procedure (label); /* set up PB, P, PL, and STA to call the procedure */
cpu_call_procedure (label, 0); /* set up PB, P, PL, and STA to call the procedure */
break;
@ -1702,7 +1791,7 @@ switch (operation) { /* dispatch the operatio
new_sm = Q - 4 - field & R_MASK; /* compute the new stack pointer value */
cpu_read_memory (stack_checked, Q, &operand); /* read the delta Q value from the stack marker */
cpu_read_memory (stack, Q, &operand); /* read the delta Q value from the stack marker */
new_q = Q - operand & R_MASK; /* and determine the new Q value */
cpu_exit_procedure (new_q, new_sm, field); /* set up the return code segment and stack */
@ -1755,7 +1844,7 @@ switch (operation) { /* dispatch the operatio
else /* otherwise */
label = LABEL_EXTERNAL /* convert it to an external label */
| (field << LABEL_STTN_SHIFT) /* by merging the STT number */
| STA & STATUS_CS_MASK; /* with the currently executing segment number */
| STATUS_CS (STA); /* with the currently executing segment number */
cpu_push (); /* push the stack down */
RA = label; /* and store the label on the TOS */
@ -2256,7 +2345,7 @@ if (NPRV) /* if the mode is not pr
address = SM + SR - IO_K (CIR) & LA_MASK; /* get the location of the device number */
cpu_read_memory (stack_checked, address, &device); /* read it from the stack */
cpu_read_memory (stack, address, &device); /* read it from the stack or TOS registers */
device = LOWER_BYTE (device); /* and use only the lower byte of the value */
result = iop_direct_io (device, command, /* send the I/O order to the device */
@ -2341,80 +2430,6 @@ else { /* otherwise the device
}
/* Test for a pending interrupt.
This routine is called from within an executor for an interruptible
instruction to test for a pending interrupt. It counts an event tick and
returns TRUE if the instruction should yield, either for an interrupt or for
an event error, or FALSE if the instruction should continue.
Instructions that potentially take a long time (e.g., MOVE, SCU, LLSH) test
for pending interrupts after each word or byte moved or scanned. The design
of these instructions is such that an interrupt may be serviced and the
instruction resumed without disruption. For example, the MOVE instruction
updates the source and target addresses and word count on the stack after
each word moved. If the instruction is interrupted, the values on the stack
indicate where to resume after the interrupt handler completes.
Implementation notes:
1. The routine is essentially the same sequence as is performed at the top
of the instruction execution loop in the "sim_instr" routine. The
differences are that this routine backs up P to rerun the instruction
after the interrupt is serviced, and the interrupt holdoff test necessary
for the SED instruction isn't done here, as this routine is not called by
the SED executor.
2. The event interval decrement that occurs in the main instruction loop
after each instruction execution is cancelled here if "sim_process_event"
returns an error code. This is done so that a STEP command does not
decrement sim_interval twice. Note that skipping the initial decrement
here does not help, as it's the sim_interval value AFTER the call to
sim_process_event that must be preserved.
*/
static t_bool interrupt_pending (t_stat *status)
{
uint32 device_number = 0;
sim_interval = sim_interval - 1; /* count the cycle */
if (sim_interval <= 0) { /* if an event timeout expired */
*status = sim_process_event (); /* then process the event service */
if (*status != SCPE_OK) { /* if the service failed */
P = P - 1 & R_MASK; /* then back up to reenter the instruction */
sim_interval = sim_interval + 1; /* and cancel the instruction loop increment */
return TRUE; /* abort the instruction and stop the simulator */
}
}
else /* otherwise */
*status = SCPE_OK; /* indicate good status from the service */
if (sel_request) /* if a selector channel request is pending */
sel_service (1); /* then service it */
if (mpx_request_set) /* if a multiplexer channel request is pending */
mpx_service (1); /* then service it */
if (iop_interrupt_request_set && STA & STATUS_I) /* if a hardware interrupt request is pending and enabled */
device_number = iop_poll (); /* then poll to acknowledge the request */
if (CPX1 & CPX1_IRQ_SET) { /* if an interrupt is pending */
P = P - 1 & R_MASK; /* then back up to reenter the instruction */
cpu_run_mode_interrupt (device_number); /* and set up the service routine */
return TRUE; /* abort the instruction */
}
else /* otherwise */
return FALSE; /* continue with the current instruction */
}
/* Decrement the stack pointer.
Pop values from the stack until the stack pointer has been decremented by the
@ -2442,87 +2457,6 @@ return;
}
/* Convert a data- or program-relative byte address to a word address.
The supplied byte offset from DB or PB is converted to a memory address,
bounds-checked, and then returned. If the supplied block length is not zero,
the converted address is assumed to be the starting address of a block, and
an ending address, based on the block length, is calculated and
bounds-checked. If either address lies outside of the segment associated
with the access class, a Bounds Violation trap occurs, unless a privileged
data access is requested.
Byte offsets into data segments present problems, in that negative offsets
are permitted (to access the DL-to-DB area), but there are not enough bits to
represent all locations unambiguously in the potential -32K to +32K word
offset range. Therefore, a byte offset with bit 0 = 1 can represent either a
positive or negative word offset from DB, depending on the interpretation.
The HP 3000 adopts the convention that if the address resulting from a
positive-offset interpretation does not fall within the DL-to-S range, then
32K is added to the address, effectively changing the interpretation from a
positive to a negative offset. If this new address does not fall within the
DL-to-S range, a Bounds Violation trap occurs if the mode is non-privileged.
The reinterpretation as a negative offset is performed only if the CPU is not
in split-stack mode (where either DBANK is different from SBANK, or DB does
not lie between DL and Z), as extra data segments do not permit negative-DB
addressing. Reinterpretation is also not used for code segments, as negative
offsets from PB are not permitted.
Implementation notes:
1. This routine implements the DBBC microcode subroutine.
*/
static uint32 byte_to_word_address (ACCESS_CLASS class, uint32 byte_offset, uint32 block_length)
{
uint32 starting_word, ending_word, increment;
if (block_length & D16_SIGN) /* if the block length is negative */
increment = 0177777; /* then the memory increment is negative also */
else /* otherwise */
increment = 1; /* the increment is positive */
if (class == data) { /* if this is a data access */
starting_word = DB + (byte_offset >> 1) & LA_MASK; /* then determine the starting word address */
if (DBANK == SBANK && DL <= DB && DB <= Z /* if not in split-stack mode */
&& (starting_word < DL || starting_word > SM)) { /* and the word address is out of range */
starting_word = starting_word ^ D16_SIGN; /* then add 32K and try again */
if (NPRV && (starting_word < DL || starting_word > SM)) /* if non-privileged and still out of range */
MICRO_ABORT (trap_Bounds_Violation); /* then trap for a bounds violation */
}
if (block_length != 0) { /* if a block length was supplied */
ending_word = /* then determine the ending word address */
starting_word + ((block_length - increment + (byte_offset & 1)) >> 1) & LA_MASK;
if (NPRV && (ending_word < DL || ending_word > SM)) /* if non-privileged and the address is out of range */
MICRO_ABORT (trap_Bounds_Violation); /* then trap for a bounds violation */
}
}
else { /* otherwise this is a program address */
starting_word = PB + (byte_offset >> 1) & LA_MASK; /* so determine the starting word address */
if (starting_word < PB || starting_word > PL) /* if the starting address is out of range */
MICRO_ABORT (trap_Bounds_Violation); /* then trap for a bounds violation */
if (block_length != 0) { /* if a block length was supplied */
ending_word = /* then determine the ending address */
starting_word + ((block_length - increment + (byte_offset & 1)) >> 1) & LA_MASK;
if (ending_word < PB || ending_word > PL) /* if the ending address is out of range */
MICRO_ABORT (trap_Bounds_Violation); /* then trap for a bounds violation */
}
}
return starting_word; /* return the starting word address */
}
/* Move a block of words in memory.
A block of words is moved from a source address to a destination address. If
@ -2602,7 +2536,7 @@ while (RA != 0) { /* while there are words
RB = RB + increment & R_MASK; /* and the source */
*RX = *RX + increment & R_MASK; /* and destination offsets */
if (interrupt_pending (&status)) /* if an interrupt is pending */
if (cpu_interrupt_pending (&status)) /* if an interrupt is pending */
return status; /* then return with an interrupt set up or an error */
}
@ -2629,6 +2563,11 @@ return SCPE_OK; /* and return the succ
| 0 0 1 0 | 0 0 0 0 | special op | 0 0 | sp op | Special
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
Byte move and compare instructions that specify byte counts (e.g., MVB, CMPB)
bounds-check the starting and ending addresses to avoid checking each access
separately. Instructions that do not (e.g., SCW, MVBW) must bounds-check
each access, as the counts are indeterminate.
Implementation notes:
@ -2788,13 +2727,17 @@ switch (operation) { /* dispatch the move or
else /* otherwise */
increment = 1; /* the increment is positive */
if (CIR & DB_FLAG) /* if the move is from the data segment */
class = data; /* then classify as a data access */
else /* otherwise the move is from the code segment */
class = program; /* so classify as a program access */
if (CIR & DB_FLAG) { /* if the move is from the data segment */
class = data; /* then classify as a data access */
source = cpu_byte_ea (data_checked, RB, RA); /* and convert and check the byte address */
}
source = byte_to_word_address (class, RB, RA); /* convert the source byte address and check bounds */
target = byte_to_word_address (data, RC, RA); /* convert the target byte address and check bounds */
else { /* otherwise the move is from the code segment */
class = program; /* so classify as a program access */
source = cpu_byte_ea (program_checked, RB, RA); /* and convert and check the byte address */
}
target = cpu_byte_ea (data_checked, RC, RA); /* convert the target byte address and check the bounds */
while (RA != 0) { /* while there are bytes to move */
cpu_read_memory (class, source, &operand); /* read a source word */
@ -2823,7 +2766,7 @@ switch (operation) { /* dispatch the move or
RB = RB + increment & R_MASK; /* and the source */
RC = RC + increment & R_MASK; /* and destination offsets */
if (interrupt_pending (&status)) /* if an interrupt is pending */
if (cpu_interrupt_pending (&status)) /* if an interrupt is pending */
return status; /* then return with an interrupt set up or an error */
}
}
@ -2872,13 +2815,13 @@ switch (operation) { /* dispatch the move or
test_byte = LOWER_BYTE (RA); /* get the test byte */
terminal_byte = UPPER_BYTE (RA); /* and the terminal byte */
source = byte_to_word_address (data, RB, 0); /* convert the source byte address and check the bounds */
source = cpu_byte_ea (data_checked, RB, 0); /* convert the source byte address and check the bounds */
cpu_read_memory (data, source, &operand); /* read the first word */
while (TRUE) {
if (RB & 1) { /* if the byte address is odd */
if (interrupt_pending (&status)) /* then if an interrupt is pending */
if (cpu_interrupt_pending (&status)) /* then if an interrupt is pending */
return status; /* then return with an interrupt set up or an error */
byte = LOWER_BYTE (operand); /* get the lower byte */
@ -3000,8 +2943,8 @@ switch (operation) { /* dispatch the move or
while (SR > 2) /* if more than two TOS registers are valid */
cpu_queue_down (); /* then queue them down until exactly two are left */
source = byte_to_word_address (data, RA, 0); /* convert the source */
target = byte_to_word_address (data, RB, 0); /* and target byte addresses and check the bounds */
source = cpu_byte_ea (data_checked, RA, 0); /* convert the source and target */
target = cpu_byte_ea (data_checked, RB, 0); /* byte addresses and check the starting bounds */
if (source > target) { /* if the source is closer to SM than the target */
byte_count = (int32) (SM - source + 1) * 2; /* then set the byte count from the source */
@ -3057,7 +3000,7 @@ switch (operation) { /* dispatch the move or
RA = RA + 1 & R_MASK; /* and the source */
RB = RB + 1 & R_MASK; /* and destination offsets */
if (interrupt_pending (&status)) /* if an interrupt is pending */
if (cpu_interrupt_pending (&status)) /* if an interrupt is pending */
return status; /* then return with an interrupt set up or an error */
}
@ -3080,13 +3023,17 @@ switch (operation) { /* dispatch the move or
else /* otherwise */
increment = 1; /* the increment is positive */
if (CIR & DB_FLAG) /* if the move is from the data segment */
class = data; /* then classify as a data access */
else /* otherwise the move is from the code segment */
class = program; /* so classify as a program access */
if (CIR & DB_FLAG) { /* if the comparison is from the data segment */
class = data; /* then classify as a data access */
source = cpu_byte_ea (data_checked, RB, RA); /* and convert and check the byte address */
}
source = byte_to_word_address (class, RB, RA); /* convert the source byte address and check bounds */
target = byte_to_word_address (data, RC, RA); /* convert the target byte address and check bounds */
else { /* otherwise the comparison is from the code segment */
class = program; /* so classify as a program access */
source = cpu_byte_ea (program_checked, RB, RA); /* and convert and check the byte address */
}
target = cpu_byte_ea (data_checked, RC, RA); /* convert the target byte address and check the bounds */
while (RA != 0) { /* while there are bytes to compare */
cpu_read_memory (class, source, &operand); /* read a source word */
@ -3116,7 +3063,7 @@ switch (operation) { /* dispatch the move or
RB = RB + increment & R_MASK; /* and the source */
RC = RC + increment & R_MASK; /* and destination offsets */
if (interrupt_pending (&status)) /* if an interrupt is pending */
if (cpu_interrupt_pending (&status)) /* if an interrupt is pending */
return status; /* then return with an interrupt set up or an error */
}
}
@ -3160,7 +3107,7 @@ switch (operation) { /* dispatch the move or
X = X - 1 & R_MASK; /* decrement the count */
if (interrupt_pending (&status)) /* if an interrupt is pending */
if (cpu_interrupt_pending (&status)) /* if an interrupt is pending */
return status; /* then return with an interrupt set up or an error */
}
@ -3182,14 +3129,14 @@ switch (operation) { /* dispatch the move or
if (PRIV) /* if the mode is privileged */
if (CIR & 1) { /* PSTA (none; STUN, MODE) */
PREADJUST_SR (1); /* ensure a valid TOS register */
cpu_write_memory (absolute_checked, /* before writing the TOS to memory */
cpu_write_memory (absolute_mapped, /* before writing the TOS to memory */
X, RA); /* at address X */
cpu_pop (); /* and popping the stack */
}
else { /* PLDA (CCA; STOV, MODE) */
cpu_read_memory (absolute_checked, /* read the value at address X */
X, &operand);
cpu_read_memory (absolute_mapped, /* read the value at address X */
X, &operand);
cpu_push (); /* push the stack down */
RA = operand; /* and store the value on the TOS */
@ -3213,7 +3160,7 @@ switch (operation) { /* dispatch the move or
cpu_queue_down (); /* then queue them down until exactly two are left */
address = TO_PA (RB, RA); /* form the physical address */
cpu_read_memory (absolute_checked, /* and read the word from memory */
cpu_read_memory (absolute, /* and read the word from memory */
address, &operand);
cpu_push (); /* push the stack down */
@ -3230,7 +3177,7 @@ switch (operation) { /* dispatch the move or
cpu_queue_down (); /* then queue them down until exactly three are left */
address = TO_PA (RC, RB); /* form the physical address */
cpu_write_memory (absolute_checked, /* and write the word on the TOS to memory */
cpu_write_memory (absolute, /* and write the word on the TOS to memory */
address, RA);
cpu_pop (); /* pop the TOS */
@ -3242,15 +3189,14 @@ switch (operation) { /* dispatch the move or
cpu_queue_down (); /* then queue them down until exactly two are left */
address = TO_PA (RB, RA); /* form the physical address */
cpu_read_memory (absolute_checked, /* and read the MSW from memory */
cpu_read_memory (absolute, /* and read the MSW from memory */
address, &operand);
cpu_push (); /* push the stack down */
RA = operand; /* and store the MSW on the TOS */
address = TO_PA (RC, RB + 1 & LA_MASK); /* increment the physical address */
cpu_read_memory (absolute_checked, /* read the LSW from memory */
cpu_read_memory (absolute, /* and read the LSW from memory */
address, &operand);
cpu_push (); /* push the stack down again */
@ -3264,12 +3210,11 @@ switch (operation) { /* dispatch the move or
PREADJUST_SR (4); /* ensure there are four valid TOS registers */
address = TO_PA (RD, RC); /* form the physical address */
cpu_write_memory (absolute_checked, /* write the MSW from the NOS to memory */
cpu_write_memory (absolute, /* write the MSW from the NOS to memory */
address, RB);
address = TO_PA (RD, RC + 1 & LA_MASK); /* increment the physical address */
cpu_write_memory (absolute_checked, /* write the LSW on the TOS to memory */
cpu_write_memory (absolute, /* and write the LSW on the TOS to memory */
address, RA);
cpu_pop (); /* pop the TOS */
@ -3302,7 +3247,7 @@ switch (operation) { /* dispatch the move or
new_q = 0; /* but the compiler doesn't realize this and so warns */
if (!disp_active) { /* if not called by the dispatcher to start a process */
if ((STA & STATUS_CS_MASK) > 1) { /* then if an external interrupt was serviced */
if (STATUS_CS (STA) > 1) { /* then if an external interrupt was serviced */
cpu_read_memory (stack, /* then get the device number (parameter) */
Q + 3 & LA_MASK,
&device);
@ -3465,11 +3410,15 @@ return status; /* return the execution
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 0 1 0 | 0 0 0 1 | 0 1 1 1 1 0 0 | x | DMUL/DDIV
| 0 0 1 0 | 0 0 0 1 | 0 1 1 1 | 1 0 0 | x | DMUL/DDIV
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 0 1 0 | 0 0 0 1 | 0 0 0 0 1 | ext fp op | Extended FP
| 0 0 1 0 | 0 0 0 1 | 0 0 0 0 | 1 | ext fp op | Extended FP
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| 0 0 1 0 | 0 0 0 1 | 0 0 1 1 | COBOL op | COBOL
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
@ -3491,19 +3440,16 @@ return status; /* return the execution
W1 0000 020400-020417 Extended Instruction Set (Floating Point)
W2 0001 020420-020437 32105A APL Instruction Set
W3 0010 020440-020457
W4 0011 020460-020477 32234A COBOL II Instruction Set
W4 0011 020460-020477 32234A COBOL II Extended Instruction Set
W5 0100 020500-020517
W6 0101 020520-020537
W7 0110 020540-020557
-- 0111 020560-020577 Base Set (DMUL/DDIV)
W8 1000 020600-020777 Extended Instruction Set (Decimal Arith)
W8 1xxx 020600-020777 Extended Instruction Set (Decimal Arith)
The range occupied by the base set has no jumper and is hardwired as
"present".
In simulation, presence is determined by the settings of the CPU unit flags.
Currently, the only defined option flag is UNIT_EIS, although the EIS itself
has not been implemented.
"present". In simulation, presence is determined by the settings of the CPU
unit flags.
Implementation notes:
@ -3525,6 +3471,14 @@ operation = FIRMEXTOP (CIR); /* get the operation fro
switch (operation) { /* dispatch the operation */
case 003: /* COBOL II Extended Instruction Set */
if (cpu_unit [0].flags & UNIT_CIS) /* if the firmware is installed */
status = cpu_cis_op (); /* then call the CIS dispatcher */
else /* otherwise */
status = STOP_UNIMPL; /* the instruction range decodes as unimplemented */
break;
case 007: /* base set */
suboperation = FMEXSUBOP (CIR); /* get the suboperation from the instruction */
@ -3915,11 +3869,11 @@ switch (operation) { /* dispatch the I/O or c
case 006: /* XEQ (none; BNDV) */
address = SM + SR - IO_K (CIR) & LA_MASK; /* get the address of the target instruction */
if (address >= DB || PRIV) { /* if the address is not below DB or the mode is privileged */
cpu_read_memory (stack_checked, address, &NIR); /* the read the word at S - K into the NIR */
if (address >= DB || PRIV) { /* if the address is not below DB or the mode is privileged */
cpu_read_memory (stack, address, &NIR); /* then read the word at S - K into the NIR */
P = P - 1 & R_MASK; /* decrement P so the instruction after XEQ is next */
sim_interval = sim_interval + 1; /* but don't count the XEQ against a STEP count */
P = P - 1 & R_MASK; /* decrement P so the instruction after XEQ is next */
sim_interval = sim_interval + 1; /* but don't count the XEQ against a STEP count */
}
else /* otherwise the address is below DB and not privileged */
@ -3975,8 +3929,8 @@ switch (operation) { /* dispatch the I/O or c
if (NPRV) /* if the mode is not privileged */
MICRO_ABORT (trap_Privilege_Violation); /* then abort with a privilege violation */
address = SM + SR - IO_K (CIR) & LA_MASK; /* get the location of the command word */
cpu_read_memory (stack_checked, address, &command); /* and read it from the stack */
address = SM + SR - IO_K (CIR) & LA_MASK; /* get the location of the command word */
cpu_read_memory (stack, address, &command); /* and read it from the stack or TOS registers */
module = CMD_TO (command); /* get the addressed (TO) module number */

1970
HP3000/hp3000_cpu_cis.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
10-Oct-16 JDB Moved cpu_read_memory, cpu_write_memory to hp3000_cpu.h
01-Sep-16 JDB Added the cpu_cold_cmd and cpu_power_cmd routines
15-Aug-16 JDB Removed obsolete comment mentioning iop_read/write_memory
15-Jul-16 JDB Corrected the IOCW_COUNT macro to return the correct value
@ -146,16 +147,11 @@ typedef enum {
cpu_cold_cmd : process the LOAD and DUMP commands
cpu_power_cmd : process the POWER commands
cpu_read_memory : read a word from main memory
cpu_write_memory : write a word to main memory
*/
extern t_stat cpu_cold_cmd (int32 arg, CONST char *buf);
extern t_stat cpu_power_cmd (int32 arg, CONST char *buf);
extern t_bool cpu_read_memory (ACCESS_CLASS classification, uint32 offset, HP_WORD *value);
extern t_bool cpu_write_memory (ACCESS_CLASS classification, uint32 offset, HP_WORD value);
/* Global SIO order structures.

View File

@ -23,6 +23,10 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
29_Dec-16 JDB Changed the status mnemonic flag from REG_S to REG_T
20-Nov-16 JDB Added mapped memory access classes
24-Oct-16 JDB Added half-byte definitions for CIS decoding
10-Oct-16 JDB Moved ACCESS_CLASS definition here from hp3000_cpu.h
03-Sep-16 JDB Added the STOP_POWER and STOP_ARSINH codes
13-May-16 JDB Modified for revised SCP API function parameter types
21-Mar-16 JDB Changed uint16 types to HP_WORD
@ -107,10 +111,6 @@
#ifndef HP3000_DEFS_H_
#define HP3000_DEFS_H_
#include "sim_rev.h"
#include "sim_defs.h"
@ -150,7 +150,7 @@
#define REG_A (1u << REG_V_UF + 0) /* permit any display */
#define REG_B (1u << REG_V_UF + 1) /* permit binary display */
#define REG_M (1u << REG_V_UF + 2) /* default to instruction mnemonic display */
#define REG_S (1u << REG_V_UF + 3) /* default to status mnemonic display */
#define REG_T (1u << REG_V_UF + 3) /* default to status mnemonic display */
/* Register macros.
@ -264,21 +264,24 @@
printf (__VA_ARGS__); \
if (sim_log) \
fprintf (sim_log, __VA_ARGS__); \
} while (0)
} \
while (0)
#define cputs(str) \
do { \
fputs (str, stdout); \
if (sim_log) \
fputs (str, sim_log); \
} while (0)
} \
while (0)
#define cputc(ch) \
do { \
putc (ch); \
if (sim_log) \
fputc (ch, sim_log); \
} while (0)
} \
while (0)
/* Simulation stop codes.
@ -396,6 +399,9 @@ typedef uint32 HP_WORD; /* HP 16-bit data word r
#define R_MASK 0177777u /* 16-bit register mask */
#define D4_WIDTH 4 /* 4-bit data bit width */
#define D4_MASK 0017u /* 4-bit data mask */
#define D8_WIDTH 8 /* 8-bit data bit width */
#define D8_MASK 0377u /* 8-bit data mask */
#define D8_UMAX 0377u /* 8-bit unsigned maximum value */
@ -481,6 +487,67 @@ typedef uint32 HP_WORD; /* HP 16-bit data word r
#define TO_OFFSET(p) ((p) & LA_MASK)
/* Memory access classifications.
The access classification determines which bank register is used with the
supplied offset to access memory, whether or not the access is bounds
checked, and whether or not the access is mapped to the TOS registers if the
address is between SM and SM + SR.
Bounds checking is optionally performed on program (including instruction
fetch), data, and stack accesses when not in privileged mode. Absolute
addresses are always accessed in privileged mode, so bounds checking is never
performed.
If the memory address lies between SM and SM + SR within the stack bank, then
access to the TOS registers may be substituted for access to memory.
Register mapping is always performed on stack accesses, optionally performed
on absolute and data accesses, and is never performed on program (and fetch)
accesses.
To summarize bounds checking and TOS register mapping:
Bounds TOS
Access Check Mapping
-------- ------ -------
absolute N O
fetch O N
program O N
data O O
stack O Y
dma N N
Implementation notes:
1. The enumeration values must be ordered such that the "checked" classes
are odd and differ from their corresponding "unchecked" classes only in
the LSBs.
2. There is no hardware DMA bank register. The "dma" class exists only to
differentiate DMA memory accesses from CPU memory accesses when tracing.
*/
typedef enum {
absolute, /* absolute bank */
absolute_mapped, /* absolute bank, TOS registers mapped */
fetch, /* program bank, instruction fetch */
fetch_checked, /* program bank, instruction fetch, bounds checked */
program, /* program bank, data access */
program_checked, /* program bank, data access, bounds checked */
data, /* data bank, data access */
data_checked, /* data bank, data access, bounds checked */
data_mapped, /* data bank, data or TOS register access */
data_mapped_checked, /* data bank, data or TOS register access, bounds checked */
stack, /* stack bank, data or TOS register access */
stack_checked, /* stack bank, data or TOS register access, bounds checked */
dma /* DMA bank */
} ACCESS_CLASS;
#define UNCHECKED(c) ((c) & ~1u) /* reclassify a request as unchecked */
#define INVERT_CHECK(c) ((c) ^ 1u) /* convert checked to unchecked and vice versa */
/* Portable conversions.
SIMH is written with the assumption that the defined-size types (e.g.,
@ -495,11 +562,13 @@ typedef uint32 HP_WORD; /* HP 16-bit data word r
The conversions available are:
- SEXT -- int16 sign-extended to int32
- NEG16 -- int16 negated
- NEG32 -- int32 negated
- INT16 -- uint16 to int16
- INT32 -- uint32 to int32
- SEXT8 -- int8 sign-extended to int32
- SEXT16 -- int16 sign-extended to int32
- NEG16 -- int8 negated
- NEG16 -- int16 negated
- NEG32 -- int32 negated
- INT16 -- uint16 to int16
- INT32 -- uint32 to int32
Implementation notes:
@ -508,8 +577,10 @@ typedef uint32 HP_WORD; /* HP 16-bit data word r
before invoking.
*/
#define SEXT(x) (int32) ((x) & D16_SIGN ? (x) | ~D16_MASK : (x))
#define SEXT8(x) (int32) ((x) & D8_SIGN ? (x) | ~D8_MASK : (x))
#define SEXT16(x) (int32) ((x) & D16_SIGN ? (x) | ~D16_MASK : (x))
#define NEG8(x) ((~(x) + 1) & D8_MASK)
#define NEG16(x) ((~(x) + 1) & D16_MASK)
#define NEG32(x) ((~(x) + 1) & D32_MASK)
@ -517,6 +588,12 @@ typedef uint32 HP_WORD; /* HP 16-bit data word r
#define INT32(u) ((u) > D32_SMAX ? (-(int32) (D32_UMAX - (u)) - 1) : (int32) (u))
/* Half-byte accessors */
#define UPPER_HALF(b) ((b) >> D4_WIDTH & D4_MASK)
#define LOWER_HALF(b) ((b) & D4_MASK)
/* Byte accessors.
These macros extract the upper and lower bytes from a word and form a word
@ -614,8 +691,8 @@ extern const BITSET_FORMAT inbound_format; /* the inbound signal format str
extern const BITSET_FORMAT outbound_format; /* the outbound signal format structure */
/* System interface global SCP support routines previously declared in scp.h */
/*
/* System interface global SCP support routines declared in scp.h
extern t_stat sim_load (FILE *fptr, CONST char *cptr, CONST char *fnam, int flag);
extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 sw);
extern t_stat parse_sym (CONST char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw);
@ -629,14 +706,12 @@ extern t_stat hp_show_dib (FILE *st, UNIT *uptr, int32 code, CONST void
/* System interface global utility routines */
extern t_bool hp_device_conflict (void);
extern t_stat fprint_cpu (FILE *ofile, t_value *val, uint32 radix, int32 switches);
extern t_stat fprint_cpu (FILE *ofile, t_value *val, uint32 radix, int32 switches);
extern uint32 fprint_edit (FILE *ofile, t_value *val, uint32 radix, uint32 byte_address);
extern const char *fmt_status (uint32 status);
extern const char *fmt_char (uint32 charval);
extern const char *fmt_bitset (uint32 bitset, const BITSET_FORMAT bitfmt);
extern void hp_debug (DEVICE *dptr, uint32 flag, ...);
#endif
extern void hp_debug (DEVICE *dptr, uint32 flag, ...);
extern t_bool hp_device_conflict (void);

View File

@ -1,6 +1,6 @@
SIMH/HP 3000 DIAGNOSTICS PERFORMANCE
====================================
Last update: 2016-09-07
Last update: 2016-12-01
The HP 32230 diagnostic suite has been run against the SIMH HP 3000 simulation.
@ -60,8 +60,8 @@ The results of the diagnostic runs are summarized below:
PD435A Universal Interface 01.01 Passed
PD438A Terminal Control Interface 01.00 Passed
PD439A CALCOMP Plotter Interface 01.01 No simulation
PD441A COBOL-II A Firmware 00.00 No simulation
PD442A COBOL-II B Firmware 00.00 No simulation
PD441A COBOL-II A Firmware 00.00 Passed
PD442A COBOL-II B Firmware 00.00 Passed
PD466A Online Line Printer Verifier 01.06 Passed
The "Result" column indicates the level of success in passing the given
@ -1548,7 +1548,9 @@ CONFIGURATION: sim> set lp diagnostic,intmask=8
sim> set clk realtime
sim> go
TEST REPORT: D100 UNIV. INTERFACE TEST (HP D435A.01.01)
TEST REPORT: [CR entered]
D100 UNIV. INTERFACE TEST (HP D435A.01.01)
(C)COPYRIGHT HEWLETT PACKARD COMPANY 1976.
****************** WARNING ******************
this diagnostic has tests which will produce error
@ -1852,6 +1854,239 @@ TEST RESULT: Passed.
---------------------------
D441A - COBOL-II A Firmware
---------------------------
TESTED DEVICE: CPU (hp3000_cpu.c)
CONFIGURATION: sim> set cpu cis
sim> go
TEST REPORT: [CTRL+E]
sim> deposit SWCH 100011
sim> go
[CR entered]
COBOLIIA F/W DIAG. (D441A.00.00)
TESTING MFL OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
MFL OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING MC'N OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
MCN OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING IC AND SUFT OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
IC OF EDIT PASSED ALL TESTS WITHOUT ERROR
SUFT OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING MA'N OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
MA OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING ICS AND SST0 AND SST1 OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
ICS OF EDIT PASSED ALL TESTS WITHOUT ERROR
SST0 OF EDIT PASSED ALL TESTS WITHOUT ERROR
SST1 OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING ICI OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
ICI OF EDIT PASSED ALL TESTS WITHOUT ERROR
BRIS OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING MN'N OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
MN OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING SFC AND ICSI OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
SFC OF EDIT PASSED ALL TESTS WITHOUT ERROR
ICSI OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING MNS OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
MNS OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING DBNZ AND SETC OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
DBNZ OF EDIT PASSED ALL TESTS WITHOUT ERROR
SETC OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING MDWO AND SUFS OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
MDWO OF EDIT PASSED ALL TESTS WITHOUT ERROR
SUFS OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING ICP OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
ICP OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING ICPS OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
ICPS OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING "IS" OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
"IS" OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
TESTING "ENDF" OF EDIT
TESTING "SFLC" OF EDIT
TESTING "DFLC" OF EDIT
PB'DB'MODE= 0
PB'DB'MODE= 1
"ENDF" OF EDIT PASSED ALL TESTS WITHOUT ERROR
"SFLC" OF EDIT PASSED ALL TESTS WITHOUT ERROR
"DFLC" OF EDIT PASSED ALL TESTS WITHOUT ERROR
********************************************************************************
END OF PASS 0
Programmed halt, CIR: 030375 (HALT 15), P: 010330 (RSW)
TEST RESULT: Passed.
---------------------------
D442A - COBOL-II B Firmware
---------------------------
TESTED DEVICE: CPU (hp3000_cpu.c)
CONFIGURATION: sim> set cpu cis
sim> go
TEST REPORT: [CTRL+E]
sim> deposit SWCH 100011
sim> go
[CR entered]
COBOLIIB FIRMWARE DIAGNOSTIC (D442A.00.00)
TESTING ABSD
ABSD PASSED ALL TESTS WITHOUT ERROR
TESTING ABSN
ABSN PASSED ALL TESTS WITHOUT ERROR
TESTING XBR
XBR PASSED ALL TESTS WITHOUT ERROR
TESTING NEGD
SDEC= 0
SDEC= 1
NEGD PASSED ALL TESTS WITHOUT ERROR
TESTING PARC AND ENDP
I AM IN OUTER'BLOCK OF PARC
I AM IN PAR6
I AM IN OUTER'BLOCK OF PARC
PARC AND ENDP PASSED ALL TESTS WITHOUT ERROR
TESTING TR
TESTING DB TABLE ACCESS
TESTING PB TABLE ACCESS
TR PASSED ALL TESTS WITHOUT ERROR
TESTING CVND
SDEC = 0
SDEC = 1
CVND PASSED ALL TESTS WITHOUT ERROR
TESTING CMPS
TESTING DB-TARGET ACCESS
TESTING PB-TARGET ACCESS
CMPS PASSED ALL TESTS WITHOUT ERROR
TESTING CMPT
TESTING TRANSLATION TABLE IN PB
TESTING DB-TARGET ACCESS
TESTING PB-TARGET ACCESS
CMPT PASSED ALL TESTS WITHOUT ERRORS
TESTING TCCS
TCCS PASSED ALL TESTS WITHOUT ERROR
TESTING LDW
SDEC=0
SDEC=1
TESTING LDDW
SDEC=0
SDEC=1
LDW AND LDWW PASSED ALL TESTS WITHOUT ERROR
TESTING ALGN
ALGN PASSED ALL TESTS WITHOUT ERROR
END OF PASS 0
Programmed halt, CIR: 030375 (HALT 15), P: 010315 (RSW)
TEST RESULT: Passed.
------------------------------------
D466A - Online Line Printer Verifier
------------------------------------

View File

@ -25,6 +25,7 @@
IOP HP 3000 Series III I/O Processor
10-Oct-16 JDB Renumbered debug flags to start at bit 0
03-Sep-16 JDB Added "iop_assert_PFWARN" to warn devices of power loss
01-Aug-16 JDB Added "iop_reset" to initialize the IOP
30-Jun-16 JDB Changed REG type of filter array to BRDATA
@ -174,6 +175,7 @@
#include "hp3000_cpu.h"
#include "hp3000_cpu_ims.h"
#include "hp3000_io.h"
#include "hp3000_mem.h"
@ -188,15 +190,10 @@
the trace stream. It returns the bit in the filter array corresponding to
the device number. If the bit is set, the trace will be generated;
otherwise, it will be suppressed.
Implementation notes:
1. Bit 0 is reserved for the memory data trace flag.
*/
#define DEB_DIO (1u << 1) /* trace direct I/O commands */
#define DEB_IRQ (1u << 2) /* trace interrupt requests */
#define DEB_DIO (1u << 0) /* trace direct I/O commands */
#define DEB_IRQ (1u << 1) /* trace interrupt requests */
#define FILTER(d) (1u << (d) % 32 & filter [(d) / 32])

1051
HP3000/hp3000_mem.c Normal file

File diff suppressed because it is too large Load Diff

162
HP3000/hp3000_mem.h Normal file
View File

@ -0,0 +1,162 @@
/* hp3000_mem.h: HP 3000 memory subsystem interface declarations
Copyright (c) 2016, J. David Bryan
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 THE
AUTHOR 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 the author shall not be used
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the author.
10-Oct-16 JDB Created
This file contains declarations used by the CPU, I/O Processor, Multiplexer
Channel, and Selector Channel to interface with the HP 3000 memory subsystem.
*/
/* Debug flags.
Implementation notes:
1. Memory debug flags are allocated in descending order, as they may be used
by other modules (e.g., CPU) that allocate their own flags in ascending
order. No check is made for overlapping values.
*/
#define DEB_MDATA (1u << 31) /* trace memory reads and writes */
#define DEB_MFETCH (1u << 30) /* trace memory instruction fetches */
#define DEB_MOPND (1u << 29) /* trace memory operand accesses */
/* Architectural constants.
The type used to represent a main memory word value is defined. An array of
this type is used to simulate the CPU main memory.
Implementation notes:
1. The MEMORY_WORD type is a 16-bit unsigned type, corresponding with the
16-bit main memory in the HP 3000. Unlike the general data type, which
is a 32-bit type for speed, main memory does not benefit from the faster
32-bit execution on IA-32 processors, as only one instruction in the
cpu_read_memory and cpu_write_memory routines has an operand override
that invokes the slower instruction fetch path. There is a negligible
difference in the Memory Pattern Test diagnostic execution speeds for the
uint32 vs. uint16 definition, whereas the VM requirements are doubled for
the former.
*/
typedef uint16 MEMORY_WORD; /* HP 16-bit memory word representation */
/* Byte accessors.
The HP 3000 is a word-addressable machine. Byte addressing is implemented by
assuming that a memory of N physical words may be addressed as 2N bytes. The
"byte-capable" machine instructions use "relative byte addresses" that are
used to obtain absolute word addresses by dividing by two and then accessing
the upper or lower byte of the resulting word, depending on the LSB of the
byte address.
In simulation, this module provides a byte access structure and a set of
routines that read or write the next byte in ascending byte-offset order.
The structure is initialized with the starting byte offset from a specified
base register value and then is passed as a parameter to the other routines,
which update the fields accordingly for the access requested. This relieves
the caller from having to manage the continual logical-to-physical address
translation, word buffering, byte selection, etc.
Byte accessors are also used to provide debug traces of byte operands in
memory. Initializing an accessor sets a field containing the absolute byte
memory address; this address may be passed to the byte formatters to print
the operand.
In most cases, operands are defined by starting byte addresses and byte
counts. However, some operands (e.g., EDIT instruction operands) are
delineated only by the extents of the accesses. For these operands, byte
accessors maintain the lowest byte addresses and offsets actually accessed,
as well as the lengths of the extent of the accesses.
*/
typedef struct { /* byte access descriptor */
HP_WORD *byte_offset; /* relative byte offset of the next byte */
HP_WORD data_word; /* memory data word containing the current byte */
ACCESS_CLASS class; /* memory access classification */
uint32 word_address; /* logical word address containing the next byte */
t_bool write_needed; /* TRUE if the data word must be written to memory */
uint32 count; /* current count of bytes accessed */
uint32 length; /* (trace) length of extent of access */
uint32 initial_byte_address; /* (trace) initial absolute byte address */
uint32 initial_byte_offset; /* (trace) initial relative byte offset */
uint32 first_byte_address; /* (trace) lowest absolute byte address accessed */
uint32 first_byte_offset; /* (trace) lowest relative byte offset accessed */
} BYTE_ACCESS;
/* Memory global SCP support routines */
t_stat mem_examine (t_value *eval_array, t_addr address, UNIT *uptr, int32 switches);
t_stat mem_deposit (t_value value, t_addr address, UNIT *uptr, int32 switches);
/* Global memory functions.
mem_initialize : allocate main memory
mem_is_empty : check for a non-zero value within a range of memory locations
mem_fill : set all memory locations to a specified value
mem_read : read a word from main memory
mem_write : write a word to main memory
mem_init_byte : initialize a memory byte access structure
mem_set_byte : set the access structure to a new byte offset
mem_lookup_byte : return a byte at a specified index in a table
mem_read_byte : read the next byte from memory
mem_write_byte : write the next byte to memory
mem_modify_byte : replace the last byte written to memory
mem_post_byte : post the word containing the last byte modified in place to memory
mem_update_byte : rewrite the word containing the last byte written to memory
fmt_byte_operand : format a byte operand in memory into a character string
fmt_bcd_operand : format a BCD operand in memory into a character string
*/
extern t_bool mem_initialize (uint32 memory_size);
extern t_bool mem_is_empty (uint32 starting_address);
extern void mem_fill (uint32 starting_address, HP_WORD fill_value);
extern t_bool mem_read (DEVICE *dptr, ACCESS_CLASS classification, uint32 offset, HP_WORD *value);
extern t_bool mem_write (DEVICE *dptr, ACCESS_CLASS classification, uint32 offset, HP_WORD value);
extern void mem_init_byte (BYTE_ACCESS *bap, ACCESS_CLASS class, HP_WORD *byte_offset, uint32 block_length);
extern void mem_set_byte (BYTE_ACCESS *bap);
extern uint8 mem_lookup_byte (BYTE_ACCESS *bap, uint8 index);
extern uint8 mem_read_byte (BYTE_ACCESS *bap);
extern void mem_write_byte (BYTE_ACCESS *bap, uint8 byte);
extern void mem_modify_byte (BYTE_ACCESS *bap, uint8 byte);
extern void mem_post_byte (BYTE_ACCESS *bap);
extern void mem_update_byte (BYTE_ACCESS *bap);
extern char *fmt_byte_operand (uint32 byte_address, uint32 byte_count);
extern char *fmt_translated_byte_operand (uint32 byte_address, uint32 byte_count, uint32 table_address);
extern char *fmt_bcd_operand (uint32 byte_address, uint32 digit_count);

View File

@ -25,6 +25,7 @@
MPX HP 3000 Series III Multiplexer Channel
24-Oct-16 JDB Renamed SEXT macro to SEXT16
12-Sep-16 JDB Changed DIB register macro usage from SRDATA to DIB_REG
15-Jul-16 JDB Fixed the word count display for DREADSTB trace
08-Jun-16 JDB Corrected %d format to %u for unsigned values
@ -322,12 +323,23 @@
#include "hp3000_defs.h"
#include "hp3000_cpu.h"
#include "hp3000_cpu_ims.h"
#include "hp3000_io.h"
#include "hp3000_mem.h"
/* IOP device */
extern DEVICE iop_dev; /* I/O Processor */
/* Memory access macros */
#define iop_read_memory(c,o,v) mem_read (&iop_dev, c, o, v)
#define iop_write_memory(c,o,v) mem_write (&iop_dev, c, o, v)
/* Program constants.
The multiplexer channel clock period is 175 nanoseconds. The channel runs
@ -1230,8 +1242,8 @@ while (cycles > 0) { /* execute as long as cy
else /* otherwise */
inbound_signals = NO_SIGNALS; /* no acknowledgement is needed */
cpu_read_memory (absolute_iop, addr_reg, &iocw); /* fetch the IOCW from memory */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
iop_read_memory (absolute, addr_reg, &iocw); /* fetch the IOCW from memory */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
order_reg = IOCW_ORDER (iocw); /* get the translated order from the IOCW */
@ -1326,25 +1338,25 @@ while (cycles > 0) { /* execute as long as cy
break;
}
if (store_ioaw == FALSE) { /* if a fetch is needed */
cpu_read_memory (absolute_iop, addr_reg, &ioaw); /* then load the IOAW from memory */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
if (store_ioaw == FALSE) { /* if a fetch is needed */
iop_read_memory (absolute, addr_reg, &ioaw); /* then load the IOAW from memory */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
dprintf (mpx_dev, DEB_PIO, "Channel SR %u loaded IOAW %06o from address %06o\n",
srn, ioaw, addr_reg);
}
else /* otherwise provide a dummy value */
ioaw = 0; /* that will be overwritten */
else /* otherwise provide a dummy value */
ioaw = 0; /* that will be overwritten */
if (inbound_signals) /* if there are signals to assert */
outbound = dibptr->io_interface (dibptr, /* then pass them to the interface */
if (inbound_signals) /* if there are signals to assert */
outbound = dibptr->io_interface (dibptr, /* then pass them to the interface */
inbound_signals, ioaw);
if (store_ioaw == TRUE) { /* if a store is needed */
ioaw = IODATA (outbound); /* then set the IOAW from the returned value */
cpu_write_memory (absolute_iop, addr_reg, ioaw); /* and store it in memory */
cycles = cycles - CYCLES_PER_WRITE; /* count the memory access */
if (store_ioaw == TRUE) { /* if a store is needed */
ioaw = IODATA (outbound); /* then set the IOAW from the returned value */
iop_write_memory (absolute, addr_reg, ioaw); /* and store it in memory */
cycles = cycles - CYCLES_PER_WRITE; /* count the memory access */
dprintf (mpx_dev, DEB_PIO, "Channel SR %u stored IOAW %06o to address %06o\n",
srn, ioaw, addr_reg);
@ -1393,15 +1405,15 @@ while (cycles > 0) { /* execute as long as cy
outbound = dibptr->io_interface (dibptr, inbound_signals, 0);
if (sio_order != sioJUMP /* if we're not completing */
&& (sio_order != sioJUMPC || (outbound & JMPMET) == 0)) { /* a successful jump order */
cpu_read_memory (absolute_iop, IODATA (outbound), &addr_reg); /* then get the I/O program pointer */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
if (sio_order != sioJUMP /* if we're not completing */
&& (sio_order != sioJUMPC || (outbound & JMPMET) == 0)) { /* a successful jump order */
iop_read_memory (absolute, IODATA (outbound), &addr_reg); /* then get the I/O program pointer */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
}
cpu_write_memory (absolute_iop, IODATA (outbound), /* write the updated program pointer */
addr_reg + 2 & R_MASK); /* back to the DRT */
cycles = cycles - CYCLES_PER_WRITE; /* and count the access */
iop_write_memory (absolute, IODATA (outbound), /* write the updated program pointer */
addr_reg + 2 & R_MASK); /* back to the DRT */
cycles = cycles - CYCLES_PER_WRITE; /* and count the access */
break;
@ -1409,9 +1421,9 @@ while (cycles > 0) { /* execute as long as cy
case State_D:
inbound_data = 0; /* assume there is no inbound data */
if (sio_order == sioSBANK) { /* if this is a Set Bank order */
cpu_read_memory (absolute_iop, addr_reg, &ioaw); /* then read the IOAW */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
if (sio_order == sioSBANK) { /* if this is a Set Bank order */
iop_read_memory (absolute, addr_reg, &ioaw); /* then read the IOAW */
cycles = cycles - CYCLES_PER_READ; /* and count the memory access */
dprintf (mpx_dev, DEB_PIO, "Channel SR %u loaded IOAW %06o from address %06o\n",
srn, ioaw, addr_reg);
@ -1449,7 +1461,7 @@ while (cycles > 0) { /* execute as long as cy
else /* otherwise */
inbound_signals |= EOT | TOGGLEOUTXFER; /* assert EOT and end the transfer */
if (cpu_read_memory (dma_iop, /* read the word from memory */
if (iop_read_memory (dma, /* read the word from memory */
TO_PA (AUX_BANK (aux_reg), addr_reg), /* at the indicated bank and offset */
&inbound_data)) /* if the read succeeds */
cycles = cycles - CYCLES_PER_READ; /* then count the memory access */
@ -1467,10 +1479,10 @@ while (cycles > 0) { /* execute as long as cy
if (device_end == SET) { /* if the transfer was aborted by the interface */
outbound_data = IODATA (outbound); /* then it returned the DRT program pointer address */
cpu_read_memory (absolute_iop, outbound_data, &addr_reg); /* do the I/O program pointer fetch here */
cpu_write_memory (absolute_iop, outbound_data, /* so we don't have to do State C */
iop_read_memory (absolute, outbound_data, &addr_reg); /* do the I/O program pointer fetch here */
iop_write_memory (absolute, outbound_data, /* so we don't have to do State C */
addr_reg + 2 & R_MASK);
cycles = cycles - CYCLES_PER_READ - CYCLES_PER_WRITE; /* count the two memory accesses */
cycles = cycles - CYCLES_PER_READ - CYCLES_PER_WRITE; /* count the two memory accesses */
if (cntr_reg == CNTR_MAX) /* if the word count is now exhausted */
if (order_reg & ORDER_DC) /* then if the order is chained */
@ -1498,7 +1510,7 @@ while (cycles > 0) { /* execute as long as cy
else { /* otherwise the transfer succeeded */
if (sio_order == sioREAD || sio_order == sioREADC) /* if this is a Read or Read Chained order */
if (cpu_write_memory (dma_iop, /* then write the word to memory */
if (iop_write_memory (dma, /* then write the word to memory */
TO_PA (AUX_BANK (aux_reg), addr_reg), /* at the indicated bank and offset */
IODATA (outbound))) /* if the write succeeds */
cycles = cycles - CYCLES_PER_WRITE; /* then count the memory access */
@ -1739,7 +1751,7 @@ while (working_set) {
dprintf (mpx_dev, DEB_CSRW, "Order register value %02o (%s) "
"and counter register value %d returned\n",
order_reg & ORDER_MASK, sio_order_name [IOCW_ORDER (outbound_value)],
SEXT (IOCW_COUNT (outbound_value)));
SEXT16 (IOCW_COUNT (outbound_value)));
}
if (control_word & CN_ADDR_RAM) { /* if the address register is selected */

View File

@ -1,6 +1,6 @@
SIMH/HP 3000 RELEASE NOTES
==========================
Last update: 2016-09-20
Last update: 2017-01-08
This file documents the release history of the Hewlett-Packard 3000 simulator.
@ -158,6 +158,149 @@ the MPE version used:
=====================
Release 4, 2017-01-08
=====================
This release of the HP 3000 simulator adds the following features:
- The HP 32234A COBOL II Extended Instruction Set firmware is now available.
The new SET CPU CIS option enables the firmware.
- Subprograms in memory associated with the EDIT instruction may be examined
symbolically with the -E switch.
- The new CPU "OPND" trace option traces memory byte operands.
- The new CPU "EXEC" trace option turns on full tracing for instructions
that match a value specified by the new "SET CPU EXEC=<match>{;<mask>}"
command.
- The diagnostics coverage is extended to the COBOL II firmware.
--------------------
Implementation Notes
--------------------
- The MPE-V/R software kit has been updated to add the COBOL II runtime
routines to the system SL and COBOL example programs to the OPERATOR.SYS
account. The startup command files also enable the COBOL II instruction set.
- New "hp3000_cpu_cis.c" and "hp3000_mem.c" modules have been added.
- For this release, checking for interrupts is not performed during execution
of the COBOL II EDIT, TR, CMPS, and CMPT instructions. A future release will
add interruptibility to these instructions to comply with their hardware
behavior.
- The new OPND trace option does not currently trace byte operands for
instructions in the base set (e.g., MOVB or CMPB). Operands for the
COBOL II firmware instructions are fully covered.
- The command-line switch for the EXAMINE command to request display in
status-register format has been changed from "-S" to "-T" to avoid conflict
with the "-S" switch used to indicate an address offset from SBANK.
----------
Bugs Fixed
----------
1. PROBLEM: SETR prints a base register trace when values are not changed.
VERSION: Release 3
OBSERVATION: The SETR instruction may be used to change any combination of
the SBANK, DB, DL, Z, STA, X, Q, and SM register values. If the REG trace
is active, the base register values will be printed after the instruction
completes. This occurs whether or not the base register values were
actually changed. In particular, the CPU diagnostic uses the SETR
instruction to flush the stack to memory without changing any base
registers. The REG trace in this case is unnecessary.
CAUSE: The "cpu_base_changed" flag is set unconditionally when the
instruction completes. It should be set only if the SETR instruction
specifies one or more base registers to change.
RESOLUTION: Modify "cpu_move_spec_fw_imm_field_reg_op" (hp3000_cpu_base.c)
to set the "cpu_base_changed" flag only if one or more base register change
bits are set in the instruction operand field.
STATUS: Fixed in Release 4.
2. PROBLEM: Invalid bank and offset values are accepted for address entry.
VERSION: Release 3
OBSERVATION: Bank-offset addresses with out-of-range the bank or offset
values, e.g., EXAMINE 30.0 and EXAMINE 0.1777777, are accepted without
complaint. The bank value is taken modulo 20, and the higher order bits of
the offset value are merged into the bank number. Values out of range
should be rejected with errors.
CAUSE: Incomplete range verification.
RESOLUTION: Modify "parse_addr" (hp3000_sys.c) to check the parsed bank
and offset values against their respective maximums and return an "Invalid
argument" error if either is exceeded.
STATUS: Fixed in Release 4.
3. PROBLEM: The "-S" (SBANK-offset) switch displays values in status-register
format.
VERSION: Release 3
OBSERVATION: The HP 3000 User's Manual states that adding the "-S" switch
to the EXAMINE command implies that the offset is from the bank number in
the SBANK register. The example given, "EXAMINE -S <sbank-offset>", should
display the memory data value at the address <SBANK-number>.<offset> in
octal format. Instead, it displays the value in status-register format.
CAUSE: The "-S" switch is used for both SBANK and STA formats. Section
2.1.3 says that -S means that "The implied bank number is obtained from
SBANK." Section 2.1.2 says that -S means that "A CPU status mnemonic" is
being displayed. For EXAMINE -S, the latter interpretation causes the
expected octal value to be displayed in status-register format.
RESOLUTION: Modify "fprint_sym" (hp3000_sys.c) to use the "-T" switch to
designate status-register format. Modify hp3000_sys.c, hp3000_cpu.c, and
hp3000_defs.h to rename the "REG_S" format indicator to "REG_T" for
consistency with the switch change.
STATUS: Fixed in Release 4.
4. PROBLEM: SCAL 0 and PCAL 0 instructions fail when a stack overflow occurs.
VERSION: Release 3
OBSERVATION: The SCAL 0 and PCAL 0 instructions transfer control via
subroutine or procedure calls, respectively, through program labels
residing on the top of the stack. If a stack overflow occurs during
instruction execution, the stack overflow trap handler is called to enlarge
the stack, and the instruction is reexecuted. However, the program label
has been lost, so control transfers to a random location.
CAUSE: The instructions obtain the label and then delete the TOS, flush
the rest of the stack registers to memory, and then check that SM <= Z,
i.e., that the current top of the stack in memory does not exceed the
stack limit. If SM > Z, a stack overflow has occurred, and the trap
handler is called. However, the label has not been restored to the stack,
so when the instruction is reexecuted after the stack is enlarged, the
wrong value is pulled from the TOS.
RESOLUTION: Modify "cpu_io_cntl_prog_imm_mem_op" SCAL and PCAL executors
(hp3000_cpu_base.c) to push the label back onto the stack before taking the
stack overflow trap.
STATUS: Fixed in Release 4.
=====================
Release 3, 2016-09-20
=====================

View File

@ -25,6 +25,8 @@
SEL HP 3000 Series III Selector Channel
10-Oct-16 JDB Renumbered debug flags to start at 0
Added port_read_memory, port_write_memory macros
11-Jul-16 JDB Change "sel_unit" from a UNIT to an array of one UNIT
30-Jun-16 JDB Reestablish active_dib pointer during sel_initialize
08-Jun-16 JDB Corrected %d format to %u for unsigned values
@ -289,9 +291,9 @@
#include "hp3000_defs.h"
#include "hp3000_cpu.h"
#include "hp3000_cpu_ims.h"
#include "hp3000_io.h"
#include "hp3000_mem.h"
@ -364,18 +366,18 @@ static const char *const action_name [] = { /* indexed by SEQ_STATE */
};
/* Debug flags.
/* Debug flags */
#define DEB_CSRW (1u << 0) /* trace channel command initiations and completions */
#define DEB_PIO (1u << 1) /* trace programmed I/O commands */
#define DEB_STATE (1u << 2) /* trace state changes */
#define DEB_SR (1u << 3) /* trace service requests */
Implementation notes:
/* Memory access macros */
1. Bit 0 is reserved for the memory data trace flag.
*/
#define DEB_CSRW (1u << 1) /* trace channel command initiations and completions */
#define DEB_PIO (1u << 2) /* trace programmed I/O commands */
#define DEB_STATE (1u << 3) /* trace state changes */
#define DEB_SR (1u << 4) /* trace service requests */
#define port_read_memory(c,o,v) mem_read (&sel_dev, c, o, v)
#define port_write_memory(c,o,v) mem_write (&sel_dev, c, o, v)
/* Channel global state */
@ -600,8 +602,8 @@ if (sel_is_idle) { /* if the channel is idl
active_dib = dibptr; /* save the interface's DIB pointer */
device_number = dibptr->device_number; /* and set the device number register */
cpu_read_memory (absolute_sel, device_number * 4, /* read the initial program counter from the DRT */
&program_counter);
port_read_memory (absolute, device_number * 4, /* read the initial program counter from the DRT */
&program_counter);
}
else { /* otherwise abort the transfer in progress */
@ -935,7 +937,7 @@ while (sel_request && cycles > 0) { /* execute as long as a
outbound_data = IODATA (outbound); /* get the status or residue to return */
return_address = program_counter - 1 & LA_MASK; /* point at the second of the program words */
cpu_write_memory (absolute_sel, return_address, outbound_data); /* save the word */
port_write_memory (absolute, return_address, outbound_data); /* save the word */
cycles = cycles - CYCLES_PER_WRITE; /* and count the access */
dprintf (sel_dev, DEB_PIO, "Channel stored IOAW %06o to address %06o\n",
@ -1029,9 +1031,9 @@ while (sel_request && cycles > 0) { /* execute as long as a
}
else { /* otherwise it's a Write or Write Chained order */
if (cpu_read_memory (dma_sel, /* if the memory read */
TO_PA (bank, address_word), /* from the specified bank and offset */
&input_buffer)) { /* succeeds */
if (port_read_memory (dma, /* if the memory read */
TO_PA (bank, address_word), /* from the specified bank and offset */
&input_buffer)) { /* succeeds */
cycles = cycles - CYCLES_PER_READ; /* then count the access */
inbound_data = input_buffer; /* get the word to supply */
@ -1098,9 +1100,9 @@ while (sel_request && cycles > 0) { /* execute as long as a
|| order == sioREADC) { /* and if this is a Read or Read Chained order */
output_buffer = IODATA (outbound); /* then pick up the returned data word */
if (cpu_write_memory (dma_sel, /* if the memory write */
TO_PA (bank, address_word), /* to the specified bank and offset */
output_buffer)) /* succeeds */
if (port_write_memory (dma, /* if the memory write */
TO_PA (bank, address_word), /* to the specified bank and offset */
output_buffer)) /* succeeds */
cycles = cycles - CYCLES_PER_WRITE; /* then count the access */
else { /* otherwise the memory write failed */
@ -1264,8 +1266,8 @@ return SCPE_OK;
static void end_channel (DIB *dibptr)
{
cpu_write_memory (absolute_sel, device_number * 4, /* write the program counter back to the DRT */
program_counter);
port_write_memory (absolute, device_number * 4, /* write the program counter back to the DRT */
program_counter);
dibptr->service_request = FALSE; /* clear any outstanding device service request */
@ -1302,7 +1304,7 @@ return active_dib->io_interface (active_dib, XFERERROR | CHANSO, 0); /* tell
static void load_control (HP_WORD *value)
{
cpu_read_memory (absolute_sel, program_counter, value); /* read the IOCW from memory */
port_read_memory (absolute, program_counter, value); /* read the IOCW from memory */
dprintf (sel_dev, DEB_PIO, "Channel %s IOCW %06o (%s) from address %06o\n",
action_name [sequencer], *value,
@ -1324,7 +1326,7 @@ return;
static void load_address (HP_WORD *value)
{
cpu_read_memory (absolute_sel, program_counter, value); /* read the IOAW from memory */
port_read_memory (absolute, program_counter, value); /* read the IOAW from memory */
dprintf (sel_dev, DEB_PIO, "Channel %s IOAW %06o from address %06o\n",
action_name [sequencer], *value, program_counter);

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors.
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion from "hp_disclib.h"
03-Aug-16 JDB "fmt_bitset" now allows multiple concurrent calls
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
08-Jun-16 JDB Corrected %d format to %u for unsigned values
@ -372,21 +373,22 @@
#include <math.h>
#include "hp3000_defs.h" /* this must reflect the machine used */
#include "hp_disclib.h"
/* Program constants */
#define CNTLR_UNIT (DL_MAXDRIVE + 1) /* controller unit number */
#define MAX_UNIT 10 /* last legal unit number */
#define CNTLR_UNIT (DL_MAXDRIVE + 1) /* controller unit number */
#define MAX_UNIT 10 /* last legal unit number */
#define WORDS_PER_SECTOR 128 /* data words per sector */
#define WORDS_PER_SECTOR 128 /* data words per sector */
#define UNTALK_DELAY 160 /* ICD untalk delay (constant instruction count) */
#define CNTLR_TIMEOUT S (1.74) /* command and parameter wait timeout (1.74 seconds) */
#define UNTALK_DELAY 160 /* ICD untalk delay (constant instruction count) */
#define CNTLR_TIMEOUT S (1.74) /* command and parameter wait timeout (1.74 seconds) */
#define NO_EVENT -1 /* do not schedule an event */
#define NO_EVENT -1 /* do not schedule an event */
#define NO_ACTION (CNTLR_IFN_IBUS) (NO_FUNCTIONS | NO_DATA)
@ -404,9 +406,9 @@
/* Controller clear types */
typedef enum {
Hard_Clear, /* power-on/preset hard clear */
Timeout_Clear, /* command or parameter timeout clear */
Soft_Clear /* programmed soft clear */
Hard_Clear, /* power-on/preset hard clear */
Timeout_Clear, /* command or parameter timeout clear */
Soft_Clear /* programmed soft clear */
} CNTLR_CLEAR;

View File

@ -24,6 +24,7 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the authors.
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion to "hp_disclib.c"
13-May-16 JDB Modified for revised SCP API function parameter types
24-Mar-16 JDB Added the DL_BUFFER type to define the disc buffer array
21-Mar-16 JDB Changed uint16 types to HP_WORD
@ -42,10 +43,6 @@
#include "hp3000_defs.h" /* this must reflect the machine used */
/* Architectural constants.
The type of the disc buffer element is defined. This must be a 16-bit array

View File

@ -24,6 +24,7 @@
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the authors.
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion from "hp_tapelib.h"
01-Jul-16 JDB Changed tl_attach to reset the event delay times pointer
09-Jun-16 JDB Added casts for ptrdiff_t to int32 values
08-Jun-16 JDB Corrected %d format to %u for unsigned values
@ -326,6 +327,7 @@
#include "hp3000_defs.h" /* this must reflect the machine used */
#include "hp_tapelib.h"

View File

@ -24,6 +24,7 @@
in advertising or otherwise to promote the sale, use or other dealings in
this Software without prior written authorization from the authors.
10-Oct-16 JDB Moved "hp3000_defs.h" inclusion to "hp_tapelib.c"
13-May-16 JDB Modified for revised SCP API function parameter types
24-Mar-16 JDB Added the TL_BUFFER type to define the tape buffer array
21-Mar-16 JDB Changed uint16 types to HP_WORD
@ -38,8 +39,6 @@
#include "hp3000_defs.h" /* this must reflect the machine used */
#include "sim_tape.h"

View File

@ -204,6 +204,10 @@
RelativePath="..\HP3000\hp3000_cpu_base.c"
>
</File>
<File
RelativePath="..\HP3000\hp3000_cpu_cis.c"
>
</File>
<File
RelativePath="..\HP3000\hp3000_cpu_fp.c"
>
@ -220,6 +224,10 @@
RelativePath="..\HP3000\hp3000_lp.c"
>
</File>
<File
RelativePath="..\HP3000\hp3000_mem.c"
>
</File>
<File
RelativePath="..\HP3000\hp3000_mpx.c"
>
@ -317,6 +325,10 @@
RelativePath="..\HP3000\hp3000_io.h"
>
</File>
<File
RelativePath="..\HP3000\hp3000_mem.h"
>
</File>
<File
RelativePath="..\HP3000\hp_disclib.h"
>

View File

@ -432,9 +432,10 @@ HP3000_DIR = SYS$DISK:[.HP3000]
HP3000_LIB1 = $(LIB_DIR)HP3000L1-$(ARCH).OLB
HP3000_SOURCE1 = $(HP3000_DIR)HP3000_ATC.C,$(HP3000_DIR)HP3000_CLK.C,\
$(HP3000_DIR)HP3000_CPU.C,$(HP3000_DIR)HP3000_CPU_BASE.C,\
$(HP3000_DIR)HP3000_CPU_FP.C,$(HP3000_DIR)HP3000_DS.C,\
$(HP3000_DIR)HP3000_LP.C,\
$(HP3000_DIR)HP3000_IOP.C,$(HP3000_DIR)HP3000_MPX.C,\
$(HP3000_DIR)HP3000_CPU_CIS.C,$(HP3000_DIR)HP3000_CPU_FP.C,\
$(HP3000_DIR)HP3000_DS.C,$(HP3000_DIR)HP3000_LP.C,\
$(HP3000_DIR)HP3000_IOP.C,$(HP3000_DIR)HP3000_MEM.C,\
$(HP3000_DIR)HP3000_MPX.C,\
$(HP3000_DIR)HP3000_MS.C,$(HP3000_DIR)HP3000_SCMB.C,\
$(HP3000_DIR)HP3000_SEL.C,$(HP3000_DIR)HP3000_SYS.C
HP3000_LIB2 = $(LIB_DIR)HP3000L2-$(ARCH).OLB

Binary file not shown.

View File

@ -1215,9 +1215,10 @@ HP2100_OPT = -DHAVE_INT64 -I ${HP2100D}
HP3000D = HP3000
HP3000 = ${HP3000D}/hp_disclib.c ${HP3000D}/hp_tapelib.c ${HP3000D}/hp3000_atc.c \
${HP3000D}/hp3000_clk.c ${HP3000D}/hp3000_cpu.c ${HP3000D}/hp3000_cpu_base.c \
${HP3000D}/hp3000_cpu_fp.c ${HP3000D}/hp3000_ds.c ${HP3000D}/hp3000_iop.c \
${HP3000D}/hp3000_lp.c ${HP3000D}/hp3000_mpx.c ${HP3000D}/hp3000_ms.c \
${HP3000D}/hp3000_scmb.c ${HP3000D}/hp3000_sel.c ${HP3000D}/hp3000_sys.c
${HP3000D}/hp3000_cpu_fp.c ${HP3000D}/hp3000_cpu_cis.c ${HP3000D}/hp3000_ds.c \
${HP3000D}/hp3000_iop.c ${HP3000D}/hp3000_lp.c ${HP3000D}/hp3000_mem.c \
${HP3000D}/hp3000_mpx.c ${HP3000D}/hp3000_ms.c ${HP3000D}/hp3000_scmb.c \
${HP3000D}/hp3000_sel.c ${HP3000D}/hp3000_sys.c
HP3000_OPT = -I ${HP3000D}