/* hp2100_cpu0.c: HP 1000 unimplemented instruction set stubs

   Copyright (c) 2006, 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.

   CPU0         Unimplemented firmware option instructions

   01-Dec-06    JDB     Removed and implemented "cpu_sis".
   26-Sep-06    JDB     Created

   This file contains template simulations for the firmware options that have
   not yet been implemented.  When a given firmware option is implemented, it
   should be moved out of this file and into another (or its own, depending on
   complexity).

   Primary references:
   - HP 1000 M/E/F-Series Computers Technical Reference Handbook
        (5955-0282, Mar-1980)
   - HP 1000 M/E/F-Series Computers Engineering and Reference Documentation
        (92851-90001, Mar-1981)
   - Macro/1000 Reference Manual (92059-90001, Dec-1992)

   Additional references are listed with the associated firmware
   implementations, as are the HP option model numbers pertaining to the
   applicable CPUs.
*/

#include "hp2100_defs.h"
#include "hp2100_cpu.h"
#include "hp2100_cpu1.h"


t_stat cpu_rte_ema (uint32 IR, uint32 intrq);               /* RTE-4 EMA */
t_stat cpu_rte_vma (uint32 IR, uint32 intrq);               /* RTE-6 VMA */
t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap); /* RTE-6 OS */
t_stat cpu_ds  (uint32 IR, uint32 intrq);               /* Distributed System */
t_stat cpu_vis (uint32 IR, uint32 intrq);               /* Vector Instruction Set */
t_stat cpu_signal (uint32 IR, uint32 intrq);            /* SIGNAL/1000 Instructions */


/* RTE-IV Extended Memory Area Instructions

   The RTE-IV operating system (HP product number 92067A) introduced the
   Extended Memory Area (EMA) instructions.  EMA provided a mappable data area
   up to one megaword in size.  These three instructions accelerated data
   accesses to variables stored in EMA partitions.  Support was limited to
   E/F-Series machines; M-Series machines used software equivalents.

   Option implementation by CPU was as follows:

      2114    2115    2116    2100   1000-M  1000-E  1000-F
     ------  ------  ------  ------  ------  ------  ------
      N/A     N/A     N/A     N/A     N/A    92067A  92067A

   The routines are mapped to instruction codes as follows:

     Instr.  1000-E/F   Description
     ------  --------  ----------------------------------------------
     .EMIO    105240   EMA I/O
     MMAP     105241   Map physical to logical memory
     [test]   105242   [self test]
     .EMAP    105257   Resolve array element address

   Notes:

     1. RTE-IV EMA and RTE-6 VMA instructions share the same address space, so a
        given machine can run one or the other, but not both.

   Additional references:
    - RTE-IVB Programmer's Reference Manual (92068-90004, Dec-1983).
    - RTE-IVB Technical Specifications (92068-90013, Jan-1980).
*/

static const OP_PAT op_ema[16] = {
  OP_A,    OP_AKK,    OP_N,    OP_N,                    /* .EMIO  MMAP   [test]  ---   */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---   */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---   */
  OP_N,    OP_N,      OP_N,    OP_A                     /*  ---    ---    ---   .EMAP  */
  };

t_stat cpu_rte_ema (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;

if ((cpu_unit.flags & UNIT_EMA) == 0)                   /* EMA option installed? */
    return stop_inst;

entry = IR & 017;                                       /* mask to entry point */

if (op_ema[entry] != OP_N)
    if (reason = cpu_ops (op_ema[entry], op, intrq))    /* get instruction operands */
        return reason;

switch (entry) {                                        /* decode IR<3:0> */

    default:                                            /* others undefined */
        reason = stop_inst;
        }

return reason;
}


