/* 3b2_cpu.h: WE32100 and WE32200 CPU

   Copyright (c) 2017-2022, Seth J. Morabito

   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 AUTHORS OR COPYRIGHT HOLDERS
   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.
*/

#ifndef _3B2_CPU_H_
#define _3B2_CPU_H_

#include "3b2_defs.h"

/* Execution Modes */
#define EX_LVL_KERN           0
#define EX_LVL_EXEC           1
#define EX_LVL_SUPR           2
#define EX_LVL_USER           3

#define MAX_HIST_SIZE         10000000
#define MIN_HIST_SIZE         64
#define MEM_SIZE              (cpu_unit.capac)

#define UNIT_V_MSIZE          (UNIT_V_UF)
#define UNIT_MSIZE            (1 << UNIT_V_MSIZE)

#define WD_MSB                0x80000000
#define HW_MSB                0x8000
#define BT_MSB                0x80
#define WORD_MASK             0xffffffff
#define HALF_MASK             0xffffu
#define BYTE_MASK             0xff

/* Exception Types */
#define RESET_EXCEPTION       0
#define PROCESS_EXCEPTION     1
#define STACK_EXCEPTION       2
#define NORMAL_EXCEPTION      3

/* Reset Exceptions */
#define OLD_PCB_FAULT         0
#define SYSTEM_DATA_FAULT     1
#define INTERRUPT_STACK_FAULT 2
#define EXTERNAL_RESET        3
#define NEW_PCB_FAULT         4
#define GATE_VECTOR_FAULT     6

/* Process Exceptions */
#define GATE_PCB_FAULT        1

/* Stack Exceptions */
#define STACK_BOUND           0
#define STACK_FAULT           1
#define INTERRUPT_ID_FETCH    3

/* Normal Exceptions */
#define INTEGER_ZERO_DIVIDE   0
#define TRACE_TRAP            1
#define ILLEGAL_OPCODE        2
#define RESERVED_OPCODE       3
#define INVALID_DESCRIPTOR    4
#define EXTERNAL_MEMORY_FAULT 5
#define N_GATE_VECTOR         6
#define ILLEGAL_LEVEL_CHANGE  7
#define RESERVED_DATATYPE     8
#define INTEGER_OVERFLOW      9
#define PRIVILEGED_OPCODE     10
#define BREAKPOINT_TRAP       14
#define PRIVILEGED_REGISTER   15

#define PSW_ET                0
#define PSW_TM                2
#define PSW_ISC               3
#define PSW_I                 7
#define PSW_R                 8
#define PSW_PM                9
#define PSW_CM                11
#define PSW_IPL               13
#define PSW_TE                17
#define PSW_C                 18
#define PSW_V                 19
#define PSW_Z                 20
#define PSW_N                 21
#define PSW_OE                22
#define PSW_CD                23
#define PSW_QIE               24
#define PSW_CFD               25

#define PSW_ET_MASK           3u
#define PSW_TM_MASK           (1u << PSW_TM)
#define PSW_ISC_MASK          (15u << PSW_ISC)
#define PSW_I_MASK            (1u << PSW_I)
#define PSW_R_MASK            (1u << PSW_R)
#define PSW_PM_MASK           (3u << PSW_PM)
#define PSW_CM_MASK           (3u << PSW_CM)
#define PSW_IPL_MASK          (15u << PSW_IPL)
#define PSW_TE_MASK           (1u << PSW_TE)
#define PSW_C_MASK            (1u << PSW_C)
#define PSW_V_MASK            (1u << PSW_V)
#define PSW_N_MASK            (1u << PSW_N)
#define PSW_Z_MASK            (1u << PSW_Z)
#define PSW_OE_MASK           (1u << PSW_OE)
#define PSW_CD_MASK           (1u << PSW_CD)
#define PSW_QIE_MASK          (1u << PSW_QIE)
#define PSW_CFD_MASK          (1u << PSW_CFD)
#define PSW_CUR_IPL           (((R[NUM_PSW] & PSW_IPL_MASK) >> PSW_IPL) & 0xf)

