simh-testsetgenerator/3B2/3b2_cpu.h
Seth Morabito 84bf5f4d14 3b2: Update README.md and correct line endings
This change updates the 3B2 README.md file, and fixes
all line endings on 3B2 source files.
2022-09-19 09:37:17 -07:00

684 lines
21 KiB
C

/* 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