/* RTE-6/VM Virtual Memory Area Instructions

   RTE-6/VM (product number 92084A) introduced Virtual Memory Area (VMA)
   instructions -- a superset of the RTE-IV EMA instructions.  Different
   microcode was supplied with the operating system that replaced the microcode
   used with RTE-IV.  Microcode was limited to the E/F-Series, and the M-Series
   used software equivalents.

   Option implementation by CPU was as follows:

      2114    2115    2116    2100   1000-M  1000-E  1000-F
     ------  ------  ------  ------  ------  ------  ------
      N/A     N/A     N/A     N/A     N/A    92084A  92084A

   The routines are mapped to instruction codes as follows:

     Instr.  1000-E/F   Description
     ------  --------  ----------------------------------------------
     .PMAP    105240   Map VMA page into map register
     $LOC     105241   Load on call
     [test]   105242   [self test]
     .SWP     105243   [Swap A and B registers]
     .STAS    105244   [STA B; LDA SP]
     .LDAS    105245   [LDA SP]
     .MYAD    105246   [NOP in microcode]
     .UMPY    105247   [Unsigned multiply and add]

     .IMAP    105250   Integer element resolve address and map
     .IMAR    105251   Integer element resolve address
     .JMAP    105252   Double integer element resolve address and map
     .JMAR    105253   Double integer element resolve address
     .LPXR    105254   Map pointer in P+1 plus offset in P+2
     .LPX     105255   Map pointer in A/B plus offset in P+1
     .LBPR    105256   Map pointer in P+1
     .LBP     105257   Map pointer in A/B registers

   Notes:

     1. The opcodes 105243-247 are undocumented and do not appear to be used in
        any HP software.

     2. The opcode list in the CE Handbook incorrectly shows 105246 as ".MYAD -
        multiply 2 signed integers."  The microcode listing shows that this
        instruction was deleted, and the opcode is now a NOP.

     3. RTE-IV EMA and RTE-6 VMA instructions shared the same address space, so
        a given machine could run one or the other, but not both.

   Additional references:
    - RTE-6/VM VMA/EMA Microcode Source (92084-18828, revision 3).
    - RTE-6/VM Technical Specifications (92084-90015, Apr-1983).
    - M/E/F-Series Computer Systems CE Handbook (5950-3767, Jul-1984).
*/

static const OP_PAT op_vma[16] = {
  OP_N,    OP_KKKAKK, OP_N,    OP_N,                    /* .PMAP  $LOC   [test] .SWAP  */
  OP_N,    OP_N,      OP_N,    OP_K,                    /* .STAS  .LDAS  .MYAD  .UMPY  */
  OP_A,    OP_A,      OP_A,    OP_A,                    /* .IMAP  .IMAR  .JMAP  .JMAR  */
  OP_FF,   OP_F,      OP_F,    OP_N                     /* .LPXR  .LPX   .LBPR  .LBP   */
  };

t_stat cpu_rte_vma (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;

if ((cpu_unit.flags & UNIT_VMAOS) == 0)                 /* VMA/OS option installed? */
    return cpu_rte_ema (IR, intrq);                     /* try EMA */

entry = IR & 017;                                       /* mask to entry point */

if (op_vma[entry] != OP_N)
    if (reason = cpu_ops (op_vma[entry], op, intrq))    /* get instruction operands */
        return reason;

switch (entry) {                                        /* decode IR<3:0> */

    default:                                            /* others undefined */
        reason = stop_inst;
        }

return reason;
}