#if defined(REV3)
#define PSW_X                 26
#define PSW_AR                27
#define PSW_EXUC              28
#define PSW_EA                29

#define PSW_X_MASK            (1u << PSW_X)
#define PSW_AR_MASK           (1u << PSW_AR)
#define PSW_EXUC_MASK         (1u << PSW_EXUC)
#define PSW_EA_MASK           (1u << PSW_EA)
#endif

#if defined(REV3)
#define QIE_PSW_MASK          (PSW_EA_MASK|PSW_EXUC_MASK|PSW_X_MASK|    \
                               PSW_CFD_MASK|PSW_QIE_MASK|PSW_CD_MASK|PSW_OE_MASK| \
                               PSW_N_MASK|PSW_Z_MASK|PSW_V_MASK|PSW_C_MASK| \
                               PSW_TE_MASK|PSW_IPL_MASK|PSW_PM_MASK|PSW_I_MASK)
#else
#define QIE_PSW_MASK          (PSW_CFD_MASK|PSW_QIE_MASK|PSW_CD_MASK|PSW_OE_MASK| \
                               PSW_N_MASK|PSW_Z_MASK|PSW_V_MASK|PSW_C_MASK| \
                               PSW_TE_MASK|PSW_IPL_MASK|PSW_PM_MASK|PSW_I_MASK)
#endif

/* A helper to set the PSW, preserving read-only fields */
#define PSW_RO_MASK           0x17f   /* ET, TM, ISC, and R are read-only! */
#define WRITE_PSW(V)          (R[NUM_PSW] = ((R[NUM_PSW] & PSW_RO_MASK) | ((V) & ~PSW_RO_MASK)))

/* Exceptional conditions handled within the instruction loop */
#define ABORT_EXC             1 /* CPU exception  */

/* Contexts for aborts */
#define C_NONE                0 /* No context. Normal handling. */
#define C_NORMAL_GATE_VECTOR  1
#define C_PROCESS_GATE_PCB    2
#define C_PROCESS_OLD_PCB     3
#define C_PROCESS_NEW_PCB     4
#define C_RESET_GATE_VECTOR   5
#define C_RESET_INT_STACK     6
#define C_RESET_NEW_PCB       7
#define C_RESET_SYSTEM_DATA   8
#define C_STACK_FAULT         9

/* Register numbers */
#define NUM_FP                9
#define NUM_AP                10
#define NUM_PSW               11
#define NUM_SP                12
#define NUM_PCBP              13
#define NUM_ISP               14
#define NUM_PC                15

/* System board interrupt priority levels */
#define CPU_IPL_8             8
#define CPU_IPL_9             9
#define CPU_IPL_11            11
#define CPU_IPL_13            13
#define CPU_IPL_15            15

/* Processor permission levels */
#define L_KERNEL              0
#define L_EXEC                1
#define L_SUPER               2
#define L_USER                3

/* Currently selected processor permission level */
#define CPU_CM                (cpu_km ? L_KERNEL : ((R[NUM_PSW] >> PSW_CM) & 3))

/* Data types operated on by instructions. NB: These integer values
   have meaning when decoding instructions, so this is not just an
   enum. Please don't change them. */
#define UW                    0 /* Unsigned Word */
#define UH                    2 /* Unsigned Halfword */
#define BT                    3 /* Unsigned Byte */
#define WD                    4 /* Signed Word */
#define HW                    6 /* Signed Halfword */
#define SB                    7 /* Signed Byte */

#define NA                   -1

/*
 *
 * Mode                   Syntax     Mode          Reg.    Bytes    Notes
 * ----------------------------------------------------------------------
 * Absolute               $expr         7           15     5
 * Abs. Deferred          *$expr       14           15     5
 * Byte Disp.             expr(%rn)    12   0-10,12-15     2
 * Byte Disp. Def.        *expr(%rn)   13   0-10,12-15     2
 * Halfword Disp.         expr(%rn)    10   0-10,12-15     3
 * Halfword Disp. Def.    *expr(%rn)   11   0-10,12-15     3
 * Word Disp.             expr(%rn)     8   0-10,12-15     5
 * Word Disp. Def.        *expr(%rn)    9   0-10,12-15     5
 * AP Short Offset        so(%ap)       7         0-14     1         1
 * FP Short Offset        so(%fp)       6         0-14     1         1
 * Byte Immediate         &imm8         6           15     2         2,3
 * Halfword Immediate     &imm16        5           15     3         2,3
 * Word Immediate         &imm32        4           15     5         2,3
 * Positive Literal       &lit        0-3         0-15     1         2,3
 * Negative Literal       &lit         15         0-15     1         2,3
 * Register               %rn           4         0-14     1         1,3
 * Register Deferred      (%rn)         5   0-10,12-14     1         1
 * Expanded Op. Type      {type}opnd   14         0-14   2-6         4
 *
 * Notes:
 *
 * 1. Mode field has special meaning if register field is 15; see
 *    absolute or immediate mode.
 * 2. Mode may not be used for a destination operand.
 * 3. Mode may not be used if the instruction takes effective address
 *    of the operand.
 * 4. 'type' overrides instruction type; 'type' determines the operand
 *    type, except that it does not determine the length for immediate
 *    or literals or whether literals are signed or unsigned. 'opnd'
 *    determines actual address mode. For total bytes, add 1 to byte
 *    count for address mode determined by 'opnd'.
 *
 */

/*
 * Opcodes
 */