/* RTE-6/VM Operating System Instructions

   The OS instructions were added to acccelerate certain time-consuming
   operations of the RTE-6/VM operating system, HP product number 92084A.
   Microcode was available for the E- and F-Series; the M-Series used software
   equivalents.

   Option implementation by CPU was as follows:

      2114    2115    2116    2100   1000-M  1000-E  1000-F
     ------  ------  ------  ------  ------  ------  ------
      N/A     N/A     N/A     N/A     N/A    92084A  92084A

   The routines are mapped to instruction codes as follows:

     Instr.  1000-E/F   Description
     ------  --------  ----------------------------------------------
     $LIBR    105340   Enter privileged/reentrant library routine
     $LIBX    105341   Exit privileged/reentrant library routine
     .TICK    105342   TBG tick interrupt handler
     .TNAM    105343   Find ID segment that matches name
     .STIO    105344   Configure I/O instructions
     .FNW     105345   Find word with user increment
     .IRT     105346   Interrupt return processing
     .LLS     105347   Linked list search

     .SIP     105350   Skip if interrupt pending
     .YLD     105351   .SIP completion return point
     .CPM     105352   Compare words LT/EQ/GT
     .ETEQ    105353   Set up EQT pointers in base page
     .ENTN    105354   Transfer parameter addresses (utility)
     [test]   105355   [self test]
     .ENTC    105356   Transfer parameter addresses (priv/reent)
     .DSPI    105357   Set display indicator

   Opcodes 105354-105357 are "dual use" instructions that take different
   actions, depending on whether they are executed from a trap cell during an
   interrupt.  When executed from a trap cell, they have these actions:

     Instr.  1000-E/F   Description
     ------  --------  ----------------------------------------------
     [dma]    105354   DCPC channel interrupt processing
     [dms]    105355   DMS/MP/PE interrupt processing
     [dev]    105356   Standard device interrupt processing
     [tbg]    105357   TBG interrupt processing

   Notes:

     1. The microcode differentiates between interrupt processing and normal
        execution of the "dual use" instructions by testing the CPU flag.
        Interrupt vectoring sets the flag; a normal instruction fetch clears it.
        Under simulation, interrupt vectoring is indicated by the value of the
        "iotrap" parameter.

     2. The operand patterns for .ENTN and .ENTC normally would be coded as
        "OP_A", as each takes a single address as a parameter.  However, because
        they might also be executed from a trap cell, we cannot assume that P+1
        is an address, or we might cause a DM abort when trying to access
        memory.  Therefore, "OP_A" handling is done within each routine, once
        the type of use is determined.

   Additional references:
    - RTE-6/VM O/S Microcode Source (92084-18831, revision 6).
    - RTE-6/VM Technical Specifications (92084-90015, Apr-1983).
*/

static const OP_PAT op_os[16] = {
  OP_A,    OP_A,    OP_N,    OP_N,                      /* $LIBR  $LIBX  .TICK  .TNAM  */
  OP_A,    OP_K,    OP_A,    OP_KK,                     /* .STIO  .FNW   .IRT   .LLS   */
  OP_N,    OP_CC,   OP_KK,   OP_N,                      /* .SIP   .YLD   .CPM   .ETEQ  */
  OP_N,    OP_N,    OP_N,    OP_N                       /* .ENTN  [test] .ENTC  .DSPI  */
  };

t_stat cpu_rte_os (uint32 IR, uint32 intrq, uint32 iotrap)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;

if ((cpu_unit.flags & UNIT_VMAOS) == 0)                 /* VMA/OS option installed? */
    return stop_inst;

entry = IR & 017;                                       /* mask to entry point */

if (op_os[entry] != OP_N)  
    if (reason = cpu_ops (op_os[entry], op, intrq))     /* get instruction operands */
        return reason;

switch (entry) {                                        /* decode IR<3:0> */

    default:                                            /* others undefined */
        reason = stop_inst;
        }

return reason;
}


/* Distributed System

   Distributed System firmware was provided with the HP 91740A DS/1000 product
   for use with the HP 12771A (12665A) Serial Interface and 12773A Modem
   Interface system interconnection kits.  Firmware permitted high-speed
   transfers with minimum impact to the processor.  The advent of the
   "intelligent" 12794A and 12825A HDLC cards, the 12793A and 12834A Bisync
   cards, and the 91750A DS-1000/IV software obviated the need for CPU firmware,
   as essentially the firmware was moved onto the I/O cards.

   Primary documentation for the DS instructions has not been located.  However,
   examination of the DS/1000 sources reveals that two instruction were used by
   the DVA65 Serial Interface driver (91740-18071) and placed in the trap cells
   of the communications interfaces.  Presumably they handled interrupts from
   the cards.

   Implementation of the DS instructions will also require simulation of the
   12665A Hardwired Serial Data Interface Card and the 12620A RTE Privileged
   Interrupt Fence.  These are required for DS/1000.

   Option implementation by CPU was as follows:

      2114    2115    2116    2100   1000-M  1000-E  1000-F
     ------  ------  ------  ------  ------  ------  ------
      N/A     N/A     N/A     N/A    91740A  91740B  91740B

   The routines are mapped to instruction codes as follows:

     Instr.  1000-M  1000-E/F  Description
     ------  ------  --------  ----------------------------------------------
             105520   105300   "Open loop" (trap cell handler)
             105521   105301   "Closed loop" (trap cell handler)
             105522   105302   [unknown]
     [test]  105524   105304   [self test]

   Notes:

     1. The E/F-Series opcodes were moved from 105340-357 to 105300-317 at
        revision 1813.

     2. DS/1000 ROM data are available from Bitsavers.

   Additional references (documents unavailable):
    - HP 91740A M-Series Distributed System (DS/1000) Firmware Installation
      Manual (91740-90007).
    - HP 91740B Distributed System (DS/1000) Firmware Installation Manual
      (91740-90009).
*/