typedef enum {
    SPOPRD  = 0x02,
    SPOPD2  = 0x03,
    MOVAW   = 0x04,
    SPOPRT  = 0x06,
    SPOPT2  = 0x07,
    RET     = 0x08,
#if defined(REV3)
    CASWI   = 0x09,
    SETX    = 0x0A,
    CLRX    = 0x0B,
#endif
    MOVTRW  = 0x0C,
#if defined(REV3)
    TEDTH   = 0x0D,
    PACKB   = 0x0E,
    UNPACKB = 0x0F,
#endif
    SAVE    = 0x10,
    SPOPWD  = 0x13,
    EXTOP   = 0x14,
    SPOPWT  = 0x17,
    RESTORE = 0x18,
#if defined(REV3)
    DTH     = 0x19,
#endif
    SWAPWI  = 0x1C,
#if defined(REV3)
    TGEDTH  = 0x1D,
#endif
    SWAPHI  = 0x1E,
    SWAPBI  = 0x1F,
    POPW    = 0x20,
    SPOPRS  = 0x22,
    SPOPS2  = 0x23,
    JMP     = 0x24,
    CFLUSH  = 0x27,
    TSTW    = 0x28,
#if defined(REV3)
    DTB     = 0x29,
#endif
    TSTH    = 0x2A,
    TSTB    = 0x2B,
    CALL    = 0x2C,
#if defined(REV3)
    TGDTH   = 0x2D,
#endif
    BPT     = 0x2E,
    WAIT    = 0x2F,
    EMB     = 0x30, /* Multi-byte */
    SPOP    = 0x32,
    SPOPWS  = 0x33,
    JSB     = 0x34,
    BSBH    = 0x36,
    BSBB    = 0x37,
    BITW    = 0x38,
    BITH    = 0x3A,
    BITB    = 0x3B,
    CMPW    = 0x3C,
#if defined(REV3)
    TNEDTH  = 0x3D,
#endif
    CMPH    = 0x3E,
    CMPB    = 0x3F,
    RGEQ    = 0x40,
    BGEH    = 0x42,
    BGEB    = 0x43,
    RGTR    = 0x44,
    BGH     = 0x46,
    BGB     = 0x47,
    RLSS    = 0x48,
    BLH     = 0x4A,
    BLB     = 0x4B,
    RLEQ    = 0x4C,
#if defined(REV3)
    TEDTB   = 0x4D,
#endif
    BLEH    = 0x4E,
    BLEB    = 0x4F,
    RGEQU   = 0x50,
    BGEUH   = 0x52,
    BGEUB   = 0x53,
    RGTRU   = 0x54,
    BGUH    = 0x56,
    BGUB    = 0x57,
    RLSSU   = 0x58,
    BLUH    = 0x5A,
    BLUB    = 0x5B,
    RLEQU   = 0x5C,
#if defined(REV3)
    TGEDTB  = 0x5D,
#endif
    BLEUH   = 0x5E,
    BLEUB   = 0x5F,
    RVC     = 0x60,
    BVCH    = 0x62,
    BVCB    = 0x63,
    RNEQU   = 0x64,
    BNEH_D  = 0x66,
    BNEB_D  = 0x67,
    RVS     = 0x68,
    BVSH    = 0x6A,
    BVSB    = 0x6B,
    REQLU   = 0x6C,
#if defined(REV3)
    TGDTB   = 0x6D,
#endif
    BEH_D   = 0x6E,
    BEB_D   = 0x6F,
    NOP     = 0x70,
    NOP3    = 0x72,
    NOP2    = 0x73,
    RNEQ    = 0x74,
    BNEH    = 0x76,
    BNEB    = 0x77,
    RSB     = 0x78,
    BRH     = 0x7A,
    BRB     = 0x7B,
    REQL    = 0x7C,
#if defined(REV3)
    TNEDTB  = 0x7D,
#endif
    BEH     = 0x7E,
    BEB     = 0x7F,
    CLRW    = 0x80,
    CLRH    = 0x82,
    CLRB    = 0x83,
    MOVW    = 0x84,
    MOVH    = 0x86,
    MOVB    = 0x87,
    MCOMW   = 0x88,
    MCOMH   = 0x8A,
    MCOMB   = 0x8B,
    MNEGW   = 0x8C,
    MNEGH   = 0x8E,
    MNEGB   = 0x8F,
    INCW    = 0x90,
    INCH    = 0x92,
    INCB    = 0x93,
    DECW    = 0x94,
    DECH    = 0x96,
    DECB    = 0x97,
#if defined(REV3)
    RETQINT = 0x98,
    SUBPB2  = 0x9B,
#endif
    ADDW2   = 0x9C,
    ADDH2   = 0x9E,
    ADDB2   = 0x9F,
    PUSHW   = 0xA0,
#if defined(REV3)
    ADDPB2  = 0xA3,
#endif
    MODW2   = 0xA4,
    MODH2   = 0xA6,
    MODB2   = 0xA7,
    MULW2   = 0xA8,
    MULH2   = 0xAA,
    MULB2   = 0xAB,
    DIVW2   = 0xAC,
    DIVH2   = 0xAE,
    DIVB2   = 0xAF,
    ORW2    = 0xB0,
    ORH2    = 0xB2,
    ORB2    = 0xB3,
    XORW2   = 0xB4,
    XORH2   = 0xB6,
    XORB2   = 0xB7,
    ANDW2   = 0xB8,
    ANDH2   = 0xBA,
    ANDB2   = 0xBB,
    SUBW2   = 0xBC,
    SUBH2   = 0xBE,
    SUBB2   = 0xBF,
    ALSW3   = 0xC0,
    ARSW3   = 0xC4,
    ARSH3   = 0xC6,
    ARSB3   = 0xC7,
    INSFW   = 0xC8,
    INSFH   = 0xCA,
    INSFB   = 0xCB,
    EXTFW   = 0xCC,
    EXTFH   = 0xCE,
    EXTFB   = 0xCF,
    LLSW3   = 0xD0,
    LLSH3   = 0xD2,
    LLSB3   = 0xD3,
    LRSW3   = 0xD4,
    ROTW    = 0xD8,
#if defined(REV3)
    SUBPB3  = 0xDB,
#endif
    ADDW3   = 0xDC,
    ADDH3   = 0xDE,
    ADDB3   = 0xDF,
    PUSHAW  = 0xE0,
#if defined(REV3)
    ADDPB3  = 0xE3,
#endif
    MODW3   = 0xE4,
    MODH3   = 0xE6,
    MODB3   = 0xE7,
    MULW3   = 0xE8,
    MULH3   = 0xEA,
    MULB3   = 0xEB,
    DIVW3   = 0xEC,
    DIVH3   = 0xEE,
    DIVB3   = 0xEF,
    ORW3    = 0xF0,
    ORH3    = 0xF2,
    ORB3    = 0xF3,
    XORW3   = 0xF4,
    XORH3   = 0xF6,
    XORB3   = 0xF7,
    ANDW3   = 0xF8,
    ANDH3   = 0xFA,
    ANDB3   = 0xFB,
    SUBW3   = 0xFC,
    SUBH3   = 0xFE,
    SUBB3   = 0xFF,
    MVERNO  = 0x3009,
    ENBVJMP = 0x300d,
    DISVJMP = 0x3013,
    MOVBLW  = 0x3019,
    STREND  = 0x301f,
    INTACK  = 0x302f,
    STRCPY  = 0x3035,
    RETG    = 0x3045,
    GATE    = 0x3061,
    CALLPS  = 0x30ac,
#if defined(REV3)
    UCALLPS = 0x30c0,
#endif
    RETPS   = 0x30c8
} opcode;