static const OP_PAT op_ds[16] = {
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---  */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---  */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---  */
  OP_N,    OP_N,      OP_N,    OP_N                     /*  ---    ---    ---    ---  */
  };

t_stat cpu_ds (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;

if ((cpu_unit.flags & UNIT_DS) == 0)                    /* DS option installed? */
    return stop_inst;

entry = IR & 017;                                       /* mask to entry point */

if (op_ds[entry] != OP_N)
    if (reason = cpu_ops (op_ds[entry], op, intrq))     /* get instruction operands */
        return reason;

switch (entry) {                                        /* decode IR<3:0> */

    default:                                            /* others undefined */
        reason = stop_inst;
        }

return reason;
}


/* Vector Instruction Set

   The VIS provides instructions that operate on one-dimensional arrays of
   floating-point values.  Both single- and double-precision operations are
   supported.

   Option implementation by CPU was as follows:

      2114    2115    2116    2100   1000-M  1000-E  1000-F
     ------  ------  ------  ------  ------  ------  ------
      N/A     N/A     N/A     N/A     N/A     N/A    12824A

   The routines are mapped to instruction codes as follows:

        Single-Precision        Double-Precision
     Instr.  Opcode  Subcod  Instr.  Opcode  Subcod  Description
     ------  ------  ------  ------  ------  ------  -----------------------------
     VADD    101460  000000  DVADD   105460  004002  Vector add
     VSUB    101460  000020  DVSUB   105460  004022  Vector subtract
     VMPY    101460  000040  DVMPY   105460  004042  Vector multiply
     VDIV    101460  000060  DVDIV   105460  004062  Vector divide
     VSAD    101460  000400  DVSAD   105460  004402  Scalar-vector add
     VSSB    101460  000420  DVSSB   105460  004422  Scalar-vector subtract
     VSMY    101460  000440  DVSMY   105460  004442  Scalar-vector multiply
     VSDV    101460  000460  DVSDV   105460  004462  Scalar-vector divide
     VPIV    101461  0xxxxx  DVPIV   105461  0xxxxx  Vector pivot
     VABS    101462  0xxxxx  DVABS   105462  0xxxxx  Vector absolute value
     VSUM    101463  0xxxxx  DVSUM   105463  0xxxxx  Vector sum
     VNRM    101464  0xxxxx  DVNRM   105464  0xxxxx  Vector norm
     VDOT    101465  0xxxxx  DVDOT   105465  0xxxxx  Vector dot product
     VMAX    101466  0xxxxx  DVMAX   105466  0xxxxx  Vector maximum value
     VMAB    101467  0xxxxx  DVMAB   105467  0xxxxx  Vector maximum absolute value
     VMIN    101470  0xxxxx  DVMIN   105470  0xxxxx  Vector minimum value
     VMIB    101471  0xxxxx  DVMIB   105471  0xxxxx  Vector minimum absolute value
     VMOV    101472  0xxxxx  DVMOV   105472  0xxxxx  Vector move
     VSWP    101473  0xxxxx  DVSWP   105473  0xxxxx  Vector swap
     .ERES   101474    --     --       --      --    Resolve array element address
     .ESEG   101475    --     --       --      --    Load MSEG maps
     .VSET   101476    --     --       --      --    Vector setup
     [test]    --      --     --     105477    --    [self test]

   Instructions use IR bit 11 to select single- or double-precision format.  The
   double-precision instruction names begin with "D" (e.g., DVADD vs. VADD).
   Most VIS instructions are two words in length, with a sub-opcode immediately
   following the primary opcode.

   Notes:

     1. The .VECT (101460) and .DVCT (105460) opcodes preface a single- or
        double-precision arithmetic operation that is determined by the
        sub-opcode value.  The remainder of the dual-precision sub-opcode values
        are "don't care," except for requiring a zero in bit 15.

     2. The VIS uses the hardware FPP of the F-Series.  FPP malfunctions are
        detected by the VIS firmware and are indicated by a memory-protect
        violation and setting the overflow flag.  Under simulation,
        malfunctions cannot occur.

     3. VIS ROM data are available from Bitsavers.

   Additional references:
    - 12824A Vector Instruction Set User's Manual (12824-90001, Jun-1979).
*/

static const OP_PAT op_vis[16] = {
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---  */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---  */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---  */
  OP_N,    OP_N,      OP_N,    OP_N                     /*  ---    ---    ---    ---  */
  };

t_stat cpu_vis (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;

if ((cpu_unit.flags & UNIT_VIS) == 0)                   /* VIS option installed? */
    return stop_inst;

entry = IR & 017;                                       /* mask to entry point */

if (op_vis[entry] != OP_N)
    if (reason = cpu_ops (op_vis[entry], op, intrq))    /* get instruction operands */
        return reason;

switch (entry) {                                        /* decode IR<3:0> */

    default:                                            /* others undefined */
        reason = stop_inst;
        }

return reason;
}


/* SIGNAL/1000 Instructions

   The SIGNAL/1000 instructions provide fast Fourier transforms and complex
   arithmetic.  They utilize the F-Series floating-point processor and the
   Vector Instruction Set.

   Option implementation by CPU was as follows:

      2114    2115    2116    2100   1000-M  1000-E  1000-F
     ------  ------  ------  ------  ------  ------  ------
      N/A     N/A     N/A     N/A     N/A     N/A    92835A

   The routines are mapped to instruction codes as follows:

     Instr.  1000-F  Description
     ------  ------  ----------------------------------------------
     BITRV   105600  Bit reversal
     BTRFY   105601  Butterfly algorithm
     UNSCR   105602  Unscramble for phasor MPY
     PRSCR   105603  Unscramble for phasor MPY
     BITR1   105604  Swap two elements in array (alternate format)
     BTRF1   105605  Butterfly algorithm (alternate format)
     .CADD   105606  Complex number addition
     .CSUB   105607  Complex number subtraction
     .CMPY   105610  Complex number multiplication
     .CDIV   105611  Complex number division
     CONJG   105612  Complex conjugate
     ..CCM   105613  Complex complement
     AIMAG   105614  Return imaginary part
     CMPLX   105615  Form complex number
     [nop]   105616  [no operation]
     [test]  105617  [self test]

   Notes:

     1. SIGNAL/1000 ROM data are available from Bitsavers.

   Additional references (documents unavailable):
    - HP Signal/1000 User Reference and Installation Manual (92835-90002).
*/

static const OP_PAT op_signal[16] = {
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---   */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---   */
  OP_N,    OP_N,      OP_N,    OP_N,                    /*  ---    ---    ---    ---   */
  OP_N,    OP_N,      OP_N,    OP_N                     /*  ---    ---    ---    ---   */
  };

t_stat cpu_signal (uint32 IR, uint32 intrq)
{
t_stat reason = SCPE_OK;
OPS op;
uint32 entry;

if ((cpu_unit.flags & UNIT_SIGNAL) == 0)                /* SIGNAL option installed? */
    return stop_inst;

entry = IR & 017;                                       /* mask to entry point */

if (op_signal[entry] != OP_N)
    if (reason = cpu_ops (op_signal[entry], op, intrq)) /* get instruction operands */
        return reason;

switch (entry) {                                        /* decode IR<3:0> */

    default:                                            /* others undefined */
        reason = stop_inst;
        }

return reason;
}