/*
 * Each instruction expects operands of a certain type.
 *
 * The large majority of instructions expect operands that have a
 * descriptor as the first byte. This descriptor carries all the
 * information necessary to compute the addressing mode of the
 * operand.
 *
 * e.g.:
 *
 *   MOVB 6(%r1),%r0
 *   +------+------+------+------+
 *   | 0x87 | 0xc1 | 0x06 | 0x40 |
 *   +------+------+------+------+
 *           ^^^^^^
 *       Descriptor byte. mode = 13 (0x0c), register = 1 (0x01)
 *
 *
 * Branch instructions have either an 8-bit or a 16-bit signed
 * displacement value, and lack a descriptor byte.
 *
 * e.g.:
 *
 *   BCCB 0x03
 *   +------+------+
 *   | 0x53 | 0x03 |            8-bit displacement
 *   +------+------+
 *
 *   BCCH 0x01ff
 *   +------+------+------+
 *   | 0x52 | 0xff | 0x01 |    16-bit displacement
 *   +------+------+------+
 *
 *
 * TODO: Describe coprocessor instructions
 *
 */
typedef enum {
    OP_NONE, /* NULL type */
    OP_DESC, /* Descriptor byte */
    OP_DESB, /* Descriptor with byte displacement (WE32200 only) */
    OP_DESH, /* Descriptor with halfword displacement (WE32200 only) */
    OP_BYTE, /* 8-bit signed value */
    OP_HALF, /* 16-bit signed value */
    OP_COPR  /* Coprocessor instruction */
} op_mode;

/* Describes a CPU opcode.
 *
 * e.g.:
 *
 *    {0x09, 3, OP_DESC, WD, "CASWI", 0, 1, -1, 2}
 *
 *  - Opcode 0x09.
 *  - Followed by three operands.
 *  - Operands use descriptor bytes.
 *  - Default data type is word (32 bit).
 *  - Operand 0 is source 1.
 *  - Operand 1 is source 2.
 *  - Operand 2 is destination.
 *
 */
typedef struct {
    uint16  opcode;
    int8    op_count;    /* Number of operands */
    op_mode mode;        /* Dispatch mode      */
    int8    dtype;       /* Default data type  */
    char    mnemonic[8];
    int8    src_op1;
    int8    src_op2;
    int8    src_op3;
    int8    dst_op;
} mnemonic;

/*
 * Structure that describes each operand in a decoded instruction
 */
typedef struct {
    uint8   mode;        /* Embedded data addressing mode */
    uint8   reg;         /* Operand register (0-15) */
#if defined(REV3)
    uint8   reg2;        /* Operand register 2 (16-31) */
#endif
    int8    dtype;       /* Default type for the operand */
    int8    etype;       /* Expanded type (-1 if none) */
    union {
        uint32 w;
        uint16 h;
        uint8  b;
    } embedded;          /* Data consumed as part of the instruction
                            stream, i.e. literals, displacement,
                            etc. */
    uint32  data;        /* Data either read or written during
                            instruction execution */
} operand;

/*
 * An inst is a combination of a decoded instruction and
 * 0 to 4 operands. Also used for history record keeping.
 */
typedef struct {
    mnemonic *mn;
    uint32 psw;
    uint32 sp;
    uint32 pc;
    t_bool valid;
    operand operands[4];
} instr;

/* Function prototypes */
t_stat sys_boot(int32 flag, CONST char *ptr);
t_stat cpu_svc(UNIT *uptr);
t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw);
t_stat cpu_reset(DEVICE *dptr);
t_stat cpu_set_size(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_set_hist(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
t_stat cpu_show_hist(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat cpu_show_virt(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat cpu_show_stack(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat cpu_show_cio(FILE *st, UNIT *uptr, int32 val, CONST void *desc);
t_stat cpu_set_halt(UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_clear_halt(UNIT *uptr, int32 val, char *cptr, void *desc);
t_stat cpu_boot(int32 unit_num, DEVICE *dptr);
t_stat cpu_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
CONST char *cpu_description(DEVICE *dptr);

t_bool cpu_is_pc_a_subroutine_call (t_addr **ret_addrs);

void cpu_register_name(uint8 reg, char *buf, size_t len);
void cpu_show_operand(FILE *st, operand *op);
void fprint_sym_hist(FILE *st, instr *ip);
t_stat fprint_sym_m(FILE *of, t_addr addr, t_value *val);

instr *cpu_next_instruction(void);

uint8 decode_instruction(instr *instr);
void cpu_on_interrupt(uint16 vec);
void cpu_abort(uint8 et, uint8 isc);

/* Helper macros */

#define MOD(A,B,OP1,OP2,SZ) {                                      \
        if (op_signed(OP1) && !op_signed(OP2)) {                   \
            result = (SZ)(B) % (A);                                \
        } else if (!op_signed(OP1) && op_signed(OP2)) {            \
            result = (B) % (SZ)(A);                                \
        } else if (op_signed(OP1)  && op_signed(OP2)) {            \
            result = (SZ)(B) % (SZ)(A);                            \
        } else {                                                   \
            result = (B) % (A);                                    \
        }                                                          \
    }

#define DIV(A,B,OP1,OP2,SZ) {                                      \
        if (op_signed(OP1) && !op_signed(OP2)) {                   \
            result = (SZ)(B) / (A);                                \
        } else if (!op_signed(OP1) && op_signed(OP2)) {            \
            result = (B) / (SZ)(A);                                \
        } else if (op_signed(OP1)  && op_signed(OP2)) {            \
            result = (SZ)(B) / (SZ)(A);                            \
        } else {                                                   \
            result = (B) / (A);                                    \
        }                                                          \
    }

#define OP_R_W(d,a,p) {                         \
        (d) = (uint32) (a)[(p)++];              \
        (d) |= (uint32) (a)[(p)++] << 8u;       \
        (d) |= (uint32) (a)[(p)++] << 16u;      \
        (d) |= (uint32) (a)[(p)++] << 24u;      \
    }

#define OP_R_H(d,a,p) {                         \
        (d) = (uint16) (a)[(p)++];              \
        (d) |= (uint16) (a)[(p)++] << 8u;       \
    }

#define OP_R_B(d,a,p) {                        \
        (d) = (uint8) (a)[(p)++];              \
    }

#define CPU_SET_INT(flags) (sbd_int_req |= flags)
#define CPU_CLR_INT(flags) (sbd_int_req &= ~(flags))

extern t_bool rom_loaded;
extern volatile int32 stop_reason;
extern uint16 sbd_int_req;
extern instr *cpu_instr;
extern t_bool cpu_nmi;
extern uint8 *ROM;
extern uint8 *RAM;
extern uint32 R[NUM_REGISTERS];
extern REG cpu_reg[];
extern UNIT cpu_unit;
extern uint8 fault;
extern t_bool cpu_km;

#endif
