AltairZ80: Added Motorola 68000 CPU support for CP/M-68K, support for Altair mini-disk format, added descriptions for all device registers
This commit is contained in:
parent
709016c356
commit
589aca19f4
43 changed files with 46967 additions and 1095 deletions
|
@ -27,7 +27,8 @@
|
||||||
Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license)
|
Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "altairz80_defs.h"
|
#include "m68k.h"
|
||||||
|
#include "assert.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#define SWITCHCPU_DEFAULT 0xfd
|
#define SWITCHCPU_DEFAULT 0xfd
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ void out(const uint32 Port, const uint32 Value);
|
||||||
uint32 in(const uint32 Port);
|
uint32 in(const uint32 Port);
|
||||||
void altairz80_init(void);
|
void altairz80_init(void);
|
||||||
t_stat sim_instr(void);
|
t_stat sim_instr(void);
|
||||||
t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM);
|
t_stat install_bootrom(const int32 bootrom[], const int32 size, const int32 addr, const int32 makeROM);
|
||||||
uint8 GetBYTEWrapper(const uint32 Addr);
|
uint8 GetBYTEWrapper(const uint32 Addr);
|
||||||
void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
|
void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
|
||||||
uint8 GetByteDMA(const uint32 Addr);
|
uint8 GetByteDMA(const uint32 Addr);
|
||||||
|
@ -254,6 +255,9 @@ static uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue
|
||||||
static int32 pcq_p = 0; /* PC queue ptr */
|
static int32 pcq_p = 0; /* PC queue ptr */
|
||||||
static REG *pcq_r = NULL; /* PC queue reg ptr */
|
static REG *pcq_r = NULL; /* PC queue reg ptr */
|
||||||
|
|
||||||
|
uint32 m68k_registers[M68K_REG_CPU_TYPE + 1]; /* M68K CPU registers */
|
||||||
|
|
||||||
|
|
||||||
/* data structure for IN/OUT instructions */
|
/* data structure for IN/OUT instructions */
|
||||||
struct idev {
|
struct idev {
|
||||||
int32 (*routine)(const int32, const int32, const int32);
|
int32 (*routine)(const int32, const int32, const int32);
|
||||||
|
@ -262,107 +266,275 @@ struct idev {
|
||||||
static int32 switcherPort = SWITCHCPU_DEFAULT;
|
static int32 switcherPort = SWITCHCPU_DEFAULT;
|
||||||
static struct idev oldSwitcherDevice = { NULL };
|
static struct idev oldSwitcherDevice = { NULL };
|
||||||
|
|
||||||
|
// CPU_INDEX_8080 is defined in altairz80_defs.h
|
||||||
|
#define CPU_INDEX_8086 26
|
||||||
|
#define CPU_INDEX_M68K 53
|
||||||
|
|
||||||
REG cpu_reg[] = {
|
REG cpu_reg[] = {
|
||||||
{ HRDATA (AF, AF_S, 16) },
|
// 8080 and Z80 registers
|
||||||
{ HRDATA (BC, BC_S, 16) },
|
{ HRDATAD (AF, AF_S, 16, "8080 / Z80 Accumulator Flag register")
|
||||||
{ HRDATA (DE, DE_S, 16) },
|
}, /* 0 */
|
||||||
{ HRDATA (HL, HL_S, 16) },
|
{ HRDATAD (BC, BC_S, 16, "8080 / Z80 BC register")
|
||||||
{ HRDATA (IX, IX_S, 16) },
|
}, /* 1 */
|
||||||
{ HRDATA (IY, IY_S, 16) },
|
{ HRDATAD (DE, DE_S, 16, "8080 / Z80 DE register")
|
||||||
{ HRDATA (PC, PC_S, 16 + MAXBANKSLOG2) }, /* 8080 / Z80 PC [6] */
|
}, /* 2 */
|
||||||
{ HRDATA (PCX, PCX_S, 16 + MAXBANKSLOG2) }, /* 8086 PC [7] */
|
{ HRDATAD (HL, HL_S, 16, "8080 / Z80 HL register")
|
||||||
{ HRDATA (SP, SP_S, 16) },
|
}, /* 3 */
|
||||||
{ HRDATA (AF1, AF1_S, 16) },
|
{ HRDATAD (PC, PC_S, 16 + MAXBANKSLOG2, "8080 / Z80 Program Counter register")
|
||||||
{ HRDATA (BC1, BC1_S, 16) },
|
}, /* 4 8080 / Z80 */
|
||||||
{ HRDATA (DE1, DE1_S, 16) },
|
{ HRDATAD (SP, SP_S, 16, "8080 / Z80 Stack Pointer register")
|
||||||
{ HRDATA (HL1, HL1_S, 16) },
|
}, /* 5 */
|
||||||
{ GRDATA (IFF, IFF_S, 2, 2, 0) },
|
|
||||||
{ FLDATA (IR, IR_S, 8) },
|
// Z80 registers
|
||||||
{ HRDATA (AX, AX_S, 16) }, /* 8086 */
|
{ HRDATAD (IX, IX_S, 16, "Z80 IX register")
|
||||||
{ GRDATA (AL, AX_S, 16, 8, 0) }, /* 8086, low 8 bits of AX */
|
}, /* 8 */
|
||||||
{ GRDATA (AH, AX_S, 16, 8, 8) }, /* 8086, high 8 bits of AX */
|
{ HRDATAD (IY, IY_S, 16, "Z80 IY register")
|
||||||
{ HRDATA (BX, BX_S, 16) }, /* 8086 */
|
}, /* 9 */
|
||||||
{ GRDATA (BL, BX_S, 16, 8, 0) }, /* 8086, low 8 bits of BX */
|
{ HRDATAD (AF1, AF1_S, 16, "Z80 Alternate Accumulator Flag register")
|
||||||
{ GRDATA (BH, BX_S, 16, 8, 8) }, /* 8086, high 8 bits of BX */
|
}, /* 10 */
|
||||||
{ HRDATA (CX, CX_S, 16) }, /* 8086 */
|
{ HRDATAD (BC1, BC1_S, 16, "Z80 Alternate BC register")
|
||||||
{ GRDATA (CL, CX_S, 16, 8, 0) }, /* 8086, low 8 bits of CX */
|
}, /* 11 */
|
||||||
{ GRDATA (CH, CX_S, 16, 8, 8) }, /* 8086, high 8 bits of CX */
|
{ HRDATAD (DE1, DE1_S, 16, "Z80 Alternate DE register")
|
||||||
{ HRDATA (DX, DX_S, 16) }, /* 8086 */
|
}, /* 12 */
|
||||||
{ GRDATA (DL, DX_S, 16, 8, 0) }, /* 8086, low 8 bits of DX */
|
{ HRDATAD (HL1, HL1_S, 16, "Z80 Alternate HL register")
|
||||||
{ GRDATA (DH, DX_S, 16, 8, 8) }, /* 8086, high 8 bits of DX */
|
}, /* 13 */
|
||||||
{ HRDATA (SPX, SPX_S, 16) }, /* 8086 */
|
{ GRDATAD (IFF, IFF_S, 2, 2, 0, "Z80 Interrupt Flip Flop register")
|
||||||
{ HRDATA (BP, BP_S, 16) }, /* 8086, Base Pointer */
|
}, /* 6 */
|
||||||
{ HRDATA (SI, SI_S, 16) }, /* 8086, Source Index */
|
{ FLDATAD (IR, IR_S, 8, "8Z80 Interrupt (upper) / Refresh (lower) register")
|
||||||
{ HRDATA (DI, DI_S, 16) }, /* 8086, Destination Index */
|
}, /* 7 */
|
||||||
{ HRDATA (CS, CS_S, 16) }, /* 8086, Code Segment */
|
|
||||||
{ HRDATA (DS, DS_S, 16) }, /* 8086, Data Segment */
|
// 8086 registers
|
||||||
{ HRDATA (ES, ES_S, 16) }, /* 8086, Extra Segment */
|
{ HRDATAD (AX, AX_S, 16, "8086 AX register")
|
||||||
{ HRDATA (SS, SS_S, 16) }, /* 8086, Stack Segment */
|
}, /* 14 8086 */
|
||||||
{ HRDATA (FLAGS, FLAGS_S, 16) }, /* 8086, FLAGS */
|
{ GRDATAD (AL, AX_S, 16, 8, 0, "8086 low bits of AX register")
|
||||||
{ HRDATA (IP, IP_S, 16), REG_RO }, /* 8086, set via PC */
|
}, /* 15 8086, low 8 bits of AX */
|
||||||
{ FLDATA (OPSTOP, cpu_unit.flags, UNIT_CPU_V_OPSTOP), REG_HRO },
|
{ GRDATAD (AH, AX_S, 16, 8, 8, "8086 high bits of AX register")
|
||||||
{ HRDATA (SR, SR, 8) },
|
}, /* 16 8086, high 8 bits of AX */
|
||||||
{ HRDATA (BANK, bankSelect, MAXBANKSLOG2) },
|
{ HRDATAD (BX, BX_S, 16, "8086 BX register")
|
||||||
{ HRDATA (COMMON, common, 32) },
|
}, /* 17 8086 */
|
||||||
{ HRDATA (SWITCHERPORT, switcherPort, 8), },
|
{ GRDATAD (BL, BX_S, 16, 8, 0, "8086 low bits of BX register")
|
||||||
{ DRDATA (CLOCK, clockFrequency, 32) },
|
}, /* 18 8086, low 8 bits of BX */
|
||||||
{ DRDATA (SLICE, sliceLength, 16) },
|
{ GRDATAD (BH, BX_S, 16, 8, 8, "8086 high bits of BX register")
|
||||||
{ DRDATA (TSTATES, executedTStates, 32), REG_RO },
|
}, /* 19 8086, high 8 bits of BX */
|
||||||
{ HRDATA (CAPACITY, cpu_unit.capac, 32), REG_RO },
|
{ HRDATAD (CX, CX_S, 16, "8086 CX register")
|
||||||
{ HRDATA (PREVCAP, previousCapacity, 32), REG_RO },
|
}, /* 20 8086 */
|
||||||
{ BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC },
|
{ GRDATAD (CL, CX_S, 16, 8, 0, "8086 low bits of CX register")
|
||||||
{ DRDATA (PCQP, pcq_p, PCQ_SIZE_LOG2), REG_HRO },
|
}, /* 21 8086, low 8 bits of CX */
|
||||||
{ HRDATA (WRU, sim_int_char, 8) },
|
{ GRDATAD (CH, CX_S, 16, 8, 8, "8086 high bits of CX register")
|
||||||
|
}, /* 22 8086, high 8 bits of CX */
|
||||||
|
{ HRDATAD (DX, DX_S, 16, "8086 DX register")
|
||||||
|
}, /* 23 8086 */
|
||||||
|
{ GRDATAD (DL, DX_S, 16, 8, 0, "8086 low bits of DX register")
|
||||||
|
}, /* 24 8086, low 8 bits of DX */
|
||||||
|
{ GRDATAD (DH, DX_S, 16, 8, 8, "8086 high bits of DX register")
|
||||||
|
}, /* 25 8086, high 8 bits of DX */
|
||||||
|
{ HRDATAD (PCX, PCX_S, 16 + MAXBANKSLOG2, "8086 Program Counter register")
|
||||||
|
}, /* 26 8086, Program Counter */
|
||||||
|
{ HRDATAD (SPX, SPX_S, 16, "8086 Stack Pointer register")
|
||||||
|
}, /* 27 8086, Stack Pointer */
|
||||||
|
{ HRDATAD (BP, BP_S, 16, "8086 Base Pointer register")
|
||||||
|
}, /* 28 8086, Base Pointer */
|
||||||
|
{ HRDATAD (SI, SI_S, 16, "8086 Source Index register")
|
||||||
|
}, /* 29 8086, Source Index */
|
||||||
|
{ HRDATAD (DI, DI_S, 16, "8086 Destination Index register")
|
||||||
|
}, /* 30 8086, Destination Index */
|
||||||
|
{ HRDATAD (CS, CS_S, 16, "8086 Code Segment register")
|
||||||
|
}, /* 31 8086, Code Segment */
|
||||||
|
{ HRDATAD (DS, DS_S, 16, "8086 Data Segment register")
|
||||||
|
}, /* 32 8086, Data Segment */
|
||||||
|
{ HRDATAD (ES, ES_S, 16, "8086 Extra Segment register")
|
||||||
|
}, /* 33 8086, Extra Segment */
|
||||||
|
{ HRDATAD (SS, SS_S, 16, "8086 Stack Segment register")
|
||||||
|
}, /* 34 8086, Stack Segment */
|
||||||
|
{ HRDATAD (FLAGS, FLAGS_S, 16, "8086 Flag register")
|
||||||
|
}, /* 35 8086, FLAGS */
|
||||||
|
{ HRDATAD (IP, IP_S, 16, "8086 Instruction Pointer register"),
|
||||||
|
REG_RO }, /* 36 8086, set via PC */
|
||||||
|
|
||||||
|
// M68K registers
|
||||||
|
{ HRDATAD (M68K_D0, m68k_registers[M68K_REG_D0], 32, "M68K D0 register"),
|
||||||
|
}, /* 37 M68K, D0 */
|
||||||
|
{ HRDATAD (M68K_D1, m68k_registers[M68K_REG_D1], 32, "M68K D1 register"),
|
||||||
|
}, /* 38 M68K, D1 */
|
||||||
|
{ HRDATAD (M68K_D2, m68k_registers[M68K_REG_D2], 32, "M68K D2 register"),
|
||||||
|
}, /* 39 M68K, D2 */
|
||||||
|
{ HRDATAD (M68K_D3, m68k_registers[M68K_REG_D3], 32, "M68K D3 register"),
|
||||||
|
}, /* 40 M68K, D3 */
|
||||||
|
{ HRDATAD (M68K_D4, m68k_registers[M68K_REG_D4], 32, "M68K D4 register"),
|
||||||
|
}, /* 41 M68K, D4 */
|
||||||
|
{ HRDATAD (M68K_D5, m68k_registers[M68K_REG_D5], 32, "M68K D5 register"),
|
||||||
|
}, /* 42 M68K, D5 */
|
||||||
|
{ HRDATAD (M68K_D6, m68k_registers[M68K_REG_D6], 32, "M68K D6 register"),
|
||||||
|
}, /* 43 M68K, D6 */
|
||||||
|
{ HRDATAD (M68K_D7, m68k_registers[M68K_REG_D7], 32, "M68K D7 register"),
|
||||||
|
}, /* 44 M68K, D7 */
|
||||||
|
{ HRDATAD (M68K_A0, m68k_registers[M68K_REG_A0], 32, "M68K A0 register"),
|
||||||
|
}, /* 45 M68K, A0 */
|
||||||
|
{ HRDATAD (M68K_A1, m68k_registers[M68K_REG_A1], 32, "M68K A1 register"),
|
||||||
|
}, /* 46 M68K, A1 */
|
||||||
|
{ HRDATAD (M68K_A2, m68k_registers[M68K_REG_A2], 32, "M68K A2 register"),
|
||||||
|
}, /* 47 M68K, A2 */
|
||||||
|
{ HRDATAD (M68K_A3, m68k_registers[M68K_REG_A3], 32, "M68K A3 register"),
|
||||||
|
}, /* 48 M68K, A3 */
|
||||||
|
{ HRDATAD (M68K_A4, m68k_registers[M68K_REG_A4], 32, "M68K A4 register"),
|
||||||
|
}, /* 49 M68K, A4 */
|
||||||
|
{ HRDATAD (M68K_A5, m68k_registers[M68K_REG_A5], 32, "M68K A5 register"),
|
||||||
|
}, /* 50 M68K, A5 */
|
||||||
|
{ HRDATAD (M68K_A6, m68k_registers[M68K_REG_A6], 32, "M68K A6 register"),
|
||||||
|
}, /* 51 M68K, A6 */
|
||||||
|
{ HRDATAD (M68K_A7, m68k_registers[M68K_REG_A7], 32, "M68K A7 register"),
|
||||||
|
}, /* 52 M68K, A7 */
|
||||||
|
{ HRDATAD (M68K_PC, m68k_registers[M68K_REG_PC], 32, "M68K Program Counter register"),
|
||||||
|
}, /* 53 M68K, PC */
|
||||||
|
{ HRDATAD (M68K_SR, m68k_registers[M68K_REG_SR], 32, "M68K Status Register"),
|
||||||
|
}, /* 54 M68K, SR */
|
||||||
|
{ HRDATAD (M68K_SP, m68k_registers[M68K_REG_SP], 32, "M68K Stack Pointer register"),
|
||||||
|
}, /* 55 M68K, SP */
|
||||||
|
{ HRDATAD (M68K_USP, m68k_registers[M68K_REG_USP], 32, "M68K User Stack Pointer register"),
|
||||||
|
}, /* 56 M68K, USP */
|
||||||
|
{ HRDATAD (M68K_ISP, m68k_registers[M68K_REG_ISP], 32, "M68K Interrupt Stack Pointer register"),
|
||||||
|
}, /* 57 M68K, ISP */
|
||||||
|
{ HRDATAD (M68K_MSP, m68k_registers[M68K_REG_MSP], 32, "M68K Master Stack Pointer register"),
|
||||||
|
}, /* 58 M68K, MSP */
|
||||||
|
{ HRDATAD (M68K_SFC, m68k_registers[M68K_REG_SFC], 32, "M68K Source Function Code register"),
|
||||||
|
}, /* 59 M68K, SFC */
|
||||||
|
{ HRDATAD (M68K_DFC, m68k_registers[M68K_REG_DFC], 32, "M68K Destination Function Code register"),
|
||||||
|
}, /* 60 M68K, DFC */
|
||||||
|
{ HRDATAD (M68K_VBR, m68k_registers[M68K_REG_VBR], 32, "M68K Vector Base Register"),
|
||||||
|
}, /* 61 M68K, VBR */
|
||||||
|
{ HRDATAD (M68K_CACR, m68k_registers[M68K_REG_CACR], 32, "M68K Cache Control Register"),
|
||||||
|
}, /* 62 M68K, CACR */
|
||||||
|
{ HRDATAD (M68K_CAAR, m68k_registers[M68K_REG_CAAR], 32, "M68K Cache Address Register"),
|
||||||
|
}, /* 63 M68K, CAAR */
|
||||||
|
{ HRDATAD (M68K_PREF_ADDR, m68k_registers[M68K_REG_PREF_ADDR], 32, "M68K Last Prefetch Address register"),
|
||||||
|
}, /* 64 M68K, PREF_ADDR */
|
||||||
|
{ HRDATAD (M68K_PREF_DATA, m68k_registers[M68K_REG_PREF_DATA], 32, "M68K Last Prefetch Data register"),
|
||||||
|
}, /* 65 M68K, PREF_DATA */
|
||||||
|
{ HRDATAD (M68K_PPC, m68k_registers[M68K_REG_PPC], 32, "M68K Previous Proram Counter register"),
|
||||||
|
}, /* 66 M68K, PPC */
|
||||||
|
{ HRDATAD (M68K_IR, m68k_registers[M68K_REG_IR], 32, "M68K Instruction Register"),
|
||||||
|
}, /* 67 M68K, IR */
|
||||||
|
{ HRDATAD (M68K_CPU_TYPE, m68k_registers[M68K_REG_CPU_TYPE], 32, "M68K CPU Type register"),
|
||||||
|
REG_RO }, /* 68 M68K, CPU_TYPE */
|
||||||
|
|
||||||
|
// Pseudo registers
|
||||||
|
{ FLDATAD (OPSTOP, cpu_unit.flags, UNIT_CPU_V_OPSTOP, "Stop on invalid operation pseudo register"),
|
||||||
|
REG_HRO }, /* 69 */
|
||||||
|
{ HRDATAD (SR, SR, 8, "Front panel switches pseudo register"),
|
||||||
|
}, /* 70 */
|
||||||
|
{ HRDATAD (BANK, bankSelect, MAXBANKSLOG2, "Active bank pseudo register"),
|
||||||
|
}, /* 71 */
|
||||||
|
{ HRDATAD (COMMON, common, 32, "Starting address of common memory pseudo register"),
|
||||||
|
}, /* 72 */
|
||||||
|
{ HRDATAD (SWITCHERPORT, switcherPort, 8, "I/O port for CPU switcher pseudo register"),
|
||||||
|
}, /* 73 */
|
||||||
|
{ DRDATAD (CLOCK, clockFrequency, 32, "Clock frequency in kHz for 8080 / Z80 pseudo register"),
|
||||||
|
}, /* 74 */
|
||||||
|
{ DRDATAD (SLICE, sliceLength, 16, "Length of time slice for 8080 / Z80 pseudo register"),
|
||||||
|
}, /* 75 */
|
||||||
|
{ DRDATAD (TSTATES, executedTStates, 32, "Executed t-states for 8080 / Z80 pseudo register"),
|
||||||
|
REG_RO }, /* 76 */
|
||||||
|
{ HRDATAD (CAPACITY, cpu_unit.capac, 32, "Size of RAM pseudo register"),
|
||||||
|
REG_RO }, /* 77 */
|
||||||
|
{ HRDATAD (PREVCAP, previousCapacity, 32, "Previous size of RAM pseudo register"),
|
||||||
|
REG_RO }, /* 78 */
|
||||||
|
{ BRDATAD (PCQ, pcq, 16, 16, PCQ_SIZE, "Program counter circular buffer for 8080 /Z80 pseudo register"),
|
||||||
|
REG_RO + REG_CIRC }, /* 79 */
|
||||||
|
{ DRDATAD (PCQP, pcq_p, PCQ_SIZE_LOG2, "Circular buffer head for 8080 / Z80 pseudo register"),
|
||||||
|
REG_HRO }, /* 80 */
|
||||||
|
{ HRDATAD (WRU, sim_int_char, 8, "Interrupt character pseudo register"),
|
||||||
|
}, /* 81 */
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB cpu_mod[] = {
|
static MTAB cpu_mod[] = {
|
||||||
{ MTAB_XTD | MTAB_VDV, CHIP_TYPE_8080, NULL, "8080", &cpu_set_chiptype },
|
{ MTAB_XTD | MTAB_VDV, CHIP_TYPE_8080, NULL, "8080", &cpu_set_chiptype,
|
||||||
{ MTAB_XTD | MTAB_VDV, CHIP_TYPE_Z80, NULL, "Z80", &cpu_set_chiptype },
|
NULL, NULL, "Chooses 8080 CPU"},
|
||||||
{ MTAB_XTD | MTAB_VDV, CHIP_TYPE_8086, NULL, "8086", &cpu_set_chiptype },
|
{ MTAB_XTD | MTAB_VDV, CHIP_TYPE_Z80, NULL, "Z80", &cpu_set_chiptype,
|
||||||
{ UNIT_CPU_OPSTOP, UNIT_CPU_OPSTOP, "ITRAP", "ITRAP", NULL, &chip_show },
|
NULL, NULL, "Chooses Z80 CPU" },
|
||||||
{ UNIT_CPU_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL, &chip_show },
|
{ MTAB_XTD | MTAB_VDV, CHIP_TYPE_8086, NULL, "8086", &cpu_set_chiptype,
|
||||||
{ UNIT_CPU_STOPONHALT, UNIT_CPU_STOPONHALT,"STOPONHALT", "STOPONHALT", NULL },
|
NULL, NULL, "Chooses 8086 CPU" },
|
||||||
{ UNIT_CPU_STOPONHALT, 0, "LOOPONHALT", "LOOPONHALT", NULL },
|
{ MTAB_XTD | MTAB_VDV, CHIP_TYPE_M68K, NULL, "M68K", &cpu_set_chiptype,
|
||||||
{ UNIT_CPU_BANKED, UNIT_CPU_BANKED, "BANKED", "BANKED", &cpu_set_banked },
|
NULL, NULL, "Chooses M68K CPU" },
|
||||||
{ UNIT_CPU_BANKED, 0, "NONBANKED", "NONBANKED", &cpu_set_nonbanked },
|
{ UNIT_CPU_OPSTOP, UNIT_CPU_OPSTOP, "ITRAP", "ITRAP", NULL, &chip_show,
|
||||||
{ UNIT_CPU_ALTAIRROM, UNIT_CPU_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom },
|
NULL, "Stop on illegal instruction" },
|
||||||
{ UNIT_CPU_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", &cpu_set_noaltairrom},
|
{ UNIT_CPU_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL, &chip_show,
|
||||||
{ UNIT_CPU_VERBOSE, UNIT_CPU_VERBOSE, "VERBOSE", "VERBOSE", NULL, &cpu_show },
|
NULL, "Do not stop on illegal instruction" },
|
||||||
{ UNIT_CPU_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_CPU_STOPONHALT, UNIT_CPU_STOPONHALT,"STOPONHALT", "STOPONHALT", NULL,
|
||||||
{ MTAB_VDV, 0, NULL, "CLEARMEMORY", &cpu_clear_command },
|
NULL, NULL, "Stop on halt instruction" },
|
||||||
{ UNIT_CPU_MMU, UNIT_CPU_MMU, "MMU", "MMU", NULL },
|
{ UNIT_CPU_STOPONHALT, 0, "LOOPONHALT", "LOOPONHALT", NULL,
|
||||||
{ UNIT_CPU_MMU, 0, "NOMMU", "NOMMU", &cpu_set_nommu },
|
NULL, NULL, "Enter loop on halt instruction" },
|
||||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "MEMORY", &cpu_set_memory },
|
{ UNIT_CPU_BANKED, UNIT_CPU_BANKED, "BANKED", "BANKED", &cpu_set_banked,
|
||||||
{ UNIT_CPU_SWITCHER, UNIT_CPU_SWITCHER, "SWITCHER", "SWITCHER", &cpu_set_switcher, &cpu_show_switcher },
|
NULL, NULL, "Enable banked memory for 8080 / Z80" },
|
||||||
{ UNIT_CPU_SWITCHER, 0, "NOSWITCHER", "NOSWITCHER", &cpu_reset_switcher, &cpu_show_switcher },
|
{ UNIT_CPU_BANKED, 0, "NONBANKED", "NONBANKED", &cpu_set_nonbanked,
|
||||||
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AZ80", &cpu_set_ramtype },
|
NULL, NULL, "Disable banked memory for 8080 / Z80" },
|
||||||
{ MTAB_XTD | MTAB_VDV, 1, NULL, "HRAM", &cpu_set_ramtype },
|
{ UNIT_CPU_ALTAIRROM, UNIT_CPU_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom,
|
||||||
{ MTAB_XTD | MTAB_VDV, 2, NULL, "VRAM", &cpu_set_ramtype },
|
NULL, NULL, "Enable Altair ROM for 8080 / Z80" },
|
||||||
{ MTAB_XTD | MTAB_VDV, 3, NULL, "CRAM", &cpu_set_ramtype },
|
{ UNIT_CPU_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", &cpu_set_noaltairrom,
|
||||||
{ MTAB_VDV, 4, NULL, "4KB", &cpu_set_size },
|
NULL, NULL, "Disable Altair ROM for 8080 / Z80"},
|
||||||
{ MTAB_VDV, 8, NULL, "8KB", &cpu_set_size },
|
{ UNIT_CPU_VERBOSE, UNIT_CPU_VERBOSE, "VERBOSE", "VERBOSE", NULL, &cpu_show,
|
||||||
{ MTAB_VDV, 12, NULL, "12KB", &cpu_set_size },
|
NULL, "Enable verbose messages" },
|
||||||
{ MTAB_VDV, 16, NULL, "16KB", &cpu_set_size },
|
{ UNIT_CPU_VERBOSE, 0, "QUIET", "QUIET", NULL, NULL,
|
||||||
{ MTAB_VDV, 20, NULL, "20KB", &cpu_set_size },
|
NULL, "Disable verbose messages" },
|
||||||
{ MTAB_VDV, 24, NULL, "24KB", &cpu_set_size },
|
{ MTAB_VDV, 0, NULL, "CLEARMEMORY", &cpu_clear_command,
|
||||||
{ MTAB_VDV, 28, NULL, "28KB", &cpu_set_size },
|
NULL, NULL, "Clears the RAM" },
|
||||||
{ MTAB_VDV, 32, NULL, "32KB", &cpu_set_size },
|
{ UNIT_CPU_MMU, UNIT_CPU_MMU, "MMU", "MMU", NULL, NULL,
|
||||||
{ MTAB_VDV, 36, NULL, "36KB", &cpu_set_size },
|
NULL, "Enable the Memory Management Unit for 8080 / Z80" },
|
||||||
{ MTAB_VDV, 40, NULL, "40KB", &cpu_set_size },
|
{ UNIT_CPU_MMU, 0, "NOMMU", "NOMMU", &cpu_set_nommu,
|
||||||
{ MTAB_VDV, 44, NULL, "44KB", &cpu_set_size },
|
NULL, NULL, "Disable the Memory Management Unit for 8080 / Z80" },
|
||||||
{ MTAB_VDV, 48, NULL, "48KB", &cpu_set_size },
|
{ MTAB_XTD | MTAB_VDV, 0, NULL, "MEMORY", &cpu_set_memory,
|
||||||
{ MTAB_VDV, 52, NULL, "52KB", &cpu_set_size },
|
NULL, NULL, "Sets the RAM size for 8080 / Z80 / 8086" },
|
||||||
{ MTAB_VDV, 56, NULL, "56KB", &cpu_set_size },
|
{ UNIT_CPU_SWITCHER, UNIT_CPU_SWITCHER, "SWITCHER", "SWITCHER", &cpu_set_switcher, &cpu_show_switcher,
|
||||||
{ MTAB_VDV, 60, NULL, "60KB", &cpu_set_size },
|
NULL, "Sets CPU switcher port for 8080 / Z80 / 8086" },
|
||||||
{ MTAB_VDV, 64, NULL, "64KB", &cpu_set_size },
|
{ UNIT_CPU_SWITCHER, 0, "NOSWITCHER", "NOSWITCHER", &cpu_reset_switcher, &cpu_show_switcher,
|
||||||
|
NULL, "Resets CPU switcher port for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_XTD | MTAB_VDV, 0, NULL, "AZ80", &cpu_set_ramtype,
|
||||||
|
NULL, NULL, "Sets the RAM type to AltairZ80 RAM for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_XTD | MTAB_VDV, 1, NULL, "HRAM", &cpu_set_ramtype,
|
||||||
|
NULL, NULL, "Sets the RAM type to NorthStar HRAM for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_XTD | MTAB_VDV, 2, NULL, "VRAM", &cpu_set_ramtype,
|
||||||
|
NULL, NULL, "Sets the RAM type to Vector RAM for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_XTD | MTAB_VDV, 3, NULL, "CRAM", &cpu_set_ramtype,
|
||||||
|
NULL, NULL, "Sets the RAM type to Cromemco RAM for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 4, NULL, "4KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 4KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 8, NULL, "8KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 8KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 12, NULL, "12KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 12KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 16, NULL, "16KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 16KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 20, NULL, "20KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 20KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 24, NULL, "24KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 24KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 28, NULL, "28KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 28KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 32, NULL, "32KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 32KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 36, NULL, "36KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 36KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 40, NULL, "40KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 40KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 44, NULL, "44KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 44KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 48, NULL, "48KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 48KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 52, NULL, "52KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 52KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 56, NULL, "56KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 56KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 60, NULL, "60KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 60KB for 8080 / Z80 / 8086" },
|
||||||
|
{ MTAB_VDV, 64, NULL, "64KB", &cpu_set_size,
|
||||||
|
NULL, NULL, "Sets the RAM size to 64KB for 8080 / Z80 / 8086" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB cpu_dt[] = {
|
static DEBTAB cpu_dt[] = {
|
||||||
{ "LOG_IN", IN_MSG },
|
{ "LOG_IN", IN_MSG, "Log IN operations" },
|
||||||
{ "LOG_OUT", OUT_MSG },
|
{ "LOG_OUT", OUT_MSG, "Log OUT operations" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -449,7 +621,7 @@ static struct idev dev_table[256] = {
|
||||||
static int32 ramtype = 0;
|
static int32 ramtype = 0;
|
||||||
#define MAX_RAM_TYPE 3
|
#define MAX_RAM_TYPE 3
|
||||||
|
|
||||||
int32 chiptype = CHIP_TYPE_8080;
|
ChipType chiptype = CHIP_TYPE_8080;
|
||||||
|
|
||||||
void out(const uint32 Port, const uint32 Value) {
|
void out(const uint32 Port, const uint32 Value) {
|
||||||
if ((cpu_dev.dctrl & OUT_MSG) && sim_deb) {
|
if ((cpu_dev.dctrl & OUT_MSG) && sim_deb) {
|
||||||
|
@ -1555,9 +1727,9 @@ static void altairz80_print_tables(void) {
|
||||||
#define LOG2PAGESIZE 8
|
#define LOG2PAGESIZE 8
|
||||||
#define PAGESIZE (1 << LOG2PAGESIZE)
|
#define PAGESIZE (1 << LOG2PAGESIZE)
|
||||||
|
|
||||||
static uint8 M[MAXMEMORY]; /* RAM which is present */
|
static uint8 M[MAXMEMORY]; /* RAM which is present (for 8080, Z80 and 8086 */
|
||||||
|
|
||||||
struct mdev { /* Structure to describe a 2^LOG2PAGESIZE byte page of address space */
|
typedef struct { /* Structure to describe a 2^LOG2PAGESIZE byte page of address space */
|
||||||
/* There are four cases
|
/* There are four cases
|
||||||
isRAM isEmpty routine code
|
isRAM isEmpty routine code
|
||||||
TRUE FALSE NULL W page is random access memory (RAM)
|
TRUE FALSE NULL W page is random access memory (RAM)
|
||||||
|
@ -1569,9 +1741,7 @@ struct mdev { /* Structure to describe a 2^LOG2PAGESIZE byte page of address spa
|
||||||
uint32 isRAM;
|
uint32 isRAM;
|
||||||
uint32 isEmpty;
|
uint32 isEmpty;
|
||||||
int32 (*routine)(const int32, const int32, const int32);
|
int32 (*routine)(const int32, const int32, const int32);
|
||||||
};
|
} MDEV;
|
||||||
|
|
||||||
typedef struct mdev MDEV;
|
|
||||||
|
|
||||||
static MDEV ROM_PAGE = {FALSE, FALSE, NULL}; /* this makes a page ROM */
|
static MDEV ROM_PAGE = {FALSE, FALSE, NULL}; /* this makes a page ROM */
|
||||||
static MDEV RAM_PAGE = {TRUE, FALSE, NULL}; /* this makes a page RAM */
|
static MDEV RAM_PAGE = {TRUE, FALSE, NULL}; /* this makes a page RAM */
|
||||||
|
@ -1852,13 +2022,15 @@ static int32 sim_brk_lookup (const t_addr loc, const int32 btyp) {
|
||||||
int32 switch_cpu_now = TRUE; /* hharte */
|
int32 switch_cpu_now = TRUE; /* hharte */
|
||||||
|
|
||||||
t_stat sim_instr (void) {
|
t_stat sim_instr (void) {
|
||||||
uint32 i;
|
|
||||||
t_stat result;
|
t_stat result;
|
||||||
if ((chiptype == CHIP_TYPE_8086) || (cpu_unit.flags & UNIT_CPU_MMU))
|
if (chiptype == CHIP_TYPE_M68K) {
|
||||||
|
result = sim_instr_m68k();
|
||||||
|
} else if ((chiptype == CHIP_TYPE_8086) || (cpu_unit.flags & UNIT_CPU_MMU))
|
||||||
do {
|
do {
|
||||||
result = (chiptype == CHIP_TYPE_8086) ? sim_instr_8086() : sim_instr_mmu();
|
result = (chiptype == CHIP_TYPE_8086) ? sim_instr_8086() : sim_instr_mmu();
|
||||||
} while (switch_cpu_now == FALSE);
|
} while (switch_cpu_now == FALSE);
|
||||||
else {
|
else {
|
||||||
|
uint32 i;
|
||||||
for (i = 0; i < MAXBANKSIZE; i++)
|
for (i = 0; i < MAXBANKSIZE; i++)
|
||||||
MOPT[i] = M[i];
|
MOPT[i] = M[i];
|
||||||
result = sim_instr_nommu();
|
result = sim_instr_nommu();
|
||||||
|
@ -6350,6 +6522,7 @@ static t_stat cpu_reset(DEVICE *dptr) {
|
||||||
IFF_S = 3;
|
IFF_S = 3;
|
||||||
setBankSelect(0);
|
setBankSelect(0);
|
||||||
cpu8086reset();
|
cpu8086reset();
|
||||||
|
m68k_cpu_reset();
|
||||||
sim_brk_types = (SWMASK('E') | SWMASK('I') | SWMASK('M'));
|
sim_brk_types = (SWMASK('E') | SWMASK('I') | SWMASK('M'));
|
||||||
sim_brk_dflt = SWMASK('E');
|
sim_brk_dflt = SWMASK('E');
|
||||||
for (i = 0; i < PCQ_SIZE; i++)
|
for (i = 0; i < PCQ_SIZE; i++)
|
||||||
|
@ -6365,18 +6538,9 @@ static t_stat cpu_reset(DEVICE *dptr) {
|
||||||
|
|
||||||
static t_bool cpu_is_pc_a_subroutine_call (t_addr **ret_addrs) {
|
static t_bool cpu_is_pc_a_subroutine_call (t_addr **ret_addrs) {
|
||||||
static t_addr returns[2] = {0, 0};
|
static t_addr returns[2] = {0, 0};
|
||||||
if (chiptype == CHIP_TYPE_8086) {
|
switch (chiptype) {
|
||||||
switch (GetBYTE(PCX_S)) {
|
case CHIP_TYPE_8080:
|
||||||
case 0x9a: /* i86op_call_far_IMM */
|
case CHIP_TYPE_Z80:
|
||||||
case 0xe8: /* Ci86op_call_near_IMM */
|
|
||||||
returns[0] = PCX_S + (1 - fprint_sym (stdnul, PCX_S, sim_eval,
|
|
||||||
&cpu_unit, SWMASK ('M')));
|
|
||||||
*ret_addrs = returns;
|
|
||||||
return TRUE;
|
|
||||||
default:
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
} else { // 8080 or Z80
|
|
||||||
switch (GetBYTE(PC_S)) {
|
switch (GetBYTE(PC_S)) {
|
||||||
case 0xc4: /* CALL NZ,nnnn */
|
case 0xc4: /* CALL NZ,nnnn */
|
||||||
case 0xcc: /* CALL Z,nnnn */
|
case 0xcc: /* CALL Z,nnnn */
|
||||||
|
@ -6393,10 +6557,42 @@ static t_bool cpu_is_pc_a_subroutine_call (t_addr **ret_addrs) {
|
||||||
default:
|
default:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_8086:
|
||||||
|
switch (GetBYTE(PCX_S)) {
|
||||||
|
case 0x9a: /* i86op_call_far_IMM */
|
||||||
|
case 0xe8: /* Ci86op_call_near_IMM */
|
||||||
|
returns[0] = PCX_S + (1 - fprint_sym (stdnul, PCX_S, sim_eval,
|
||||||
|
&cpu_unit, SWMASK ('M')));
|
||||||
|
*ret_addrs = returns;
|
||||||
|
return TRUE;
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_M68K: {
|
||||||
|
const uint32 localPC = m68k_registers[M68K_REG_PC];
|
||||||
|
const uint32 instr = m68k_cpu_read_word(localPC);
|
||||||
|
if (((instr & 0xff00) == 0x6100) || /* BSR */
|
||||||
|
((instr & 0xffc0) == 0x4e80)) { /* JSR */
|
||||||
|
returns[0] = localPC + (1 - fprint_sym (stdnul, localPC, sim_eval,
|
||||||
|
&cpu_unit, SWMASK ('M')));
|
||||||
|
*ret_addrs = returns;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return FALSE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM) {
|
t_stat install_bootrom(const int32 bootrom[], const int32 size, const int32 addr, const int32 makeROM) {
|
||||||
int32 i;
|
int32 i;
|
||||||
if (addr & (PAGESIZE - 1))
|
if (addr & (PAGESIZE - 1))
|
||||||
return SCPE_IERR;
|
return SCPE_IERR;
|
||||||
|
@ -6410,83 +6606,126 @@ t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM) {
|
||||||
|
|
||||||
/* memory examine */
|
/* memory examine */
|
||||||
static t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) {
|
static t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) {
|
||||||
int32 oldBankSelect;
|
switch (chiptype) {
|
||||||
if (chiptype == CHIP_TYPE_8086)
|
case CHIP_TYPE_8080:
|
||||||
*vptr = GetBYTEExtended(addr);
|
case CHIP_TYPE_Z80: {
|
||||||
else {
|
const int32 oldBankSelect = getBankSelect();
|
||||||
oldBankSelect = getBankSelect();
|
|
||||||
setBankSelect((addr >> MAXBANKSIZELOG2) & BANKMASK);
|
setBankSelect((addr >> MAXBANKSIZELOG2) & BANKMASK);
|
||||||
*vptr = GetBYTE(addr & ADDRMASK);
|
*vptr = GetBYTE(addr & ADDRMASK);
|
||||||
setBankSelect(oldBankSelect);
|
setBankSelect(oldBankSelect);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_8086:
|
||||||
|
*vptr = GetBYTEExtended(addr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_M68K:
|
||||||
|
*vptr = m68k_cpu_read_byte(addr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SCPE_AFAIL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* memory deposit */
|
/* memory deposit */
|
||||||
static t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) {
|
static t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) {
|
||||||
int32 oldBankSelect;
|
switch (chiptype) {
|
||||||
if (chiptype == CHIP_TYPE_8086)
|
case CHIP_TYPE_8080:
|
||||||
PutBYTEExtended(addr, val);
|
case CHIP_TYPE_Z80: {
|
||||||
else {
|
const int32 oldBankSelect = getBankSelect();
|
||||||
oldBankSelect = getBankSelect();
|
|
||||||
setBankSelect((addr >> MAXBANKSIZELOG2) & BANKMASK);
|
setBankSelect((addr >> MAXBANKSIZELOG2) & BANKMASK);
|
||||||
PutBYTE(addr & ADDRMASK, val);
|
PutBYTE(addr & ADDRMASK, val);
|
||||||
setBankSelect(oldBankSelect);
|
setBankSelect(oldBankSelect);
|
||||||
|
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_8086:
|
||||||
|
PutBYTEExtended(addr, val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_M68K:
|
||||||
|
m68k_cpu_write_byte(addr & M68K_MAX_RAM, val);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return SCPE_AFAIL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cpuflag {
|
typedef struct {
|
||||||
int32 mask; /* bit mask within CPU status register */
|
uint32 mask; /* bit mask within CPU status register */
|
||||||
char name; /* character to print if flag is set */
|
const char* flagName; /* string to print if flag is set */
|
||||||
};
|
} CPUFLAG;
|
||||||
typedef struct cpuflag CPUFLAG;
|
|
||||||
|
|
||||||
static CPUFLAG cpuflags8086[] = {
|
const static CPUFLAG cpuflags8080[] = {
|
||||||
{1 << 11, 'O'},
|
{1 << 7, "S"},
|
||||||
{1 << 10, 'D'},
|
{1 << 6, "Z"},
|
||||||
{1 << 9, 'I'},
|
{1 << 4, "A"},
|
||||||
{1 << 8, 'T'},
|
{1 << 3, "P"},
|
||||||
{1 << 7, 'S'},
|
{1 << 1, "N"},
|
||||||
{1 << 6, 'Z'},
|
{1 << 0, "C"},
|
||||||
{1 << 4, 'A'},
|
|
||||||
{1 << 2, 'P'},
|
|
||||||
{1 << 0, 'C'},
|
|
||||||
{0, 0} /* last mask must be 0 */
|
{0, 0} /* last mask must be 0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static CPUFLAG cpuflags8080[] = {
|
const static CPUFLAG cpuflagsZ80[] = {
|
||||||
{1 << 7, 'S'},
|
{1 << 7, "S"},
|
||||||
{1 << 6, 'Z'},
|
{1 << 6, "Z"},
|
||||||
{1 << 4, 'A'},
|
{1 << 4, "A"},
|
||||||
{1 << 3, 'P'},
|
{1 << 3, "V"},
|
||||||
{1 << 1, 'N'},
|
{1 << 1, "N"},
|
||||||
{1 << 0, 'C'},
|
{1 << 0, "C"},
|
||||||
{0, 0} /* last mask must be 0 */
|
{0, 0} /* last mask must be 0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
static CPUFLAG cpuflagsZ80[] = {
|
const static CPUFLAG cpuflags8086[] = {
|
||||||
{1 << 7, 'S'},
|
{1 << 11, "O"},
|
||||||
{1 << 6, 'Z'},
|
{1 << 10, "D"},
|
||||||
{1 << 4, 'A'},
|
{1 << 9, "I"},
|
||||||
{1 << 3, 'V'},
|
{1 << 8, "T"},
|
||||||
{1 << 1, 'N'},
|
{1 << 7, "S"},
|
||||||
{1 << 0, 'C'},
|
{1 << 6, "Z"},
|
||||||
|
{1 << 4, "A"},
|
||||||
|
{1 << 2, "P"},
|
||||||
|
{1 << 0, "C"},
|
||||||
{0, 0} /* last mask must be 0 */
|
{0, 0} /* last mask must be 0 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* needs to be set for each chiptype <= MAX_CHIP_TYPE */
|
const static CPUFLAG cpuflagsM68K[] = {
|
||||||
static char *chipTypeToString[] = { "8080", "Z80", "8086" };
|
{1 << 15, "T1"}, /* Trace Enable T1 */
|
||||||
static int32 *flagregister[] = { &AF_S, &AF_S, &FLAGS_S };
|
{1 << 14, "T0"}, /* Trace Enable T0 */
|
||||||
static CPUFLAG *cpuflags[] = { cpuflags8080, cpuflagsZ80, cpuflags8086 };
|
{1 << 13, "S"}, /* Supervisor / User State */
|
||||||
|
{1 << 12, "M"}, /* Master / Interrupt State */
|
||||||
|
{1 << 10, "I2"}, /* Interrupt Priority Mask I2 */
|
||||||
|
{1 << 9, "I1"}, /* Interrupt Priority Mask I1 */
|
||||||
|
{1 << 8, "I0"}, /* Interrupt Priority Mask I0 */
|
||||||
|
{1 << 4, "X"}, /* Extend */
|
||||||
|
{1 << 3, "N"}, /* Negative */
|
||||||
|
{1 << 2, "Z"}, /* Zero */
|
||||||
|
{1 << 1, "V"}, /* Overflow */
|
||||||
|
{1 << 0, "C"}, /* Carry */
|
||||||
|
{0, 0}, /* last mask must be 0 */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* needs to be set for each chiptype < NUM_CHIP_TYPE */
|
||||||
|
const static uint32 *flagregister[NUM_CHIP_TYPE] = { (uint32*)&AF_S, (uint32*)&AF_S,
|
||||||
|
(uint32*)&FLAGS_S, &m68k_registers[M68K_REG_SR]};
|
||||||
|
const static CPUFLAG *cpuflags[NUM_CHIP_TYPE] = { cpuflags8080, cpuflagsZ80,
|
||||||
|
cpuflags8086, cpuflagsM68K, };
|
||||||
|
|
||||||
/* needs to be set for each ramtype <= MAX_RAM_TYPE */
|
/* needs to be set for each ramtype <= MAX_RAM_TYPE */
|
||||||
static char *ramTypeToString[] = { "AZ80", "HRAM", "VRAM", "CRAM" };
|
static char *ramTypeToString[] = { "AZ80", "HRAM", "VRAM", "CRAM" };
|
||||||
|
|
||||||
static t_stat chip_show(FILE *st, UNIT *uptr, int32 val, void *desc) {
|
static t_stat chip_show(FILE *st, UNIT *uptr, int32 val, void *desc) {
|
||||||
fprintf(st, cpu_unit.flags & UNIT_CPU_OPSTOP ? "ITRAP, " : "NOITRAP, ");
|
fprintf(st, cpu_unit.flags & UNIT_CPU_OPSTOP ? "ITRAP, " : "NOITRAP, ");
|
||||||
if (chiptype <= MAX_CHIP_TYPE)
|
if (chiptype < NUM_CHIP_TYPE)
|
||||||
fprintf(st, "%s", chipTypeToString[chiptype]);
|
fprintf(st, "%s", cpu_mod[chiptype].mstring);
|
||||||
fprintf(st, ", ");
|
fprintf(st, ", ");
|
||||||
if (ramtype <= MAX_RAM_TYPE)
|
if (ramtype <= MAX_RAM_TYPE)
|
||||||
fprintf(st, "%s", ramTypeToString[ramtype]);
|
fprintf(st, "%s", ramTypeToString[ramtype]);
|
||||||
|
@ -6498,7 +6737,9 @@ static t_stat cpu_show(FILE *st, UNIT *uptr, int32 val, void *desc) {
|
||||||
MDEV m;
|
MDEV m;
|
||||||
maxBanks = ((cpu_unit.flags & UNIT_CPU_BANKED) ||
|
maxBanks = ((cpu_unit.flags & UNIT_CPU_BANKED) ||
|
||||||
(chiptype == CHIP_TYPE_8086)) ? MAXBANKS : 1;
|
(chiptype == CHIP_TYPE_8086)) ? MAXBANKS : 1;
|
||||||
fprintf(st, "VERBOSE,\n ");
|
fprintf(st, "VERBOSE,");
|
||||||
|
if (chiptype < CHIP_TYPE_M68K) { /* 8080, Z80, 8086 */
|
||||||
|
fprintf(st, "\n ");
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
fprintf(st, "0123456789ABCDEF");
|
fprintf(st, "0123456789ABCDEF");
|
||||||
fprintf(st, " [16k]");
|
fprintf(st, " [16k]");
|
||||||
|
@ -6526,16 +6767,17 @@ static t_stat cpu_show(FILE *st, UNIT *uptr, int32 val, void *desc) {
|
||||||
fprintf(st, "%02X", i);
|
fprintf(st, "%02X", i);
|
||||||
}
|
}
|
||||||
fprintf(st, "]");
|
fprintf(st, "]");
|
||||||
if (chiptype <= MAX_CHIP_TYPE) {
|
}
|
||||||
|
if (chiptype < NUM_CHIP_TYPE) {
|
||||||
first = TRUE;
|
first = TRUE;
|
||||||
/* show verbose CPU flags */
|
/* show verbose CPU flags */
|
||||||
for (i = 0; cpuflags[chiptype][i].mask; i++)
|
for (i = 0; cpuflags[chiptype][i].mask; i++)
|
||||||
if (*flagregister[chiptype] & cpuflags[chiptype][i].mask) {
|
if (*flagregister[chiptype] & cpuflags[chiptype][i].mask) {
|
||||||
if (first) {
|
if (first) {
|
||||||
first = FALSE;
|
first = FALSE;
|
||||||
fprintf(st, " ");
|
fprintf(st, "\nFlags");
|
||||||
}
|
}
|
||||||
fprintf(st, "%c", cpuflags[chiptype][i].name);
|
fprintf(st, " %s", cpuflags[chiptype][i].flagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -6551,6 +6793,7 @@ static void cpu_clear(void) {
|
||||||
mmu_table[i] = EMPTY_PAGE;
|
mmu_table[i] = EMPTY_PAGE;
|
||||||
if (cpu_unit.flags & UNIT_CPU_ALTAIRROM)
|
if (cpu_unit.flags & UNIT_CPU_ALTAIRROM)
|
||||||
install_ALTAIRbootROM();
|
install_ALTAIRbootROM();
|
||||||
|
m68k_clear_memory();
|
||||||
clockHasChanged = FALSE;
|
clockHasChanged = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6699,9 +6942,8 @@ static int32 bankseldev(const int32 port, const int32 io, const int32 data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cpu_set_chiptype_short(int32 value, uint32 need_cpu_clear) {
|
static void cpu_set_chiptype_short(const int32 value) {
|
||||||
extern REG *sim_PC;
|
if ((chiptype == value) || (chiptype >= NUM_CHIP_TYPE))
|
||||||
if ((chiptype == value) || (chiptype > MAX_CHIP_TYPE))
|
|
||||||
return; /* nothing to do */
|
return; /* nothing to do */
|
||||||
if (((chiptype == CHIP_TYPE_8080) && (value == CHIP_TYPE_Z80)) ||
|
if (((chiptype == CHIP_TYPE_8080) && (value == CHIP_TYPE_Z80)) ||
|
||||||
((chiptype == CHIP_TYPE_Z80) && (value == CHIP_TYPE_8080))) {
|
((chiptype == CHIP_TYPE_Z80) && (value == CHIP_TYPE_8080))) {
|
||||||
|
@ -6709,28 +6951,38 @@ static void cpu_set_chiptype_short(int32 value, uint32 need_cpu_clear) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
chiptype = value;
|
chiptype = value;
|
||||||
if (chiptype == CHIP_TYPE_8086) {
|
switch (chiptype) {
|
||||||
|
case CHIP_TYPE_8080:
|
||||||
|
case CHIP_TYPE_Z80:
|
||||||
|
MEMORYSIZE = previousCapacity;
|
||||||
|
cpu_dev.awidth = MAXBANKSIZELOG2;
|
||||||
|
sim_PC = &cpu_reg[CPU_INDEX_8080];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_8086:
|
||||||
if (MEMORYSIZE <= MAXBANKSIZE)
|
if (MEMORYSIZE <= MAXBANKSIZE)
|
||||||
previousCapacity = MEMORYSIZE;
|
previousCapacity = MEMORYSIZE;
|
||||||
MEMORYSIZE = MAXMEMORY;
|
MEMORYSIZE = MAXMEMORY;
|
||||||
cpu_unit.flags &= ~(UNIT_CPU_BANKED | UNIT_CPU_ALTAIRROM);
|
cpu_unit.flags &= ~(UNIT_CPU_BANKED | UNIT_CPU_ALTAIRROM);
|
||||||
cpu_unit.flags |= UNIT_CPU_MMU;
|
cpu_unit.flags |= UNIT_CPU_MMU;
|
||||||
cpu_dev.awidth = MAXBANKSIZELOG2 + MAXBANKSLOG2;
|
cpu_dev.awidth = MAXBANKSIZELOG2 + MAXBANKSLOG2;
|
||||||
if (need_cpu_clear)
|
sim_PC = &cpu_reg[CPU_INDEX_8086];
|
||||||
cpu_clear();
|
break;
|
||||||
sim_PC = &cpu_reg[7];
|
|
||||||
}
|
case CHIP_TYPE_M68K:
|
||||||
else if ((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) {
|
MEMORYSIZE = M68K_MAX_RAM + 1;
|
||||||
MEMORYSIZE = previousCapacity;
|
cpu_dev.awidth = M68K_MAX_RAM_LOG2;
|
||||||
cpu_dev.awidth = MAXBANKSIZELOG2;
|
sim_PC = &cpu_reg[CPU_INDEX_M68K];
|
||||||
if (need_cpu_clear)
|
break;
|
||||||
cpu_clear();
|
|
||||||
sim_PC = &cpu_reg[6];
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_stat cpu_set_chiptype(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
static t_stat cpu_set_chiptype(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||||
cpu_set_chiptype_short(value, TRUE);
|
cpu_set_chiptype_short(value);
|
||||||
|
cpu_clear();
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6758,7 +7010,7 @@ static int32 switchcpu_io(const int32 port, const int32 io, const int32 data) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_set_chiptype_short(new_chiptype, FALSE);
|
cpu_set_chiptype_short(new_chiptype);
|
||||||
return(0xFF); /* Return High-Z Data */
|
return(0xFF); /* Return High-Z Data */
|
||||||
} else {
|
} else {
|
||||||
printf("%s: Set EXT_ADDR=%02x\n", __FUNCTION__, data);
|
printf("%s: Set EXT_ADDR=%02x\n", __FUNCTION__, data);
|
||||||
|
@ -6854,7 +7106,13 @@ static t_stat cpu_set_ramtype(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||||
|
|
||||||
/* set memory to 'size' kilo byte */
|
/* set memory to 'size' kilo byte */
|
||||||
static t_stat set_size(uint32 size) {
|
static t_stat set_size(uint32 size) {
|
||||||
uint32 maxsize = (((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) &&
|
uint32 maxsize;
|
||||||
|
if (chiptype == CHIP_TYPE_M68K) { // ignore for M68K
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("Setting memory size to %ikB ignored for M68K.\n", size);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
maxsize = (((chiptype == CHIP_TYPE_8080) || (chiptype == CHIP_TYPE_Z80)) &&
|
||||||
((cpu_unit.flags & UNIT_CPU_BANKED) == 0)) ? MAXBANKSIZE : MAXMEMORY;
|
((cpu_unit.flags & UNIT_CPU_BANKED) == 0)) ? MAXBANKSIZE : MAXMEMORY;
|
||||||
size <<= KBLOG2;
|
size <<= KBLOG2;
|
||||||
if (cpu_unit.flags & UNIT_CPU_BANKED)
|
if (cpu_unit.flags & UNIT_CPU_BANKED)
|
||||||
|
@ -6910,6 +7168,41 @@ void (*sim_vm_init) (void) = &altairz80_init;
|
||||||
|
|
||||||
#define PLURAL(x) (x), (x) == 1 ? "" : "s"
|
#define PLURAL(x) (x), (x) == 1 ? "" : "s"
|
||||||
|
|
||||||
|
static t_stat sim_load_m68k(FILE *fileref, char *cptr, char *fnam, int flag) {
|
||||||
|
char gbuf[CBUFSIZE];
|
||||||
|
int32 i;
|
||||||
|
t_addr j, lo, hi;
|
||||||
|
uint32 addr, org, cnt = 0;
|
||||||
|
char* result;
|
||||||
|
if (flag ) {
|
||||||
|
result = get_range(NULL, cptr, &lo, &hi, 16, M68K_MAX_RAM, 0);
|
||||||
|
if (result == NULL)
|
||||||
|
return SCPE_ARG;
|
||||||
|
for (j = lo; j <= hi; j++) {
|
||||||
|
if (putc(m68k_cpu_read_byte(j), fileref) == EOF)
|
||||||
|
return SCPE_IOERR;
|
||||||
|
}
|
||||||
|
printf("%d byte%s dumped [%x - %x] to %s.\n", PLURAL(hi + 1 - lo), lo, hi, fnam);
|
||||||
|
} else {
|
||||||
|
if (*cptr == 0)
|
||||||
|
addr = m68k_registers[M68K_REG_PC];
|
||||||
|
else {
|
||||||
|
get_glyph(cptr, gbuf, 0);
|
||||||
|
addr = strtotv(cptr, &result, 16) & M68K_MAX_RAM;
|
||||||
|
if (cptr == result)
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
|
org = addr;
|
||||||
|
while ((addr <= M68K_MAX_RAM) && ((i = getc(fileref)) != EOF)) {
|
||||||
|
m68k_cpu_write_byte(addr++, i);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
printf("%d byte%s [%d page%s] loaded at %x.\n",
|
||||||
|
PLURAL(cnt), PLURAL((cnt + 0xff) >> 8), org);
|
||||||
|
}
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int flag) {
|
t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int flag) {
|
||||||
int32 i;
|
int32 i;
|
||||||
uint32 addr, cnt = 0, org, pagesModified = 0, makeROM = FALSE;
|
uint32 addr, cnt = 0, org, pagesModified = 0, makeROM = FALSE;
|
||||||
|
@ -6917,6 +7210,8 @@ t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int flag) {
|
||||||
char *result;
|
char *result;
|
||||||
MDEV m;
|
MDEV m;
|
||||||
char gbuf[CBUFSIZE];
|
char gbuf[CBUFSIZE];
|
||||||
|
if (chiptype == CHIP_TYPE_M68K)
|
||||||
|
return sim_load_m68k(fileref, cptr, fnam, flag);
|
||||||
if (flag) {
|
if (flag) {
|
||||||
result = get_range(NULL, cptr, &lo, &hi, 16, ADDRMASKEXTENDED, 0);
|
result = get_range(NULL, cptr, &lo, &hi, 16, ADDRMASKEXTENDED, 0);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
|
@ -6925,7 +7220,7 @@ t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int flag) {
|
||||||
if (putc(GetBYTEExtended(j), fileref) == EOF)
|
if (putc(GetBYTEExtended(j), fileref) == EOF)
|
||||||
return SCPE_IOERR;
|
return SCPE_IOERR;
|
||||||
}
|
}
|
||||||
printf("%d byte%s dumped [%x - %x].\n", PLURAL(hi + 1 - lo), lo, hi);
|
printf("%d byte%s dumped [%x - %x] to %s.\n", PLURAL(hi + 1 - lo), lo, hi, fnam);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (*cptr == 0)
|
if (*cptr == 0)
|
||||||
|
@ -6940,7 +7235,8 @@ t_stat sim_load(FILE *fileref, char *cptr, char *fnam, int flag) {
|
||||||
addr = strtotv(cptr, &result, 16) & ADDRMASKEXTENDED;
|
addr = strtotv(cptr, &result, 16) & ADDRMASKEXTENDED;
|
||||||
if (cptr == result)
|
if (cptr == result)
|
||||||
return SCPE_ARG;
|
return SCPE_ARG;
|
||||||
while (isspace(*result)) result++;
|
while (isspace(*result))
|
||||||
|
result++;
|
||||||
get_glyph(result, gbuf, 0);
|
get_glyph(result, gbuf, 0);
|
||||||
if (strcmp(gbuf, "ROM") == 0)
|
if (strcmp(gbuf, "ROM") == 0)
|
||||||
makeROM = TRUE;
|
makeROM = TRUE;
|
||||||
|
@ -6981,6 +7277,6 @@ void cpu_raise_interrupt(uint32 irq) {
|
||||||
cpu8086_intr(irq);
|
cpu8086_intr(irq);
|
||||||
} else if (cpu_unit.flags & UNIT_CPU_VERBOSE) {
|
} else if (cpu_unit.flags & UNIT_CPU_VERBOSE) {
|
||||||
printf("Interrupts not fully supported for chiptype: %s\n",
|
printf("Interrupts not fully supported for chiptype: %s\n",
|
||||||
(chiptype <= MAX_CHIP_TYPE) ? chipTypeToString[chiptype] : "????");
|
(chiptype < NUM_CHIP_TYPE) ? cpu_mod[chiptype].mstring : "????");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
Based on work by Charles E Owen (c) 1997
|
Based on work by Charles E Owen (c) 1997
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifndef ALTAIRZ80_DEFS_H_
|
||||||
|
#define ALTAIRZ80_DEFS_H_ 0
|
||||||
|
|
||||||
#include "sim_defs.h" /* simulator definitions */
|
#include "sim_defs.h" /* simulator definitions */
|
||||||
|
|
||||||
#define MAXBANKSIZE 65536 /* maximum memory size, a power of 2 */
|
#define MAXBANKSIZE 65536 /* maximum memory size, a power of 2 */
|
||||||
|
@ -48,10 +51,15 @@
|
||||||
#define UNIT_NO_OFFSET_1 0x37 /* LD A,<unitno> */
|
#define UNIT_NO_OFFSET_1 0x37 /* LD A,<unitno> */
|
||||||
#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | <unitno> */
|
#define UNIT_NO_OFFSET_2 0xb4 /* LD a,80h | <unitno> */
|
||||||
|
|
||||||
#define CHIP_TYPE_8080 0
|
#define CPU_INDEX_8080 4 /* index of default PC register */
|
||||||
#define CHIP_TYPE_Z80 1
|
|
||||||
#define CHIP_TYPE_8086 2
|
typedef enum {
|
||||||
#define MAX_CHIP_TYPE CHIP_TYPE_8086
|
CHIP_TYPE_8080 = 0,
|
||||||
|
CHIP_TYPE_Z80,
|
||||||
|
CHIP_TYPE_8086,
|
||||||
|
CHIP_TYPE_M68K, /* must come after 8080, Z80 and 8086 */
|
||||||
|
NUM_CHIP_TYPE, /* must be last */
|
||||||
|
} ChipType;
|
||||||
|
|
||||||
/* simulator stop codes */
|
/* simulator stop codes */
|
||||||
#define STOP_HALT 0 /* HALT */
|
#define STOP_HALT 0 /* HALT */
|
||||||
|
@ -81,7 +89,7 @@
|
||||||
#define UNIX_PLATFORM 0
|
#define UNIX_PLATFORM 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ADDRESS_FORMAT "[0x%05x]"
|
#define ADDRESS_FORMAT "[0x%08x]"
|
||||||
|
|
||||||
/* use NLP for new line printing while the simulation is running */
|
/* use NLP for new line printing while the simulation is running */
|
||||||
#if UNIX_PLATFORM
|
#if UNIX_PLATFORM
|
||||||
|
@ -100,3 +108,5 @@ typedef struct {
|
||||||
uint32 io_base; /* I/O Base Address */
|
uint32 io_base; /* I/O Base Address */
|
||||||
uint32 io_size; /* I/O Address Space requirement */
|
uint32 io_size; /* I/O Address Space requirement */
|
||||||
} PNP_INFO;
|
} PNP_INFO;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Binary file not shown.
|
@ -106,6 +106,11 @@
|
||||||
T = Sector True, is a 1 when the sector is positioned to read or
|
T = Sector True, is a 1 when the sector is positioned to read or
|
||||||
write.
|
write.
|
||||||
|
|
||||||
|
----------------------------------------------------------
|
||||||
|
|
||||||
|
5/22/2014 - Updated by Mike Douglas to support the Altair Mini-Disk.
|
||||||
|
This disk uses 35 (vs 70) tracks of 16 (vs 32) sectors
|
||||||
|
of 137 bytes each.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "altairz80_defs.h"
|
#include "altairz80_defs.h"
|
||||||
|
@ -131,21 +136,26 @@
|
||||||
#define NUM_OF_DSK_MASK (NUM_OF_DSK - 1)
|
#define NUM_OF_DSK_MASK (NUM_OF_DSK - 1)
|
||||||
#define BOOTROM_SIZE_DSK 256 /* size of boot rom */
|
#define BOOTROM_SIZE_DSK 256 /* size of boot rom */
|
||||||
|
|
||||||
|
#define MINI_DISK_SECT 16 /* mini disk sectors per track */
|
||||||
|
#define MINI_DISK_TRACKS 35 /* number of tracks on mini disk */
|
||||||
|
#define MINI_DISK_SIZE (MINI_DISK_TRACKS * MINI_DISK_SECT * DSK_SECTSIZE)
|
||||||
|
#define MINI_DISK_DELTA 4096 /* threshold for detecting mini disks */
|
||||||
|
|
||||||
int32 dsk10(const int32 port, const int32 io, const int32 data);
|
int32 dsk10(const int32 port, const int32 io, const int32 data);
|
||||||
int32 dsk11(const int32 port, const int32 io, const int32 data);
|
int32 dsk11(const int32 port, const int32 io, const int32 data);
|
||||||
int32 dsk12(const int32 port, const int32 io, const int32 data);
|
int32 dsk12(const int32 port, const int32 io, const int32 data);
|
||||||
static t_stat dsk_boot(int32 unitno, DEVICE *dptr);
|
static t_stat dsk_boot(int32 unitno, DEVICE *dptr);
|
||||||
static t_stat dsk_reset(DEVICE *dptr);
|
static t_stat dsk_reset(DEVICE *dptr);
|
||||||
|
static t_stat dsk_attach(UNIT *uptr, char *cptr);
|
||||||
|
|
||||||
extern REG *sim_PC;
|
|
||||||
extern UNIT cpu_unit;
|
extern UNIT cpu_unit;
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
|
|
||||||
extern t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM);
|
extern t_stat install_bootrom(const int32 bootrom[], const int32 size, const int32 addr, const int32 makeROM);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
||||||
void install_ALTAIRbootROM(void);
|
void install_ALTAIRbootROM(void);
|
||||||
|
extern int32 find_unit_index(UNIT *uptr);
|
||||||
|
|
||||||
/* global data on status */
|
/* global data on status */
|
||||||
|
|
||||||
|
@ -156,6 +166,10 @@ static int32 current_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
static int32 current_sector [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
static int32 current_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
static int32 current_flag [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
static int32 sectors_per_track [NUM_OF_DSK] = { DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT,
|
||||||
|
DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT,
|
||||||
|
DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT,
|
||||||
|
DSK_SECT, DSK_SECT, DSK_SECT, DSK_SECT };
|
||||||
static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
static uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
||||||
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
||||||
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS,
|
||||||
|
@ -171,6 +185,41 @@ static int32 warnDSK11 = 0;
|
||||||
static int32 warnDSK12 = 0;
|
static int32 warnDSK12 = 0;
|
||||||
static int8 dskbuf[DSK_SECTSIZE]; /* data Buffer */
|
static int8 dskbuf[DSK_SECTSIZE]; /* data Buffer */
|
||||||
|
|
||||||
|
const static int32 alt_bootrom_dsk[BOOTROM_SIZE_DSK] = { // boot ROM for mini disk support
|
||||||
|
0x21, 0x13, 0xff, 0x11, 0x00, 0x4c, 0x0e, 0xe3, /* ff00-ff07 */
|
||||||
|
0x7e, 0x12, 0x23, 0x13, 0x0d, 0xc2, 0x08, 0xff, /* ff08-ff0f */
|
||||||
|
0xc3, 0x00, 0x4c, 0xf3, 0xaf, 0xd3, 0x22, 0x2f, /* ff10-ff17 */
|
||||||
|
0xd3, 0x23, 0x3e, 0x2c, 0xd3, 0x22, 0x3e, 0x03, /* ff18-ff1f */
|
||||||
|
0xd3, 0x10, 0xdb, 0xff, 0xe6, 0x11, 0x0f, 0x0f, /* ff20-ff27 */
|
||||||
|
0xc6, 0x10, 0xd3, 0x10, 0x31, 0x71, 0x4d, 0xaf, /* ff28-ff2f */
|
||||||
|
0xd3, 0x08, 0xdb, 0x08, 0xe6, 0x08, 0xc2, 0x1c, /* ff30-ff37 */
|
||||||
|
0x4c, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x38, 0x4c, /* ff38-ff3f */
|
||||||
|
0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x2d, 0x4c, 0x3e, /* ff40-ff47 */
|
||||||
|
0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, 0xc2, /* ff48-ff4f */
|
||||||
|
0x2d, 0x4c, 0x11, 0x00, 0x00, 0x06, 0x00, 0x3e, /* ff50-ff57 */
|
||||||
|
0x10, 0xf5, 0xd5, 0xc5, 0xd5, 0x11, 0x86, 0x80, /* ff58-ff5f */
|
||||||
|
0x21, 0xe3, 0x4c, 0xdb, 0x09, 0x1f, 0xda, 0x50, /* ff60-ff67 */
|
||||||
|
0x4c, 0xe6, 0x1f, 0xb8, 0xc2, 0x50, 0x4c, 0xdb, /* ff68-ff6f */
|
||||||
|
0x08, 0xb7, 0xfa, 0x5c, 0x4c, 0xdb, 0x0a, 0x77, /* ff70-ff77 */
|
||||||
|
0x23, 0x1d, 0xc2, 0x5c, 0x4c, 0xe1, 0x11, 0xe6, /* ff78-ff7f */
|
||||||
|
0x4c, 0x01, 0x80, 0x00, 0x1a, 0x77, 0xbe, 0xc2, /* ff80-ff87 */
|
||||||
|
0xc3, 0x4c, 0x80, 0x47, 0x13, 0x23, 0x0d, 0xc2, /* ff88-ff8f */
|
||||||
|
0x71, 0x4c, 0x1a, 0xfe, 0xff, 0xc2, 0x88, 0x4c, /* ff90-ff97 */
|
||||||
|
0x13, 0x1a, 0xb8, 0xc1, 0xeb, 0xc2, 0xba, 0x4c, /* ff98-ff9f */
|
||||||
|
0xf1, 0xf1, 0x2a, 0xe4, 0x4c, 0xcd, 0xdd, 0x4c, /* ffa0-ffa7 */
|
||||||
|
0xd2, 0xb3, 0x4c, 0x04, 0x04, 0x78, 0xfe, 0x10, /* ffa8-ffaf */
|
||||||
|
0xda, 0x44, 0x4c, 0x06, 0x01, 0xca, 0x44, 0x4c, /* ffb0-ffb7 */
|
||||||
|
0xdb, 0x08, 0xe6, 0x02, 0xc2, 0xa5, 0x4c, 0x3e, /* ffb8-ffbf */
|
||||||
|
0x01, 0xd3, 0x09, 0xc3, 0x42, 0x4c, 0x3e, 0x80, /* ffc0-ffc7 */
|
||||||
|
0xd3, 0x08, 0xc3, 0x00, 0x00, 0xd1, 0xf1, 0x3d, /* ffc8-ffcf */
|
||||||
|
0xc2, 0x46, 0x4c, 0x3e, 0x43, 0x01, 0x3e, 0x4d, /* ffd0-ffd7 */
|
||||||
|
0xfb, 0x32, 0x00, 0x00, 0x22, 0x01, 0x00, 0x47, /* ffd8-ffdf */
|
||||||
|
0x3e, 0x80, 0xd3, 0x08, 0x78, 0xd3, 0x01, 0xd3, /* ffe0-ffe7 */
|
||||||
|
0x11, 0xd3, 0x05, 0xd3, 0x23, 0xc3, 0xd2, 0x4c, /* ffe8-ffef */
|
||||||
|
0x7a, 0xbc, 0xc0, 0x7b, 0xbd, 0xc9, 0x00, 0x00, /* fff0-fff7 */
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff8-ffff */
|
||||||
|
};
|
||||||
|
|
||||||
/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */
|
/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */
|
||||||
int32 bootrom_dsk[BOOTROM_SIZE_DSK] = {
|
int32 bootrom_dsk[BOOTROM_SIZE_DSK] = {
|
||||||
0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */
|
0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */
|
||||||
|
@ -229,40 +278,62 @@ static UNIT dsk_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG dsk_reg[] = {
|
static REG dsk_reg[] = {
|
||||||
{ DRDATA (DISK, current_disk, 4) },
|
{ DRDATAD (DISK, current_disk, 4,
|
||||||
{ BRDATA (CURTRACK, current_track, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
"Selected disk register"), },
|
||||||
{ BRDATA (CURSECTOR, current_sector, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
{ BRDATAD (CURTRACK, current_track, 10, 32, NUM_OF_DSK,
|
||||||
{ BRDATA (CURBYTE, current_byte, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
"Selected track register array"), REG_CIRC + REG_RO },
|
||||||
{ BRDATA (CURFLAG, current_flag, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
{ BRDATAD (CURSECTOR, current_sector, 10, 32, NUM_OF_DSK,
|
||||||
{ BRDATA (TRACKS, tracks, 10, 8, NUM_OF_DSK), REG_CIRC },
|
"Selected sector register array"), REG_CIRC + REG_RO },
|
||||||
{ DRDATA (IN9COUNT, in9_count, 4), REG_RO },
|
{ BRDATAD (CURBYTE, current_byte, 10, 32, NUM_OF_DSK,
|
||||||
{ DRDATA (IN9MESSAGE, in9_message, 4), REG_RO },
|
"Current byte register arrayr"), REG_CIRC + REG_RO },
|
||||||
{ DRDATA (DIRTY, dirty, 4), REG_RO },
|
{ BRDATAD (CURFLAG, current_flag, 10, 32, NUM_OF_DSK,
|
||||||
{ DRDATA (DSKWL, warnLevelDSK, 32) },
|
"Current flag register array"), REG_CIRC + REG_RO },
|
||||||
{ BRDATA (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
{ BRDATAD (TRACKS, tracks, 10, 8, NUM_OF_DSK,
|
||||||
{ BRDATA (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
"Number of tracks register array"), REG_CIRC },
|
||||||
{ DRDATA (WARNDSK10, warnDSK10, 4), REG_RO },
|
{ BRDATAD (SECTPERTRACK,sectors_per_track, 10, 8, NUM_OF_DSK,
|
||||||
{ DRDATA (WARNDSK11, warnDSK11, 4), REG_RO },
|
"Number of sectors per track register array"), REG_CIRC },
|
||||||
{ DRDATA (WARNDSK12, warnDSK12, 4), REG_RO },
|
{ DRDATAD (IN9COUNT, in9_count, 4,
|
||||||
{ BRDATA (DISKBUFFER, dskbuf, 10, 8, DSK_SECTSIZE), REG_CIRC + REG_RO },
|
"Count of IN(9) register"), REG_RO },
|
||||||
|
{ DRDATAD (IN9MESSAGE, in9_message, 4,
|
||||||
|
"BOOL for IN(9) message register"), REG_RO },
|
||||||
|
{ DRDATAD (DIRTY, dirty, 4,
|
||||||
|
"BOOL for write needed register"), REG_RO },
|
||||||
|
{ DRDATAD (DSKWL, warnLevelDSK, 32,
|
||||||
|
"Warn level register") },
|
||||||
|
{ BRDATAD (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK,
|
||||||
|
"Count of write to locked register array"), REG_CIRC + REG_RO },
|
||||||
|
{ BRDATAD (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK,
|
||||||
|
"Count for selection of unattached disk register array"), REG_CIRC + REG_RO },
|
||||||
|
{ DRDATAD (WARNDSK10, warnDSK10, 4,
|
||||||
|
"Count of IN(8) on unattached disk register"), REG_RO },
|
||||||
|
{ DRDATAD (WARNDSK11, warnDSK11, 4,
|
||||||
|
"Count of IN/OUT(9) on unattached disk register"), REG_RO },
|
||||||
|
{ DRDATAD (WARNDSK12, warnDSK12, 4,
|
||||||
|
"Count of IN/OUT(10) on unattached disk register"), REG_RO },
|
||||||
|
{ BRDATAD (DISKBUFFER, dskbuf, 10, 8, DSK_SECTSIZE,
|
||||||
|
"Disk data buffer array"), REG_CIRC + REG_RO },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DSK_NAME "Altair Floppy Disk DSK"
|
||||||
|
|
||||||
static MTAB dsk_mod[] = {
|
static MTAB dsk_mod[] = {
|
||||||
{ UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL },
|
{ UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL, NULL, NULL,
|
||||||
{ UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL },
|
"Enables " DSK_NAME "n for writing" },
|
||||||
|
{ UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL, NULL, NULL,
|
||||||
|
"Locks " DSK_NAME "n for writing" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB dsk_dt[] = {
|
static DEBTAB dsk_dt[] = {
|
||||||
{ "IN", IN_MSG },
|
{ "IN", IN_MSG, "IN operations" },
|
||||||
{ "OUT", OUT_MSG },
|
{ "OUT", OUT_MSG, "OUT operations" },
|
||||||
{ "READ", READ_MSG },
|
{ "READ", READ_MSG, "Read operations" },
|
||||||
{ "WRITE", WRITE_MSG },
|
{ "WRITE", WRITE_MSG, "Write operations" },
|
||||||
{ "SECTOR_STUCK", SECTOR_STUCK_MSG },
|
{ "SECTOR_STUCK", SECTOR_STUCK_MSG, "Sector stuck" },
|
||||||
{ "TRACK_STUCK", TRACK_STUCK_MSG },
|
{ "TRACK_STUCK", TRACK_STUCK_MSG, "Track stuck" },
|
||||||
{ "VERBOSE", VERBOSE_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -270,9 +341,9 @@ DEVICE dsk_dev = {
|
||||||
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
"DSK", dsk_unit, dsk_reg, dsk_mod,
|
||||||
NUM_OF_DSK, 10, 31, 1, 8, 8,
|
NUM_OF_DSK, 10, 31, 1, 8, 8,
|
||||||
NULL, NULL, &dsk_reset,
|
NULL, NULL, &dsk_reset,
|
||||||
&dsk_boot, NULL, NULL,
|
&dsk_boot, &dsk_attach, NULL,
|
||||||
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
|
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
|
||||||
dsk_dt, NULL, "Altair Floppy Disk DSK"
|
dsk_dt, NULL, DSK_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
static char* selectInOut(const int32 io) {
|
static char* selectInOut(const int32 io) {
|
||||||
|
@ -291,7 +362,6 @@ static t_stat dsk_reset(DEVICE *dptr) {
|
||||||
current_sector[i] = 0;
|
current_sector[i] = 0;
|
||||||
current_byte[i] = 0;
|
current_byte[i] = 0;
|
||||||
current_flag[i] = 0;
|
current_flag[i] = 0;
|
||||||
tracks[i] = MAX_TRACKS;
|
|
||||||
}
|
}
|
||||||
warnDSK10 = 0;
|
warnDSK10 = 0;
|
||||||
warnDSK11 = 0;
|
warnDSK11 = 0;
|
||||||
|
@ -304,6 +374,28 @@ static t_stat dsk_reset(DEVICE *dptr) {
|
||||||
sim_map_resource(0x0A, 1, RESOURCE_TYPE_IO, &dsk12, dptr->flags & DEV_DIS);
|
sim_map_resource(0x0A, 1, RESOURCE_TYPE_IO, &dsk12, dptr->flags & DEV_DIS);
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
/* dsk_attach - determine type of drive attached based on disk image size */
|
||||||
|
|
||||||
|
static t_stat dsk_attach(UNIT *uptr, char *cptr) {
|
||||||
|
int32 thisUnitIndex;
|
||||||
|
int32 imageSize;
|
||||||
|
const t_stat r = attach_unit(uptr, cptr); /* attach unit */
|
||||||
|
if (r != SCPE_OK) /* error? */
|
||||||
|
return r;
|
||||||
|
|
||||||
|
assert(uptr != NULL);
|
||||||
|
thisUnitIndex = find_unit_index(uptr);
|
||||||
|
assert((0 <= thisUnitIndex) && (thisUnitIndex < NUM_OF_DSK));
|
||||||
|
|
||||||
|
/* If the file size is close to the mini-disk image size, set the number of
|
||||||
|
tracks to 16, otherwise, 32 sectors per track. */
|
||||||
|
|
||||||
|
imageSize = sim_fsize(uptr -> fileref);
|
||||||
|
sectors_per_track[thisUnitIndex] = (((MINI_DISK_SIZE - MINI_DISK_DELTA < imageSize) &&
|
||||||
|
(imageSize < MINI_DISK_SIZE + MINI_DISK_DELTA)) ?
|
||||||
|
MINI_DISK_SECT : DSK_SECT);
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void install_ALTAIRbootROM(void) {
|
void install_ALTAIRbootROM(void) {
|
||||||
const t_bool result = (install_bootrom(bootrom_dsk, BOOTROM_SIZE_DSK, ALTAIR_ROM_LOW, TRUE) ==
|
const t_bool result = (install_bootrom(bootrom_dsk, BOOTROM_SIZE_DSK, ALTAIR_ROM_LOW, TRUE) ==
|
||||||
|
@ -316,8 +408,14 @@ void install_ALTAIRbootROM(void) {
|
||||||
*/
|
*/
|
||||||
static t_stat dsk_boot(int32 unitno, DEVICE *dptr) {
|
static t_stat dsk_boot(int32 unitno, DEVICE *dptr) {
|
||||||
if (cpu_unit.flags & (UNIT_CPU_ALTAIRROM | UNIT_CPU_BANKED)) {
|
if (cpu_unit.flags & (UNIT_CPU_ALTAIRROM | UNIT_CPU_BANKED)) {
|
||||||
|
if (sectors_per_track[unitno] == MINI_DISK_SECT) {
|
||||||
|
const t_bool result = (install_bootrom(alt_bootrom_dsk, BOOTROM_SIZE_DSK,
|
||||||
|
ALTAIR_ROM_LOW, TRUE) == SCPE_OK);
|
||||||
|
assert(result);
|
||||||
|
} else {
|
||||||
/* check whether we are really modifying an LD A,<> instruction */
|
/* check whether we are really modifying an LD A,<> instruction */
|
||||||
if ((bootrom_dsk[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) && (bootrom_dsk[UNIT_NO_OFFSET_2 - 1] == LDA_INSTRUCTION)) {
|
if ((bootrom_dsk[UNIT_NO_OFFSET_1 - 1] == LDA_INSTRUCTION) &&
|
||||||
|
(bootrom_dsk[UNIT_NO_OFFSET_2 - 1] == LDA_INSTRUCTION)) {
|
||||||
bootrom_dsk[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A,<unitno> */
|
bootrom_dsk[UNIT_NO_OFFSET_1] = unitno & 0xff; /* LD A,<unitno> */
|
||||||
bootrom_dsk[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
|
bootrom_dsk[UNIT_NO_OFFSET_2] = 0x80 | (unitno & 0xff); /* LD a,80h | <unitno> */
|
||||||
}
|
}
|
||||||
|
@ -327,12 +425,13 @@ static t_stat dsk_boot(int32 unitno, DEVICE *dptr) {
|
||||||
}
|
}
|
||||||
install_ALTAIRbootROM(); /* install modified ROM */
|
install_ALTAIRbootROM(); /* install modified ROM */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
*((int32 *) sim_PC->loc) = ALTAIR_ROM_LOW;
|
*((int32 *) sim_PC->loc) = ALTAIR_ROM_LOW;
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32 dskseek(const UNIT *xptr) {
|
static int32 dskseek(const UNIT *xptr) {
|
||||||
return sim_fseek(xptr -> fileref, DSK_TRACSIZE * current_track[current_disk] +
|
return sim_fseek(xptr -> fileref, DSK_SECTSIZE * sectors_per_track[current_disk] * current_track[current_disk] +
|
||||||
DSK_SECTSIZE * current_sector[current_disk], SEEK_SET);
|
DSK_SECTSIZE * current_sector[current_disk], SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -465,7 +564,7 @@ int32 dsk11(const int32 port, const int32 io, const int32 data) {
|
||||||
writebuf();
|
writebuf();
|
||||||
if (current_flag[current_disk] & 0x04) { /* head loaded? */
|
if (current_flag[current_disk] & 0x04) { /* head loaded? */
|
||||||
current_sector[current_disk]++;
|
current_sector[current_disk]++;
|
||||||
if (current_sector[current_disk] >= DSK_SECT)
|
if (current_sector[current_disk] >= sectors_per_track[current_disk])
|
||||||
current_sector[current_disk] = 0;
|
current_sector[current_disk] = 0;
|
||||||
current_byte[current_disk] = 0xff;
|
current_byte[current_disk] = 0xff;
|
||||||
return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */
|
return (((current_sector[current_disk] << 1) & 0x3e) /* return 'sector true' bit = 0 (true) */
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
Contains code from Howard M. Harte for defining and changing disk geometry.
|
Contains code from Howard M. Harte for defining and changing disk geometry.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "altairz80_defs.h"
|
#include "m68k.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "sim_imd.h"
|
#include "sim_imd.h"
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ static void verifyDiskInfo(const DISK_INFO *info, const char unitChar);
|
||||||
#define HDSK_NUMBER_OF_TRACKS u3 /* number of tracks */
|
#define HDSK_NUMBER_OF_TRACKS u3 /* number of tracks */
|
||||||
#define HDSK_FORMAT_TYPE u6 /* Disk Format Type */
|
#define HDSK_FORMAT_TYPE u6 /* Disk Format Type */
|
||||||
#define HDSK_CAPACITY (2048*32*128) /* Default Altair HDSK Capacity */
|
#define HDSK_CAPACITY (2048*32*128) /* Default Altair HDSK Capacity */
|
||||||
#define HDSK_NUMBER 8 /* number of hard disks */
|
#define HDSK_NUMBER 16 /* number of hard disks */
|
||||||
#define CPM_OK 0 /* indicates to CP/M everything ok */
|
#define CPM_OK 0 /* indicates to CP/M everything ok */
|
||||||
#define CPM_ERROR 1 /* indicates to CP/M an error condition */
|
#define CPM_ERROR 1 /* indicates to CP/M an error condition */
|
||||||
#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */
|
#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */
|
||||||
|
@ -70,13 +70,13 @@ static void verifyDiskInfo(const DISK_INFO *info, const char unitChar);
|
||||||
#define BOOTROM_SIZE_HDSK 256
|
#define BOOTROM_SIZE_HDSK 256
|
||||||
|
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern REG *sim_PC;
|
|
||||||
extern UNIT cpu_unit;
|
extern UNIT cpu_unit;
|
||||||
|
extern ChipType chiptype;
|
||||||
|
|
||||||
extern void install_ALTAIRbootROM(void);
|
extern void install_ALTAIRbootROM(void);
|
||||||
extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
|
extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
|
||||||
extern uint8 GetBYTEWrapper(const uint32 Addr);
|
extern uint8 GetBYTEWrapper(const uint32 Addr);
|
||||||
extern t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM);
|
extern t_stat install_bootrom(const int32 bootrom[], const int32 size, const int32 addr, const int32 makeROM);
|
||||||
extern int32 bootrom_dsk[];
|
extern int32 bootrom_dsk[];
|
||||||
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
|
@ -94,11 +94,40 @@ static int32 selectedDisk;
|
||||||
static int32 selectedSector;
|
static int32 selectedSector;
|
||||||
static int32 selectedTrack;
|
static int32 selectedTrack;
|
||||||
static int32 selectedDMA;
|
static int32 selectedDMA;
|
||||||
|
static int32 hdskStatus;
|
||||||
|
|
||||||
|
void hdsk_prepareRead(void) {
|
||||||
|
hdskLastCommand = HDSK_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hdsk_prepareWrite(void) {
|
||||||
|
hdskLastCommand = HDSK_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hdsk_setSelectedDisk(const int32 disk) {
|
||||||
|
selectedDisk = disk;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hdsk_setSelectedSector(const int32 sector) {
|
||||||
|
selectedSector = sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hdsk_setSelectedTrack(const int32 track) {
|
||||||
|
selectedTrack = track;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hdsk_setSelectedDMA(const int32 dma) {
|
||||||
|
selectedDMA = dma;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 hdsk_getStatus(void) {
|
||||||
|
return hdskStatus;
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[DPB_NAME_LENGTH + 1]; /* name of CP/M disk parameter block */
|
char name[DPB_NAME_LENGTH + 1]; /* name of CP/M disk parameter block */
|
||||||
t_addr capac; /* capacity */
|
t_addr capac; /* capacity */
|
||||||
uint16 spt; /* sectors per track */
|
uint32 spt; /* sectors per track */
|
||||||
uint8 bsh; /* data allocation block shift factor */
|
uint8 bsh; /* data allocation block shift factor */
|
||||||
uint8 blm; /* data allocation block mask */
|
uint8 blm; /* data allocation block mask */
|
||||||
uint8 exm; /* extent mask */
|
uint8 exm; /* extent mask */
|
||||||
|
@ -163,6 +192,9 @@ static DPB dpb[] = {
|
||||||
{ "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF,
|
{ "HDSK", HDSK_CAPACITY, 32, 0x05, 0x1F, 0x01, 0x07f9, 0x03FF,
|
||||||
0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00, 0, 0, NULL }, /* AZ80 HDSK */
|
0xFF, 0x00, 0x0000, 0x0006, 0x00, 0x00, 0, 0, NULL }, /* AZ80 HDSK */
|
||||||
|
|
||||||
|
{ "CPM68K", (1 << 24), (1<<17),0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, NULL }, /* CP/M-68K HDSK */
|
||||||
|
|
||||||
{ "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E,
|
{ "EZ80FL", 131072, 32, 0x03, 0x07, 0x00, 127, 0x003E,
|
||||||
0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03, 0, 0, NULL }, /* 128K FLASH */
|
0xC0, 0x00, 0x0000, 0x0000, 0x02, 0x03, 0, 0, NULL }, /* 128K FLASH */
|
||||||
|
|
||||||
|
@ -204,31 +236,31 @@ static DPB dpb[] = {
|
||||||
|
|
||||||
{ "SSDD8", 512512, SPT52, 0x04, 0x0F, 0x01, 242, 0x007F,
|
{ "SSDD8", 512512, SPT52, 0x04, 0x0F, 0x01, 242, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" SS DD */
|
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" SS DD */
|
||||||
|
|
||||||
{ "SSDD8S", 512512, SPT52, 0x04, 0x0F, 0x01, 242, 0x007F,
|
{ "SSDD8S", 512512, SPT52, 0x04, 0x0F, 0x01, 242, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, standard8 }, /* Standard 8" SS DD with skew */
|
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, standard8 }, /* Standard 8" SS DD with skew */
|
||||||
|
|
||||||
{ "DSDD8", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F,
|
{ "DSDD8", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" DS DD */
|
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" DS DD */
|
||||||
|
|
||||||
{ "DSDD8S", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F,
|
{ "DSDD8S", 1025024, SPT52, 0x04, 0x0F, 0x00, 493, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" DS DD with skew */
|
0xC0, 0x00, 0x0000, 0x0002, 0x01, 0x01, 0, 0, NULL }, /* Standard 8" DS DD with skew */
|
||||||
|
|
||||||
{"512SSDD8",591360, 60, 0x04, 0x0F, 0x00, 280, 0x007F,
|
{"512SSDD8",591360, 60, 0x04, 0x0F, 0x00, 280, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Standard 8" SS DD with 512 byte sectors */
|
0xC0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Standard 8" SS DD with 512 byte sectors */
|
||||||
|
|
||||||
{"512DSDD8",1182720, 60, 0x04, 0x0F, 0x00, 569, 0x007F,
|
{"512DSDD8",1182720, 60, 0x04, 0x0F, 0x00, 569, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Standard 8" DS DD with 512 byte sectors */
|
0xC0, 0x00, 0x0000, 0x0002, 0x02, 0x03, 0, 0, NULL }, /* Standard 8" DS DD with 512 byte sectors */
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* CP/M 3 BIOS currently does not support physical sector size 1024 */
|
/* CP/M 3 BIOS currently does not support physical sector size 1024 */
|
||||||
{"1024SSDD8",630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F,
|
{"1024SSDD8",630784, 64, 0x04, 0x0F, 0x00, 299, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x03, 0x07, 0, 0, NULL }, /* Standard 8" SS DD with 1024 byte sectors */
|
0xC0, 0x00, 0x0000, 0x0002, 0x03, 0x07, 0, 0, NULL }, /* Standard 8" SS DD with 1024 byte sectors */
|
||||||
|
|
||||||
{"1024DSDD8",1261568, 64, 0x04, 0x0F, 0x00, 607, 0x007F,
|
{"1024DSDD8",1261568, 64, 0x04, 0x0F, 0x00, 607, 0x007F,
|
||||||
0xC0, 0x00, 0x0000, 0x0002, 0x03, 0x07, 0, 0, NULL }, /* Standard 8" DS DD with 1024 byte sectors */
|
0xC0, 0x00, 0x0000, 0x0002, 0x03, 0x07, 0, 0, NULL }, /* Standard 8" DS DD with 1024 byte sectors */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{ "APPLE-DO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F,
|
{ "APPLE-DO",143360, SPT32, 0x03, 0x07, 0x00, 127, 0x003F,
|
||||||
0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, apple_ii_DOS }, /* Apple II DOS 3.3 */
|
0xC0, 0x00, 0x0000, 0x0003, 0x01, 0x01, 0, 0, apple_ii_DOS }, /* Apple II DOS 3.3 */
|
||||||
|
|
||||||
|
@ -272,40 +304,60 @@ static UNIT hdsk_unit[] = {
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
};
|
};
|
||||||
static DISK_INFO* hdsk_imd[HDSK_NUMBER];
|
static DISK_INFO* hdsk_imd[HDSK_NUMBER];
|
||||||
|
|
||||||
static REG hdsk_reg[] = {
|
static REG hdsk_reg[] = {
|
||||||
{ DRDATA (HDCMD, hdskLastCommand, 32), REG_RO },
|
{ DRDATAD (HDCMD, hdskLastCommand, 32, "Last command"),
|
||||||
{ DRDATA (HDPOS, hdskCommandPosition, 32), REG_RO },
|
REG_RO },
|
||||||
{ DRDATA (HDDSK, selectedDisk, 32), REG_RO },
|
{ DRDATAD (HDPOS, hdskCommandPosition, 32, "Commmand position"),
|
||||||
{ DRDATA (HDSEC, selectedSector, 32), REG_RO },
|
REG_RO },
|
||||||
{ DRDATA (HDTRK, selectedTrack, 32), REG_RO },
|
{ DRDATAD (HDDSK, selectedDisk, 32, "Selected disk"),
|
||||||
{ DRDATA (HDDMA, selectedDMA, 32), REG_RO },
|
REG_RO },
|
||||||
|
{ DRDATAD (HDSEC, selectedSector, 32, "Selected sector"),
|
||||||
|
REG_RO },
|
||||||
|
{ DRDATAD (HDTRK, selectedTrack, 32, "Selected track"),
|
||||||
|
REG_RO },
|
||||||
|
{ DRDATAD (HDDMA, selectedDMA, 32, "Selected Direct Memory Access address"), REG_RO },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HDSK_NAME "Hard Disk HDSK"
|
||||||
|
|
||||||
static MTAB hdsk_mod[] = {
|
static MTAB hdsk_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", &set_format, &show_format, NULL },
|
&set_iobase, &show_iobase, NULL, "Defines the I/O port assignment for device " HDSK_NAME },
|
||||||
{ UNIT_HDSK_WLK, 0, "WRTENB", "WRTENB", NULL },
|
{ MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT",
|
||||||
{ UNIT_HDSK_WLK, UNIT_HDSK_WLK, "WRTLCK", "WRTLCK", NULL },
|
&set_format, &show_format, NULL, "Defines the format for unit " HDSK_NAME "n" },
|
||||||
{ MTAB_XTD|MTAB_VUN, 0, "GEOM", "GEOM", &set_geom, &show_geom, NULL },
|
{ UNIT_HDSK_WLK, 0, "WRTENB", "WRTENB",
|
||||||
|
NULL, NULL, NULL, "Enables " HDSK_NAME "n for writing" },
|
||||||
|
{ UNIT_HDSK_WLK, UNIT_HDSK_WLK, "WRTLCK", "WRTLCK",
|
||||||
|
NULL, NULL, NULL, "Locks " HDSK_NAME "n for writing" },
|
||||||
|
{ MTAB_XTD|MTAB_VUN, 0, "GEOM", "GEOM",
|
||||||
|
&set_geom, &show_geom, NULL, "Sets the disk geometry for unit " HDSK_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB hdsk_dt[] = {
|
static DEBTAB hdsk_dt[] = {
|
||||||
{ "READ", READ_MSG },
|
{ "READ", READ_MSG, "Disk read activity" },
|
||||||
{ "WRITE", WRITE_MSG },
|
{ "WRITE", WRITE_MSG, "Disk write activity" },
|
||||||
{ "VERBOSE", VERBOSE_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "All disk activity" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE hdsk_dev = {
|
DEVICE hdsk_dev = {
|
||||||
"HDSK", hdsk_unit, hdsk_reg, hdsk_mod,
|
"HDSK", hdsk_unit, hdsk_reg, hdsk_mod,
|
||||||
8, 10, 31, 1, 8, 8,
|
HDSK_NUMBER, 10, 31, 1, 8, 8,
|
||||||
NULL, NULL, &hdsk_reset,
|
NULL, NULL, &hdsk_reset,
|
||||||
&hdsk_boot, &hdsk_attach, &hdsk_detach,
|
&hdsk_boot, &hdsk_attach, &hdsk_detach,
|
||||||
&hdsk_info_data, (DEV_DISABLE | DEV_DEBUG), 0,
|
&hdsk_info_data, (DEV_DISABLE | DEV_DEBUG), 0,
|
||||||
|
@ -338,9 +390,9 @@ static uint32 is_imd(const UNIT *uptr) {
|
||||||
|
|
||||||
static void assignFormat(UNIT *uptr) {
|
static void assignFormat(UNIT *uptr) {
|
||||||
uint32 i;
|
uint32 i;
|
||||||
uptr -> HDSK_FORMAT_TYPE = -1; /* default to unknown format type */
|
uptr -> HDSK_FORMAT_TYPE = -1; /* default to unknown format type */
|
||||||
for (i = 0; dpb[i].capac != 0; i++) { /* find disk parameter block */
|
for (i = 0; dpb[i].capac != 0; i++) { /* find disk parameter block */
|
||||||
if (dpb[i].capac == uptr -> capac) { /* found if correct capacity */
|
if (dpb[i].capac == uptr -> capac) { /* found if correct capacity */
|
||||||
uptr -> HDSK_FORMAT_TYPE = i;
|
uptr -> HDSK_FORMAT_TYPE = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -376,15 +428,15 @@ static void verifyDiskInfo(const DISK_INFO *info, const char unitChar) {
|
||||||
static t_stat hdsk_attach(UNIT *uptr, char *cptr) {
|
static t_stat hdsk_attach(UNIT *uptr, char *cptr) {
|
||||||
int32 thisUnitIndex;
|
int32 thisUnitIndex;
|
||||||
char unitChar;
|
char unitChar;
|
||||||
const t_stat r = attach_unit(uptr, cptr); /* attach unit */
|
const t_stat r = attach_unit(uptr, cptr); /* attach unit */
|
||||||
if (r != SCPE_OK) /* error? */
|
if (r != SCPE_OK) /* error? */
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
assert(uptr != NULL);
|
assert(uptr != NULL);
|
||||||
thisUnitIndex = find_unit_index(uptr);
|
thisUnitIndex = find_unit_index(uptr);
|
||||||
unitChar = '0' + thisUnitIndex;
|
unitChar = '0' + thisUnitIndex;
|
||||||
assert((0 <= thisUnitIndex) && (thisUnitIndex < HDSK_NUMBER));
|
assert((0 <= thisUnitIndex) && (thisUnitIndex < HDSK_NUMBER));
|
||||||
|
|
||||||
if (is_imd(uptr)) {
|
if (is_imd(uptr)) {
|
||||||
if ((sim_fsize(uptr -> fileref) == 0) &&
|
if ((sim_fsize(uptr -> fileref) == 0) &&
|
||||||
(diskCreate(uptr -> fileref, "$Id: SIMH hdsk.c $") != SCPE_OK)) {
|
(diskCreate(uptr -> fileref, "$Id: SIMH hdsk.c $") != SCPE_OK)) {
|
||||||
|
@ -412,28 +464,28 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) {
|
||||||
}
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Step 1: Determine capacity of this disk */
|
/* Step 1: Determine capacity of this disk */
|
||||||
uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good indication */
|
uptr -> capac = sim_fsize(uptr -> fileref); /* the file length is a good indication */
|
||||||
if (uptr -> capac == 0) { /* file does not exist or has length 0 */
|
if (uptr -> capac == 0) { /* file does not exist or has length 0 */
|
||||||
uptr -> capac = (uptr -> HDSK_NUMBER_OF_TRACKS *
|
uptr -> capac = (uptr -> HDSK_NUMBER_OF_TRACKS *
|
||||||
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE);
|
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE);
|
||||||
if (uptr -> capac == 0)
|
if (uptr -> capac == 0)
|
||||||
uptr -> capac = HDSK_CAPACITY;
|
uptr -> capac = HDSK_CAPACITY;
|
||||||
} /* post condition: uptr -> capac > 0 */
|
} /* post condition: uptr -> capac > 0 */
|
||||||
assert(uptr -> capac);
|
assert(uptr -> capac);
|
||||||
|
|
||||||
/* Step 2: Determine format based on disk capacity */
|
/* Step 2: Determine format based on disk capacity */
|
||||||
assignFormat(uptr);
|
assignFormat(uptr);
|
||||||
|
|
||||||
/* Step 3: Set number of sectors per track and sector size */
|
/* Step 3: Set number of sectors per track and sector size */
|
||||||
if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found */
|
if (uptr -> HDSK_FORMAT_TYPE == -1) { /* Case 1: no disk parameter block found */
|
||||||
uptr -> HDSK_FORMAT_TYPE = 0;
|
uptr -> HDSK_FORMAT_TYPE = 0;
|
||||||
printf("HDSK%c: WARNING: Unsupported disk capacity, assuming HDSK type with capacity %iKB.\n",
|
printf("HDSK%c: WARNING: Unsupported disk capacity, assuming HDSK type with capacity %iKB.\n",
|
||||||
unitChar, uptr -> capac / 1000);
|
unitChar, uptr -> capac / 1000);
|
||||||
uptr -> flags |= UNIT_HDSK_WLK;
|
uptr -> flags |= UNIT_HDSK_WLK;
|
||||||
printf("HDSK%c: WARNING: Forcing WRTLCK.\n", unitChar);
|
printf("HDSK%c: WARNING: Forcing WRTLCK.\n", unitChar);
|
||||||
/* check whether capacity corresponds to setting of tracks, sectors per track and sector size */
|
/* check whether capacity corresponds to setting of tracks, sectors per track and sector size */
|
||||||
if (uptr -> capac != (uint32)(uptr -> HDSK_NUMBER_OF_TRACKS *
|
if (uptr -> capac != (uint32)(uptr -> HDSK_NUMBER_OF_TRACKS *
|
||||||
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE)) {
|
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE)) {
|
||||||
printf("HDSK%c: WARNING: Fixing geometry.\n", unitChar);
|
printf("HDSK%c: WARNING: Fixing geometry.\n", unitChar);
|
||||||
|
@ -443,20 +495,20 @@ static t_stat hdsk_attach(UNIT *uptr, char *cptr) {
|
||||||
uptr -> HDSK_SECTOR_SIZE = 128;
|
uptr -> HDSK_SECTOR_SIZE = 128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { /* Case 2: disk parameter block found */
|
else { /* Case 2: disk parameter block found */
|
||||||
uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh;
|
uptr -> HDSK_SECTORS_PER_TRACK = dpb[uptr -> HDSK_FORMAT_TYPE].spt >> dpb[uptr -> HDSK_FORMAT_TYPE].psh;
|
||||||
uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh);
|
uptr -> HDSK_SECTOR_SIZE = (128 << dpb[uptr -> HDSK_FORMAT_TYPE].psh);
|
||||||
}
|
}
|
||||||
assert((uptr -> HDSK_SECTORS_PER_TRACK) && (uptr -> HDSK_SECTOR_SIZE) && (uptr -> HDSK_FORMAT_TYPE >= 0));
|
assert((uptr -> HDSK_SECTORS_PER_TRACK) && (uptr -> HDSK_SECTOR_SIZE) && (uptr -> HDSK_FORMAT_TYPE >= 0));
|
||||||
|
|
||||||
/* Step 4: Number of tracks is smallest number to accomodate capacity */
|
/* Step 4: Number of tracks is smallest number to accomodate capacity */
|
||||||
uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK *
|
uptr -> HDSK_NUMBER_OF_TRACKS = (uptr -> capac + uptr -> HDSK_SECTORS_PER_TRACK *
|
||||||
uptr -> HDSK_SECTOR_SIZE - 1) / (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE);
|
uptr -> HDSK_SECTOR_SIZE - 1) / (uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE);
|
||||||
assert( ( (t_addr) ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK *
|
assert( ( (t_addr) ((uptr -> HDSK_NUMBER_OF_TRACKS - 1) * uptr -> HDSK_SECTORS_PER_TRACK *
|
||||||
uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) &&
|
uptr -> HDSK_SECTOR_SIZE) < uptr -> capac) &&
|
||||||
(uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS *
|
(uptr -> capac <= (t_addr) (uptr -> HDSK_NUMBER_OF_TRACKS *
|
||||||
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) );
|
uptr -> HDSK_SECTORS_PER_TRACK * uptr -> HDSK_SECTOR_SIZE) ) );
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,7 +648,9 @@ static int32 bootrom_hdsk[BOOTROM_SIZE_HDSK] = {
|
||||||
|
|
||||||
static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) {
|
static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) {
|
||||||
t_bool installSuccessful;
|
t_bool installSuccessful;
|
||||||
if (MEMORYSIZE < 24*KB) {
|
if (chiptype == CHIP_TYPE_M68K)
|
||||||
|
return m68k_hdsk_boot(unitno, dptr, VERBOSE_MSG, HDSK_NUMBER);
|
||||||
|
if (MEMORYSIZE < 24 * KB) {
|
||||||
printf("Need at least 24KB RAM to boot from hard disk.\n");
|
printf("Need at least 24KB RAM to boot from hard disk.\n");
|
||||||
return SCPE_ARG;
|
return SCPE_ARG;
|
||||||
}
|
}
|
||||||
|
@ -668,7 +722,7 @@ static t_stat hdsk_boot(int32 unitno, DEVICE *dptr) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* check the parameters and return TRUE iff parameters are correct or have been repaired */
|
/* check the parameters and return TRUE iff parameters are correct or have been repaired */
|
||||||
static int32 checkParameters(void) {
|
t_bool hdsk_checkParameters(void) {
|
||||||
UNIT *uptr;
|
UNIT *uptr;
|
||||||
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
|
if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) {
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
||||||
|
@ -684,7 +738,7 @@ static int32 checkParameters(void) {
|
||||||
}
|
}
|
||||||
if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) {
|
if ((selectedSector < 0) || (selectedSector >= uptr -> HDSK_SECTORS_PER_TRACK)) {
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
||||||
" Constraint violation 0 <= Sector=%02d < %d, will use sector 0 instead.\n",
|
" Constraint violation 0 <= Sector=%06d < %d, will use sector 0 instead.\n",
|
||||||
selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK);
|
selectedDisk, PCX, selectedSector, uptr -> HDSK_SECTORS_PER_TRACK);
|
||||||
selectedSector = 0;
|
selectedSector = 0;
|
||||||
}
|
}
|
||||||
|
@ -694,23 +748,36 @@ static int32 checkParameters(void) {
|
||||||
selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS);
|
selectedDisk, PCX, selectedTrack, uptr -> HDSK_NUMBER_OF_TRACKS);
|
||||||
selectedTrack = 0;
|
selectedTrack = 0;
|
||||||
}
|
}
|
||||||
selectedDMA &= ADDRMASK;
|
if (chiptype == CHIP_TYPE_M68K) {
|
||||||
|
if (selectedDMA + uptr -> HDSK_SECTOR_SIZE > M68K_MAX_RAM) {
|
||||||
|
sim_debug(VERBOSE_MSG, &hdsk_dev,
|
||||||
|
"HDSK%d: " ADDRESS_FORMAT
|
||||||
|
" Error: DMA (0x%08x) + sector size (0x%02x) out of bounds. "
|
||||||
|
"Must be at most 0x%08x.\n",
|
||||||
|
selectedDisk, PCX, selectedDMA, uptr -> HDSK_SECTOR_SIZE, M68K_MAX_RAM);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
selectedDMA &= ADDRMASK;
|
||||||
if (hdskLastCommand == HDSK_READ) {
|
if (hdskLastCommand == HDSK_READ) {
|
||||||
sim_debug(READ_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT
|
sim_debug(READ_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT
|
||||||
" Read Track=%04d Sector=%02d Len=%04d DMA=%04x\n",
|
" Read Track=%04d Sector=%06d Len=%04d DMA=%08x\n",
|
||||||
selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA);
|
selectedDisk, PCX, selectedTrack, selectedSector,
|
||||||
|
uptr -> HDSK_SECTOR_SIZE, selectedDMA);
|
||||||
}
|
}
|
||||||
if (hdskLastCommand == HDSK_WRITE) {
|
if (hdskLastCommand == HDSK_WRITE) {
|
||||||
sim_debug(WRITE_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT
|
sim_debug(WRITE_MSG, &hdsk_dev, "HDSK%d " ADDRESS_FORMAT
|
||||||
" Write Track=%04d Sector=%02d Len=%04d DMA=%04x\n",
|
" Write Track=%04d Sector=%06d Len=%04d DMA=%08x\n",
|
||||||
selectedDisk, PCX, selectedTrack, selectedSector, uptr -> HDSK_SECTOR_SIZE, selectedDMA);
|
selectedDisk, PCX, selectedTrack, selectedSector,
|
||||||
|
uptr -> HDSK_SECTOR_SIZE, selectedDMA);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pre-condition: checkParameters has been executed to repair any faulty parameters */
|
/* pre-condition: hdsk_checkParameters has been executed to repair any faulty parameters */
|
||||||
static int32 doSeek(void) {
|
static int32 doSeek(void) {
|
||||||
UNIT *uptr = &hdsk_dev.units[selectedDisk];
|
UNIT *uptr = &hdsk_dev.units[selectedDisk];
|
||||||
|
assert(uptr != NULL);
|
||||||
int32 hostSector = (dpb[uptr -> HDSK_FORMAT_TYPE].skew == NULL) ?
|
int32 hostSector = (dpb[uptr -> HDSK_FORMAT_TYPE].skew == NULL) ?
|
||||||
selectedSector : dpb[uptr -> HDSK_FORMAT_TYPE].skew[selectedSector];
|
selectedSector : dpb[uptr -> HDSK_FORMAT_TYPE].skew[selectedSector];
|
||||||
int32 sectorSize = (dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize == 0) ?
|
int32 sectorSize = (dpb[uptr -> HDSK_FORMAT_TYPE].physicalSectorSize == 0) ?
|
||||||
|
@ -719,7 +786,7 @@ static int32 doSeek(void) {
|
||||||
sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) +
|
sectorSize * (uptr -> HDSK_SECTORS_PER_TRACK * selectedTrack + hostSector) +
|
||||||
dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) {
|
dpb[uptr -> HDSK_FORMAT_TYPE].offset, SEEK_SET)) {
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
||||||
" Could not access Sector=%02d[=%02d] Track=%04d.\n",
|
" Could not access Sector=%06d[=%06d] Track=%04d.\n",
|
||||||
selectedDisk, PCX, selectedSector, hostSector, selectedTrack);
|
selectedDisk, PCX, selectedSector, hostSector, selectedTrack);
|
||||||
return CPM_ERROR;
|
return CPM_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -728,8 +795,8 @@ static int32 doSeek(void) {
|
||||||
|
|
||||||
static uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */
|
static uint8 hdskbuf[HDSK_MAX_SECTOR_SIZE] = { 0 }; /* data buffer */
|
||||||
|
|
||||||
/* pre-condition: checkParameters has been executed to repair any faulty parameters */
|
/* pre-condition: hdsk_checkParameters has been executed to repair any faulty parameters */
|
||||||
static int32 doRead(void) {
|
int32 hdsk_read(void) {
|
||||||
int32 i;
|
int32 i;
|
||||||
t_stat result;
|
t_stat result;
|
||||||
DISK_INFO *thisDisk;
|
DISK_INFO *thisDisk;
|
||||||
|
@ -761,30 +828,39 @@ static int32 doRead(void) {
|
||||||
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
||||||
hdskbuf[i] = CPM_EMPTY;
|
hdskbuf[i] = CPM_EMPTY;
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d (IMD): " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d (IMD): " ADDRESS_FORMAT
|
||||||
" . Could not read Sector=%02d Track=%04d.\n",
|
" . Could not read Sector=%06d Track=%04d.\n",
|
||||||
selectedDisk, PCX, selectedSector, selectedTrack);
|
selectedDisk, PCX, selectedSector, selectedTrack);
|
||||||
return CPM_ERROR;
|
hdskStatus = CPM_ERROR;
|
||||||
|
return hdskStatus;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (doSeek())
|
if (doSeek()) {
|
||||||
return CPM_ERROR;
|
hdskStatus = CPM_ERROR;
|
||||||
|
return hdskStatus;
|
||||||
|
}
|
||||||
|
|
||||||
if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
|
if (sim_fread(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref) != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
|
||||||
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
||||||
hdskbuf[i] = CPM_EMPTY;
|
hdskbuf[i] = CPM_EMPTY;
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
||||||
" Could not read Sector=%02d Track=%04d.\n",
|
" Could not read Sector=%06d Track=%04d.\n",
|
||||||
selectedDisk, PCX, selectedSector, selectedTrack);
|
selectedDisk, PCX, selectedSector, selectedTrack);
|
||||||
return CPM_OK; /* allows the creation of empty hard disks */
|
hdskStatus = CPM_OK;
|
||||||
|
return hdskStatus; /* allows the creation of empty hard disks */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
if (chiptype == CHIP_TYPE_M68K)
|
||||||
PutBYTEWrapper(selectedDMA + i, hdskbuf[i]);
|
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
||||||
return CPM_OK;
|
m68k_cpu_write_byte_raw(selectedDMA + i, hdskbuf[i]);
|
||||||
|
else
|
||||||
|
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
||||||
|
PutBYTEWrapper(selectedDMA + i, hdskbuf[i]);
|
||||||
|
hdskStatus = CPM_OK;
|
||||||
|
return hdskStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pre-condition: checkParameters has been executed to repair any faulty parameters */
|
/* pre-condition: hdsk_checkParameters has been executed to repair any faulty parameters */
|
||||||
static int32 doWrite(void) {
|
int32 hdsk_write(void) {
|
||||||
int32 i;
|
int32 i;
|
||||||
t_stat result;
|
t_stat result;
|
||||||
DISK_INFO *thisDisk;
|
DISK_INFO *thisDisk;
|
||||||
|
@ -797,9 +873,13 @@ static int32 doWrite(void) {
|
||||||
size_t rtn;
|
size_t rtn;
|
||||||
UNIT *uptr = &hdsk_dev.units[selectedDisk];
|
UNIT *uptr = &hdsk_dev.units[selectedDisk];
|
||||||
if (((uptr -> flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */
|
if (((uptr -> flags) & UNIT_HDSK_WLK) == 0) { /* write enabled */
|
||||||
if (is_imd(uptr)) {
|
if (chiptype == CHIP_TYPE_M68K)
|
||||||
|
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
||||||
|
hdskbuf[i] = m68k_cpu_read_byte_raw(selectedDMA + i);
|
||||||
|
else
|
||||||
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
||||||
hdskbuf[i] = GetBYTEWrapper(selectedDMA + i);
|
hdskbuf[i] = GetBYTEWrapper(selectedDMA + i);
|
||||||
|
if (is_imd(uptr)) {
|
||||||
thisDisk = hdsk_imd[selectedDisk];
|
thisDisk = hdsk_imd[selectedDisk];
|
||||||
hostSector = ((dpb[uptr -> HDSK_FORMAT_TYPE].skew == NULL) ?
|
hostSector = ((dpb[uptr -> HDSK_FORMAT_TYPE].skew == NULL) ?
|
||||||
selectedSector : dpb[uptr -> HDSK_FORMAT_TYPE].skew[selectedSector]) + thisDisk -> track[1][0].start_sector;
|
selectedSector : dpb[uptr -> HDSK_FORMAT_TYPE].skew[selectedSector]) + thisDisk -> track[1][0].start_sector;
|
||||||
|
@ -818,31 +898,53 @@ static int32 doWrite(void) {
|
||||||
sectorSize, &flags, &writelen);
|
sectorSize, &flags, &writelen);
|
||||||
if (result != SCPE_OK) {
|
if (result != SCPE_OK) {
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d (IMD): " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d (IMD): " ADDRESS_FORMAT
|
||||||
" . Could not write Sector=%02d Track=%04d.\n",
|
" . Could not write Sector=%06d Track=%04d.\n",
|
||||||
selectedDisk, PCX, selectedSector, selectedTrack);
|
selectedDisk, PCX, selectedSector, selectedTrack);
|
||||||
return CPM_ERROR;
|
hdskStatus = CPM_ERROR;
|
||||||
|
return hdskStatus;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (doSeek())
|
if (doSeek()) {
|
||||||
return CPM_ERROR;
|
hdskStatus = CPM_ERROR;
|
||||||
for (i = 0; i < uptr -> HDSK_SECTOR_SIZE; i++)
|
return hdskStatus;
|
||||||
hdskbuf[i] = GetBYTEWrapper(selectedDMA + i);
|
}
|
||||||
rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref);
|
rtn = sim_fwrite(hdskbuf, 1, uptr -> HDSK_SECTOR_SIZE, uptr -> fileref);
|
||||||
if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
|
if (rtn != (size_t)(uptr -> HDSK_SECTOR_SIZE)) {
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
||||||
" Could not write Sector=%02d Track=%04d Result=%zd.\n",
|
" Could not write Sector=%06d Track=%04d Result=%zd.\n",
|
||||||
selectedDisk, PCX, selectedSector, selectedTrack, rtn);
|
selectedDisk, PCX, selectedSector, selectedTrack, rtn);
|
||||||
return CPM_ERROR;
|
hdskStatus = CPM_ERROR;
|
||||||
|
return hdskStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &hdsk_dev, "HDSK%d: " ADDRESS_FORMAT
|
||||||
" Could not write to locked disk Sector=%02d Track=%04d.\n",
|
" Could not write to locked disk Sector=%06d Track=%04d.\n",
|
||||||
selectedDisk, PCX, selectedSector, selectedTrack);
|
selectedDisk, PCX, selectedSector, selectedTrack);
|
||||||
return CPM_ERROR;
|
hdskStatus = CPM_ERROR;
|
||||||
|
return hdskStatus;
|
||||||
}
|
}
|
||||||
return CPM_OK;
|
hdskStatus = CPM_OK;
|
||||||
|
return hdskStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* flush all attached drives. Returns CPM_OK if everything fine, otherwise CPM_ERROR */
|
||||||
|
int32 hdsk_flush(void) {
|
||||||
|
uint32 drive;
|
||||||
|
hdskStatus = CPM_OK;
|
||||||
|
for (drive = 0; drive < HDSK_NUMBER; drive++) {
|
||||||
|
const UNIT *uptr = hdsk_dev.units + drive;
|
||||||
|
if ((uptr -> flags) & UNIT_ATT) {
|
||||||
|
const int result = fflush(uptr -> fileref);
|
||||||
|
sim_debug(VERBOSE_MSG, &hdsk_dev,
|
||||||
|
"HDSK%i: 0x%08x Drive flushed [%i = %s].\n", drive, PCX,
|
||||||
|
result, result == 0 ? "Ok" : "Error");
|
||||||
|
if (result)
|
||||||
|
hdskStatus = CPM_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hdskStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PARAMETER_BLOCK_SIZE 19
|
#define PARAMETER_BLOCK_SIZE 19
|
||||||
|
@ -850,7 +952,7 @@ static uint8 parameterBlock[PARAMETER_BLOCK_SIZE];
|
||||||
|
|
||||||
static int32 hdsk_in(const int32 port) {
|
static int32 hdsk_in(const int32 port) {
|
||||||
if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) {
|
if ((hdskCommandPosition == 6) && ((hdskLastCommand == HDSK_READ) || (hdskLastCommand == HDSK_WRITE))) {
|
||||||
int32 result = checkParameters() ? ((hdskLastCommand == HDSK_READ) ? doRead() : doWrite()) : CPM_ERROR;
|
int32 result = hdsk_checkParameters() ? ((hdskLastCommand == HDSK_READ) ? hdsk_read() : hdsk_write()) : CPM_ERROR;
|
||||||
hdskLastCommand = HDSK_NONE;
|
hdskLastCommand = HDSK_NONE;
|
||||||
hdskCommandPosition = 0;
|
hdskCommandPosition = 0;
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -32,12 +32,12 @@
|
||||||
two platters as two separate drives. Each platter has 406 cylinders
|
two platters as two separate drives. Each platter has 406 cylinders
|
||||||
with 24 sectors per track and 256 bytes per sector.
|
with 24 sectors per track and 256 bytes per sector.
|
||||||
|
|
||||||
The disk image file starts with head 0, track 0, sector 0 (0,0,0) through
|
The disk image file starts with head 0, track 0, sector 0 (0,0,0) through
|
||||||
(0,0,23), followed by head 1, track 0, sector 0 (1,0,0) through (1,0,23).
|
(0,0,23), followed by head 1, track 0, sector 0 (1,0,0) through (1,0,23).
|
||||||
The pattern then repeats starting with (0,1,0).
|
The pattern then repeats starting with (0,1,0).
|
||||||
|
|
||||||
The external hard disk is accessed through eight ports of a 4-PIO card
|
The external hard disk is accessed through eight ports of a 4-PIO card
|
||||||
at I/O addresses A0h-A7h.
|
at I/O addresses A0h-A7h.
|
||||||
|
|
||||||
Written by Mike Douglas March, 2014
|
Written by Mike Douglas March, 2014
|
||||||
Disk images provided by Martin Eberhard
|
Disk images provided by Martin Eberhard
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
#define HDSK_NUM_TRACKS 406 /* tracks per surface */
|
#define HDSK_NUM_TRACKS 406 /* tracks per surface */
|
||||||
#define HDSK_TRACK_SIZE (HDSK_SECTOR_SIZE * HDSK_SECTORS_PER_TRACK)
|
#define HDSK_TRACK_SIZE (HDSK_SECTOR_SIZE * HDSK_SECTORS_PER_TRACK)
|
||||||
#define HDSK_CYLINDER_SIZE (HDSK_TRACK_SIZE * 2)
|
#define HDSK_CYLINDER_SIZE (HDSK_TRACK_SIZE * 2)
|
||||||
#define HDSK_CAPACITY (HDSK_CYLINDER_SIZE * HDSK_NUM_TRACKS)
|
#define HDSK_CAPACITY (HDSK_CYLINDER_SIZE * HDSK_NUM_TRACKS)
|
||||||
#define HDSK_NUMBER 8 /* number of hard disks */
|
#define HDSK_NUMBER 8 /* number of hard disks */
|
||||||
#define IO_IN 0 /* I/O operation is input */
|
#define IO_IN 0 /* I/O operation is input */
|
||||||
#define IO_OUT 1 /* I/O operation is output */
|
#define IO_OUT 1 /* I/O operation is output */
|
||||||
|
@ -71,7 +71,7 @@ extern uint32 PCX;
|
||||||
#define BOOTROM_SIZE_MHDSK 256
|
#define BOOTROM_SIZE_MHDSK 256
|
||||||
#define MHDSK_BOOT_ADDRESS 0xfc00
|
#define MHDSK_BOOT_ADDRESS 0xfc00
|
||||||
static t_stat mhdsk_boot(int32 unitno, DEVICE *dptr);
|
static t_stat mhdsk_boot(int32 unitno, DEVICE *dptr);
|
||||||
extern t_stat install_bootrom(int32 bootrom[], int32 size, int32 addr, int32 makeROM);
|
extern t_stat install_bootrom(const int32 bootrom[], const int32 size, const int32 addr, const int32 makeROM);
|
||||||
|
|
||||||
// Disk controller commands are in upper nibble of command high byte.
|
// Disk controller commands are in upper nibble of command high byte.
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ static char* commandMessage[CMD_MAX] = {
|
||||||
#define BUFFER_MASK 0x03 // mask - no shift needed
|
#define BUFFER_MASK 0x03 // mask - no shift needed
|
||||||
|
|
||||||
#define TRACK_SHIFTH 8 // shift left 8 places into MSbyte
|
#define TRACK_SHIFTH 8 // shift left 8 places into MSbyte
|
||||||
#define TRACK_MASKH 0x01 // msb of track number
|
#define TRACK_MASKH 0x01 // msb of track number
|
||||||
#define TRACK_MASKL 0xff // entire lsb of track number
|
#define TRACK_MASKL 0xff // entire lsb of track number
|
||||||
|
|
||||||
#define HEAD_SHIFT 5 // shift right 5 places
|
#define HEAD_SHIFT 5 // shift right 5 places
|
||||||
|
@ -178,18 +178,22 @@ static UNIT dsk_unit[] = {
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) },
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }};
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }};
|
||||||
|
|
||||||
|
#define MHDSK_NAME "MITS Hard Disk MHDSK"
|
||||||
|
|
||||||
static MTAB dsk_mod[] = {
|
static MTAB dsk_mod[] = {
|
||||||
{ UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL },
|
{ UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL, NULL, NULL,
|
||||||
{ UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL },
|
"Enables " MHDSK_NAME "n for writing" },
|
||||||
|
{ UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL, NULL, NULL,
|
||||||
|
"Locks " MHDSK_NAME "n for writing" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB mhdsk_dt[] = {
|
static DEBTAB mhdsk_dt[] = {
|
||||||
{ "READ", READ_MSG },
|
{ "READ", READ_MSG, "Read messages" },
|
||||||
{ "WRITE", WRITE_MSG },
|
{ "WRITE", WRITE_MSG, "Write messages" },
|
||||||
{ "VERBOSE", VERBOSE_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE mhdsk_dev = {
|
DEVICE mhdsk_dev = {
|
||||||
|
@ -198,41 +202,41 @@ DEVICE mhdsk_dev = {
|
||||||
NULL, NULL, &dsk_reset,
|
NULL, NULL, &dsk_reset,
|
||||||
&mhdsk_boot, NULL, NULL,
|
&mhdsk_boot, NULL, NULL,
|
||||||
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
|
NULL, (DEV_DISABLE | DEV_DEBUG), 0,
|
||||||
mhdsk_dt, NULL, "MITS Hard Disk MHDSK"
|
mhdsk_dt, NULL, MHDSK_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
static int32 bootrom_mhdsk[BOOTROM_SIZE_MHDSK] = {
|
static int32 bootrom_mhdsk[BOOTROM_SIZE_MHDSK] = {
|
||||||
0xf3, 0x31, 0x00, 0xf8, 0x21, 0x1b, 0x41, 0x2b, /* fc00-fc07 */
|
0xf3, 0x31, 0x00, 0xf8, 0x21, 0x1b, 0x41, 0x2b, /* fc00-fc07 */
|
||||||
0x7c, 0xb5, 0xc2, 0x07, 0xfc, 0xe5, 0xd3, 0xa0, /* fc08-fc0f */
|
0x7c, 0xb5, 0xc2, 0x07, 0xfc, 0xe5, 0xd3, 0xa0, /* fc08-fc0f */
|
||||||
0xd3, 0xa2, 0xd3, 0xa4, 0xd3, 0xa6, 0xd3, 0xa1, /* fc10-fc17 */
|
0xd3, 0xa2, 0xd3, 0xa4, 0xd3, 0xa6, 0xd3, 0xa1, /* fc10-fc17 */
|
||||||
0xd3, 0xa5, 0x2f, 0xd3, 0xa3, 0xd3, 0xa7, 0x3e, /* fc18-fc1f */
|
0xd3, 0xa5, 0x2f, 0xd3, 0xa3, 0xd3, 0xa7, 0x3e, /* fc18-fc1f */
|
||||||
0x2c, 0xd3, 0xa0, 0xd3, 0xa4, 0xd3, 0xa6, 0x3e, /* fc20-fc27 */
|
0x2c, 0xd3, 0xa0, 0xd3, 0xa4, 0xd3, 0xa6, 0x3e, /* fc20-fc27 */
|
||||||
0x24, 0xd3, 0xa2, 0xdb, 0xa1, 0x3e, 0x03, 0xd3, /* fc28-fc2f */
|
0x24, 0xd3, 0xa2, 0xdb, 0xa1, 0x3e, 0x03, 0xd3, /* fc28-fc2f */
|
||||||
0x10, 0x3e, 0x11, 0xd3, 0x10, 0xcd, 0xe5, 0xfc, /* fc30-fc37 */
|
0x10, 0x3e, 0x11, 0xd3, 0x10, 0xcd, 0xe5, 0xfc, /* fc30-fc37 */
|
||||||
0x0d, 0x0a, 0x48, 0x44, 0x42, 0x4c, 0x20, 0x31, /* fc38-fc3f */
|
0x0d, 0x0a, 0x48, 0x44, 0x42, 0x4c, 0x20, 0x31, /* fc38-fc3f */
|
||||||
0x2e, 0x30, 0xb1, 0xcd, 0x77, 0xfc, 0x11, 0x2c, /* fc40-fc47 */
|
0x2e, 0x30, 0xb1, 0xcd, 0x77, 0xfc, 0x11, 0x2c, /* fc40-fc47 */
|
||||||
0x00, 0x7a, 0xbb, 0xdb, 0xa5, 0xd2, 0x54, 0xfc, /* fc48-fc4f */
|
0x00, 0x7a, 0xbb, 0xdb, 0xa5, 0xd2, 0x54, 0xfc, /* fc48-fc4f */
|
||||||
0x6c, 0x61, 0x48, 0x47, 0x14, 0xc2, 0x49, 0xfc, /* fc50-fc57 */
|
0x6c, 0x61, 0x48, 0x47, 0x14, 0xc2, 0x49, 0xfc, /* fc50-fc57 */
|
||||||
0xcd, 0xe5, 0xfc, 0x0d, 0x0a, 0x4c, 0x4f, 0x41, /* fc58-fc5f */
|
0xcd, 0xe5, 0xfc, 0x0d, 0x0a, 0x4c, 0x4f, 0x41, /* fc58-fc5f */
|
||||||
0x44, 0x49, 0x4e, 0xc7, 0xd1, 0xd5, 0xcd, 0x77, /* fc60-fc67 */
|
0x44, 0x49, 0x4e, 0xc7, 0xd1, 0xd5, 0xcd, 0x77, /* fc60-fc67 */
|
||||||
0xfc, 0xdb, 0xa5, 0x12, 0x13, 0x05, 0xc2, 0x69, /* fc68-fc6f */
|
0xfc, 0xdb, 0xa5, 0x12, 0x13, 0x05, 0xc2, 0x69, /* fc68-fc6f */
|
||||||
0xfc, 0x23, 0x0d, 0xc2, 0x66, 0xfc, 0xc9, 0xe5, /* fc70-fc77 */
|
0xfc, 0x23, 0x0d, 0xc2, 0x66, 0xfc, 0xc9, 0xe5, /* fc70-fc77 */
|
||||||
0xd5, 0xc5, 0x01, 0xd0, 0xff, 0x11, 0xff, 0xff, /* fc78-fc7f */
|
0xd5, 0xc5, 0x01, 0xd0, 0xff, 0x11, 0xff, 0xff, /* fc78-fc7f */
|
||||||
0x13, 0x09, 0xda, 0x80, 0xfc, 0x7d, 0xc6, 0x30, /* fc80-fc87 */
|
0x13, 0x09, 0xda, 0x80, 0xfc, 0x7d, 0xc6, 0x30, /* fc80-fc87 */
|
||||||
0xeb, 0xfe, 0x18, 0xda, 0x90, 0xfc, 0xc6, 0x08, /* fc88-fc8f */
|
0xeb, 0xfe, 0x18, 0xda, 0x90, 0xfc, 0xc6, 0x08, /* fc88-fc8f */
|
||||||
0x47, 0xcd, 0xaf, 0xfc, 0x26, 0x30, 0xdb, 0xff, /* fc90-fc97 */
|
0x47, 0xcd, 0xaf, 0xfc, 0x26, 0x30, 0xdb, 0xff, /* fc90-fc97 */
|
||||||
0xe6, 0x03, 0x0f, 0x0f, 0xb0, 0xcd, 0xb0, 0xfc, /* fc98-fc9f */
|
0xe6, 0x03, 0x0f, 0x0f, 0xb0, 0xcd, 0xb0, 0xfc, /* fc98-fc9f */
|
||||||
0xdb, 0xa5, 0xdb, 0xa3, 0xaf, 0xd3, 0xa7, 0x3e, /* fca0-fca7 */
|
0xdb, 0xa5, 0xdb, 0xa3, 0xaf, 0xd3, 0xa7, 0x3e, /* fca0-fca7 */
|
||||||
0x50, 0xd3, 0xa3, 0xc1, 0xd1, 0xe1, 0xc9, 0x7d, /* fca8-fcaf */
|
0x50, 0xd3, 0xa3, 0xc1, 0xd1, 0xe1, 0xc9, 0x7d, /* fca8-fcaf */
|
||||||
0xd3, 0xa7, 0xdb, 0xa1, 0xdb, 0xa3, 0xdb, 0xff, /* fcb0-fcb7 */
|
0xd3, 0xa7, 0xdb, 0xa1, 0xdb, 0xa3, 0xdb, 0xff, /* fcb0-fcb7 */
|
||||||
0xe6, 0x00, 0xb4, 0xd3, 0xa3, 0xdb, 0xa0, 0x07, /* fcb8-fcbf */
|
0xe6, 0x00, 0xb4, 0xd3, 0xa3, 0xdb, 0xa0, 0x07, /* fcb8-fcbf */
|
||||||
0xd2, 0xbd, 0xfc, 0xdb, 0xa1, 0xe6, 0x7f, 0xc8, /* fcc0-fcc7 */
|
0xd2, 0xbd, 0xfc, 0xdb, 0xa1, 0xe6, 0x7f, 0xc8, /* fcc0-fcc7 */
|
||||||
0xfb, 0xf5, 0xcd, 0xe5, 0xfc, 0x0d, 0x0a, 0x4c, /* fcc8-fccf */
|
0xfb, 0xf5, 0xcd, 0xe5, 0xfc, 0x0d, 0x0a, 0x4c, /* fcc8-fccf */
|
||||||
0x4f, 0x41, 0x44, 0x20, 0x45, 0x52, 0x52, 0x4f, /* fcd0-fcd7 */
|
0x4f, 0x41, 0x44, 0x20, 0x45, 0x52, 0x52, 0x4f, /* fcd0-fcd7 */
|
||||||
0x52, 0xba, 0x21, 0x00, 0xfd, 0x34, 0xca, 0xde, /* fcd8-fcdf */
|
0x52, 0xba, 0x21, 0x00, 0xfd, 0x34, 0xca, 0xde, /* fcd8-fcdf */
|
||||||
0xfc, 0xe3, 0xc3, 0xcf, 0xfd, 0xe3, 0xdb, 0x10, /* fce0-fce7 */
|
0xfc, 0xe3, 0xc3, 0xcf, 0xfd, 0xe3, 0xdb, 0x10, /* fce0-fce7 */
|
||||||
0xe6, 0x02, 0xca, 0xe6, 0xfc, 0x7e, 0xe6, 0x7f, /* fce8-fcef */
|
0xe6, 0x02, 0xca, 0xe6, 0xfc, 0x7e, 0xe6, 0x7f, /* fce8-fcef */
|
||||||
0xd3, 0x11, 0xbe, 0x23, 0xca, 0xe6, 0xfc, 0xe3, /* fcf0-fcf7 */
|
0xd3, 0x11, 0xbe, 0x23, 0xca, 0xe6, 0xfc, 0xe3, /* fcf0-fcf7 */
|
||||||
0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fcf8-fcff */
|
0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fcf8-fcff */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -253,9 +257,9 @@ static char* cmdTranslate(const int32 cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------
|
/*----------------------------------------------------------------------------------
|
||||||
|
|
||||||
dsk_reset - install I/O handlers and initialize variables.
|
dsk_reset - install I/O handlers and initialize variables.
|
||||||
|
|
||||||
----------------------------------------------------------------------------------*/
|
----------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
static t_stat dsk_reset(DEVICE *dptr) {
|
static t_stat dsk_reset(DEVICE *dptr) {
|
||||||
|
@ -280,7 +284,7 @@ static t_stat dsk_reset(DEVICE *dptr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------------------
|
||||||
hdReturnReady - common I/O handler for several hard disk status ports which set
|
hdReturnReady - common I/O handler for several hard disk status ports which set
|
||||||
bit 7 when the corresponding hard disk function is ready. In the emulator,
|
bit 7 when the corresponding hard disk function is ready. In the emulator,
|
||||||
we're always ready for the next step, so we simply return ready all the time.
|
we're always ready for the next step, so we simply return ready all the time.
|
||||||
|
|
||||||
|
@ -289,13 +293,13 @@ static t_stat dsk_reset(DEVICE *dptr) {
|
||||||
|
|
||||||
0xA2 - ACSTA register. Accessed through the status/control register of 4-PIO
|
0xA2 - ACSTA register. Accessed through the status/control register of 4-PIO
|
||||||
port 1-B. Returns the "command received" status byte.
|
port 1-B. Returns the "command received" status byte.
|
||||||
|
|
||||||
0xA4 - CDSTA register. Accessed through the status/control register of 4-PIO
|
0xA4 - CDSTA register. Accessed through the status/control register of 4-PIO
|
||||||
port 2-A. Returns the "command data available" status byte.
|
port 2-A. Returns the "command data available" status byte.
|
||||||
|
|
||||||
0xA6 - ADSTA register. Accessed through the status/control register of 4-PIO
|
0xA6 - ADSTA register. Accessed through the status/control register of 4-PIO
|
||||||
port 2-B. Returns the "available to write" status byte.
|
port 2-B. Returns the "available to write" status byte.
|
||||||
|
|
||||||
---------------------------------------------------------------------------------------*/
|
---------------------------------------------------------------------------------------*/
|
||||||
static int32 hdReturnReady(const int32 port, const int32 io, const int32 data)
|
static int32 hdReturnReady(const int32 port, const int32 io, const int32 data)
|
||||||
{
|
{
|
||||||
|
@ -305,14 +309,14 @@ static int32 hdReturnReady(const int32 port, const int32 io, const int32 data)
|
||||||
(port == 0xa4 ? "CDSTA" : (port == 0xa6 ? "ADSTA" : "?????")))));
|
(port == 0xa4 ? "CDSTA" : (port == 0xa6 ? "ADSTA" : "?????")))));
|
||||||
return(0x80); // always indicate ready
|
return(0x80); // always indicate ready
|
||||||
|
|
||||||
// output operations have no effect
|
// output operations have no effect
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------
|
/*------------------------------------------------------------
|
||||||
hdCstat (0xA1) CSTAT register. Accessed through the
|
hdCstat (0xA1) CSTAT register. Accessed through the
|
||||||
data register of 4-PIO port 1-A.
|
data register of 4-PIO port 1-A.
|
||||||
|
|
||||||
Comments: Returns error code byte of the most recent
|
Comments: Returns error code byte of the most recent
|
||||||
operation. Reading this byte also clears
|
operation. Reading this byte also clears
|
||||||
the CRDY bit, but this isn't actually done
|
the CRDY bit, but this isn't actually done
|
||||||
in the emulation since we're always ready.
|
in the emulation since we're always ready.
|
||||||
|
@ -323,11 +327,11 @@ static int32 hdCstat(const int32 port, const int32 io, const int32 data)
|
||||||
" IN(%02X = %s) = %02x.\n", PCX, port, (port == 0xa1 ? "CSTAT" : "?????"), cstat);
|
" IN(%02X = %s) = %02x.\n", PCX, port, (port == 0xa1 ? "CSTAT" : "?????"), cstat);
|
||||||
return(cstat);
|
return(cstat);
|
||||||
|
|
||||||
// output operations have no effect
|
// output operations have no effect
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------
|
/*------------------------------------------------------------
|
||||||
hdAcmd (0xA3) ACMD register. Accessed through the
|
hdAcmd (0xA3) ACMD register. Accessed through the
|
||||||
data register of 4-PIO port 1-B.
|
data register of 4-PIO port 1-B.
|
||||||
|
|
||||||
Comments: The high byte of a command is written to
|
Comments: The high byte of a command is written to
|
||||||
|
@ -386,12 +390,12 @@ static int32 hdAcmd(const int32 port, const int32 io, const int32 data)
|
||||||
doRead(port, data, command);
|
doRead(port, data, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
// READ or WRITE BUFFER command. Initiates reading/loading specified buffer.
|
// READ or WRITE BUFFER command. Initiates reading/loading specified buffer.
|
||||||
|
|
||||||
else if ((command == CMD_WRITE_BUF) || (command == CMD_READ_BUF)) {
|
else if ((command == CMD_WRITE_BUF) || (command == CMD_READ_BUF)) {
|
||||||
selectedBuffer = buffer;
|
selectedBuffer = buffer;
|
||||||
maxBufferIdx = cmdLowByte;
|
maxBufferIdx = cmdLowByte;
|
||||||
if (maxBufferIdx == 0)
|
if (maxBufferIdx == 0)
|
||||||
maxBufferIdx = 256;
|
maxBufferIdx = 256;
|
||||||
bufferIdx = 0;
|
bufferIdx = 0;
|
||||||
sim_debug(VERBOSE_MSG, &mhdsk_dev, "MHDSK: " ADDRESS_FORMAT
|
sim_debug(VERBOSE_MSG, &mhdsk_dev, "MHDSK: " ADDRESS_FORMAT
|
||||||
|
@ -440,9 +444,9 @@ static int32 hdAcmd(const int32 port, const int32 io, const int32 data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------------------------------------------------
|
/*------------------------------------------------------------
|
||||||
hdCdata (0xA5) Cdata register. Accessed through the
|
hdCdata (0xA5) Cdata register. Accessed through the
|
||||||
data register of 4-PIO port 1-B.
|
data register of 4-PIO port 1-B.
|
||||||
|
|
||||||
Comments: Returns data from the read buffer
|
Comments: Returns data from the read buffer
|
||||||
-------------------------------------------------------------*/
|
-------------------------------------------------------------*/
|
||||||
static int32 hdCdata(const int32 port, const int32 io, const int32 data)
|
static int32 hdCdata(const int32 port, const int32 io, const int32 data)
|
||||||
|
@ -464,10 +468,10 @@ static int32 hdCdata(const int32 port, const int32 io, const int32 data)
|
||||||
|
|
||||||
|
|
||||||
/*------------------------------------------------------------
|
/*------------------------------------------------------------
|
||||||
hdAdata (0xA7) ADATA register. Accessed through the
|
hdAdata (0xA7) ADATA register. Accessed through the
|
||||||
data register of 4-PIO port 2-B.
|
data register of 4-PIO port 2-B.
|
||||||
|
|
||||||
Comments: Accepts data into the current buffer
|
Comments: Accepts data into the current buffer
|
||||||
and is also the low byte of a command.
|
and is also the low byte of a command.
|
||||||
-------------------------------------------------------------*/
|
-------------------------------------------------------------*/
|
||||||
static int32 hdAdata(const int32 port, const int32 io, const int32 data)
|
static int32 hdAdata(const int32 port, const int32 io, const int32 data)
|
||||||
|
@ -487,21 +491,21 @@ static int32 hdAdata(const int32 port, const int32 io, const int32 data)
|
||||||
|
|
||||||
/*-- doRead -------------------------------------------------
|
/*-- doRead -------------------------------------------------
|
||||||
Performs read from MITS Hard Disk image file
|
Performs read from MITS Hard Disk image file
|
||||||
|
|
||||||
Params: nothing
|
Params: nothing
|
||||||
Uses: selectedTrack, selectedHead, selectedSector
|
Uses: selectedTrack, selectedHead, selectedSector
|
||||||
selectedDisk, diskBuf[], mhdsk_dev
|
selectedDisk, diskBuf[], mhdsk_dev
|
||||||
Returns: nothing (updates cstat directly)
|
Returns: nothing (updates cstat directly)
|
||||||
Comments:
|
Comments:
|
||||||
-------------------------------------------------------------*/
|
-------------------------------------------------------------*/
|
||||||
static void doRead(const int32 port, const int32 data, const uint32 command)
|
static void doRead(const int32 port, const int32 data, const uint32 command)
|
||||||
{
|
{
|
||||||
UNIT *uptr;
|
UNIT *uptr;
|
||||||
uint32 fileOffset;
|
uint32 fileOffset;
|
||||||
|
|
||||||
uptr = mhdsk_dev.units + selectedDisk;
|
uptr = mhdsk_dev.units + selectedDisk;
|
||||||
fileOffset = HDSK_CYLINDER_SIZE * selectedTrack +
|
fileOffset = HDSK_CYLINDER_SIZE * selectedTrack +
|
||||||
HDSK_TRACK_SIZE * (selectedHead & 0x01) +
|
HDSK_TRACK_SIZE * (selectedHead & 0x01) +
|
||||||
HDSK_SECTOR_SIZE * selectedSector;
|
HDSK_SECTOR_SIZE * selectedSector;
|
||||||
if (sim_fseek(uptr->fileref, fileOffset, SEEK_SET))
|
if (sim_fseek(uptr->fileref, fileOffset, SEEK_SET))
|
||||||
cstat = CSTAT_NOT_READY; /* seek error */
|
cstat = CSTAT_NOT_READY; /* seek error */
|
||||||
|
@ -518,23 +522,23 @@ static void doRead(const int32 port, const int32 data, const uint32 command)
|
||||||
|
|
||||||
/*-- doWrite ------------------------------------------------
|
/*-- doWrite ------------------------------------------------
|
||||||
Performs write to MITS Hard Disk image file
|
Performs write to MITS Hard Disk image file
|
||||||
|
|
||||||
Params: none
|
Params: none
|
||||||
Uses: selectedTrack, selectedHead, selectedSector
|
Uses: selectedTrack, selectedHead, selectedSector
|
||||||
selectedDisk, diskBuf[], mhdsk_dev
|
selectedDisk, diskBuf[], mhdsk_dev
|
||||||
Returns: nothing (updates cstat directly)
|
Returns: nothing (updates cstat directly)
|
||||||
Comments:
|
Comments:
|
||||||
-------------------------------------------------------------*/
|
-------------------------------------------------------------*/
|
||||||
static void doWrite(const int32 port, const int32 data, const uint32 command)
|
static void doWrite(const int32 port, const int32 data, const uint32 command)
|
||||||
{
|
{
|
||||||
UNIT *uptr;
|
UNIT *uptr;
|
||||||
uint32 fileOffset;
|
uint32 fileOffset;
|
||||||
|
|
||||||
uptr = mhdsk_dev.units + selectedDisk;
|
uptr = mhdsk_dev.units + selectedDisk;
|
||||||
if (((uptr->flags) & UNIT_DSK_WLK) == 0) { /* write enabled */
|
if (((uptr->flags) & UNIT_DSK_WLK) == 0) { /* write enabled */
|
||||||
fileOffset = HDSK_CYLINDER_SIZE * selectedTrack +
|
fileOffset = HDSK_CYLINDER_SIZE * selectedTrack +
|
||||||
HDSK_TRACK_SIZE * (selectedHead & 0x01) +
|
HDSK_TRACK_SIZE * (selectedHead & 0x01) +
|
||||||
HDSK_SECTOR_SIZE * selectedSector;
|
HDSK_SECTOR_SIZE * selectedSector;
|
||||||
if (sim_fseek(uptr->fileref, fileOffset, SEEK_SET))
|
if (sim_fseek(uptr->fileref, fileOffset, SEEK_SET))
|
||||||
cstat = CSTAT_NOT_READY; /* seek error */
|
cstat = CSTAT_NOT_READY; /* seek error */
|
||||||
else if (sim_fwrite(diskBuf[selectedBuffer], 1, HDSK_SECTOR_SIZE, uptr->fileref) !=
|
else if (sim_fwrite(diskBuf[selectedBuffer], 1, HDSK_SECTOR_SIZE, uptr->fileref) !=
|
||||||
|
|
|
@ -77,30 +77,32 @@ static struct {
|
||||||
static UNIT net_unit = {
|
static UNIT net_unit = {
|
||||||
UDATA (&net_svc, UNIT_ATTABLE, 0),
|
UDATA (&net_svc, UNIT_ATTABLE, 0),
|
||||||
0, /* wait, set in attach */
|
0, /* wait, set in attach */
|
||||||
0, /* u3, unused */
|
0, /* u3, unused */
|
||||||
0, /* u4, unused */
|
0, /* u4, unused */
|
||||||
0, /* u5, unused */
|
0, /* u5, unused */
|
||||||
0, /* u6, unused */
|
0, /* u6, unused */
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG net_reg[] = {
|
static REG net_reg[] = {
|
||||||
{ DRDATA (POLL, net_unit.wait, 32) },
|
{ DRDATAD (POLL, net_unit.wait, 32, "Polling interval") },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB net_mod[] = {
|
static MTAB net_mod[] = {
|
||||||
{ UNIT_SERVER, 0, "CLIENT", "CLIENT", &set_net}, /* machine is a client */
|
{ UNIT_SERVER, 0, "CLIENT", "CLIENT", &set_net, NULL, NULL,
|
||||||
{ UNIT_SERVER, UNIT_SERVER, "SERVER", "SERVER", &set_net}, /* machine is a server */
|
"Sets machine to client mode"}, /* machine is a client */
|
||||||
|
{ UNIT_SERVER, UNIT_SERVER, "SERVER", "SERVER", &set_net, NULL, NULL,
|
||||||
|
"Sets machine to server mode"}, /* machine is a server */
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB net_dt[] = {
|
static DEBTAB net_dt[] = {
|
||||||
{ "ACCEPT", ACCEPT_MSG },
|
{ "ACCEPT", ACCEPT_MSG, "Accept messages" },
|
||||||
{ "DROP", DROP_MSG },
|
{ "DROP", DROP_MSG, "Drop messages" },
|
||||||
{ "IN", IN_MSG },
|
{ "IN", IN_MSG, "Incoming messages" },
|
||||||
{ "OUT", OUT_MSG },
|
{ "OUT", OUT_MSG, "Outgoing messages" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE net_dev = {
|
DEVICE net_dev = {
|
||||||
|
|
|
@ -64,27 +64,27 @@
|
||||||
|
|
||||||
uint8 *URLContents(const char *URL, uint32 *length);
|
uint8 *URLContents(const char *URL, uint32 *length);
|
||||||
#ifndef URL_READER_SUPPORT
|
#ifndef URL_READER_SUPPORT
|
||||||
#define RESULT_BUFFER_LENGTH 1024
|
#define RESULT_BUFFER_LENGTH 1024
|
||||||
#define RESULT_LEAD_IN "URL is not supported on this platform. START URL \""
|
#define RESULT_LEAD_IN "URL is not supported on this platform. START URL \""
|
||||||
#define RESULT_LEAD_OUT "\" URL END."
|
#define RESULT_LEAD_OUT "\" URL END."
|
||||||
uint8 *URLContents(const char *URL, uint32 *length) {
|
uint8 *URLContents(const char *URL, uint32 *length) {
|
||||||
char str[RESULT_BUFFER_LENGTH] = RESULT_LEAD_IN;
|
char str[RESULT_BUFFER_LENGTH] = RESULT_LEAD_IN;
|
||||||
char *result;
|
char *result;
|
||||||
strncat(str, URL, RESULT_BUFFER_LENGTH - strlen(RESULT_LEAD_IN) - strlen(RESULT_LEAD_OUT) - 1);
|
strncat(str, URL, RESULT_BUFFER_LENGTH - strlen(RESULT_LEAD_IN) - strlen(RESULT_LEAD_OUT) - 1);
|
||||||
strcat(str, RESULT_LEAD_OUT);
|
strcat(str, RESULT_LEAD_OUT);
|
||||||
result = (char*)malloc(strlen(str));
|
result = (char*)malloc(strlen(str));
|
||||||
strcpy(result, str);
|
strcpy(result, str);
|
||||||
*length = strlen(str);
|
*length = strlen(str);
|
||||||
return (uint8*)result;
|
return (uint8*)result;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define IN_MSG (1 << 0)
|
#define IN_MSG (1 << 0)
|
||||||
#define OUT_MSG (1 << 1)
|
#define OUT_MSG (1 << 1)
|
||||||
#define CMD_MSG (1 << 2)
|
#define CMD_MSG (1 << 2)
|
||||||
#define VERBOSE_MSG (1 << 3)
|
#define VERBOSE_MSG (1 << 3)
|
||||||
#define BUFFER_EMPTY_MSG (1 << 4)
|
#define BUFFER_EMPTY_MSG (1 << 4)
|
||||||
|
|
||||||
#define UNIT_V_SIO_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */
|
#define UNIT_V_SIO_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */
|
||||||
#define UNIT_SIO_ANSI (1 << UNIT_V_SIO_ANSI)
|
#define UNIT_SIO_ANSI (1 << UNIT_V_SIO_ANSI)
|
||||||
|
@ -172,12 +172,12 @@ extern volatile int32 stop_cpu;
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB generic_dt[] = {
|
static DEBTAB generic_dt[] = {
|
||||||
{ "IN", IN_MSG },
|
{ "IN", IN_MSG, "IN messages" },
|
||||||
{ "OUT", OUT_MSG },
|
{ "OUT", OUT_MSG, "OUT messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Commands" },
|
||||||
{ "VERBOSE", VERBOSE_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "BUFFEREMPTY", BUFFER_EMPTY_MSG },
|
{ "BUFFEREMPTY", BUFFER_EMPTY_MSG, "IN for empty buffer" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* SIMH pseudo device status registers */
|
/* SIMH pseudo device status registers */
|
||||||
|
@ -225,10 +225,10 @@ static int32 lastCPMStatus = 0; /* result of last attachCPM comm
|
||||||
static int32 lastCommand = 0; /* most recent command processed on port 0xfeh */
|
static int32 lastCommand = 0; /* most recent command processed on port 0xfeh */
|
||||||
static int32 getCommonPos = 0; /* determines state for sending the 'common' register */
|
static int32 getCommonPos = 0; /* determines state for sending the 'common' register */
|
||||||
|
|
||||||
/* CPU Clock Frequency related */
|
/* CPU Clock Frequency related */
|
||||||
static uint32 newClockFrequency;
|
static uint32 newClockFrequency;
|
||||||
static int32 setClockFrequencyPos = 0; /* determines state for sending the clock frequency */
|
static int32 setClockFrequencyPos = 0; /* determines state for sending the clock frequency */
|
||||||
static int32 getClockFrequencyPos = 0; /* determines state for receiving the clock frequency */
|
static int32 getClockFrequencyPos = 0; /* determines state for receiving the clock frequency */
|
||||||
|
|
||||||
/* support for wild card expansion */
|
/* support for wild card expansion */
|
||||||
#if UNIX_PLATFORM
|
#if UNIX_PLATFORM
|
||||||
|
@ -274,45 +274,76 @@ static UNIT sio_unit = {
|
||||||
100000, /* wait */
|
100000, /* wait */
|
||||||
FALSE, /* u3 = FALSE, no character available in buffer */
|
FALSE, /* u3 = FALSE, no character available in buffer */
|
||||||
FALSE, /* u4 = FALSE, terminal input is not attached to a file */
|
FALSE, /* u4 = FALSE, terminal input is not attached to a file */
|
||||||
0, /* u5 = 0, not used */
|
0, /* u5 = 0, not used */
|
||||||
0 /* u6 = 0, not used */
|
0 /* u6 = 0, not used */
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG sio_reg[] = {
|
static REG sio_reg[] = {
|
||||||
{ DRDATA (SIOWLEV, warnLevelSIO, 32) },
|
{ DRDATAD (SIOWLEV, warnLevelSIO, 32,
|
||||||
{ DRDATA (WRNUPTP, warnUnattachedPTP, 32) },
|
"Warn level SIO register") },
|
||||||
{ DRDATA (WRNUPTR, warnUnattachedPTR, 32) },
|
{ DRDATAD (WRNUPTP, warnUnattachedPTP, 32,
|
||||||
{ DRDATA (WRNPTRE, warnPTREOF, 32) },
|
"Counter for unattached PTP access") },
|
||||||
{ DRDATA (WRUPORT, warnUnassignedPort, 32) },
|
{ DRDATAD (WRNUPTR, warnUnattachedPTR, 32,
|
||||||
{ HRDATA (FILEATT, sio_unit.u4, 8), REG_RO }, /* TRUE iff terminal input is attached to a file */
|
"Counter for unattached PTR access") },
|
||||||
{ HRDATA (TSTATUS, sio_unit.u3, 8) }, /* TRUE iff a character available in sio_unit.buf */
|
{ DRDATAD (WRNPTRE, warnPTREOF, 32,
|
||||||
{ DRDATA (TBUFFER, sio_unit.buf, 8) }, /* input buffer for one character */
|
"Counter for EOF reached for PTR") },
|
||||||
{ DRDATA (KEYBDI, keyboardInterrupt, 3), REG_RO },
|
{ DRDATAD (WRUPORT, warnUnassignedPort, 32,
|
||||||
{ HRDATA (KEYBDH, keyboardInterruptHandler, 16) },
|
"Counter for unassigned port") },
|
||||||
|
{ HRDATAD (FILEATT, sio_unit.u4, 8,
|
||||||
|
"BOOL to determine whether terminal input is attached to a file"), REG_RO },
|
||||||
|
/* TRUE iff terminal input is attached to a file */
|
||||||
|
{ HRDATAD (TSTATUS, sio_unit.u3, 8,
|
||||||
|
"BOOL to determine whethere a character is available") },
|
||||||
|
/* TRUE iff a character available in sio_unit.buf */
|
||||||
|
{ DRDATAD (TBUFFER, sio_unit.buf, 8,
|
||||||
|
"Input buffer register") },
|
||||||
|
/* input buffer for one character */
|
||||||
|
{ DRDATAD (KEYBDI, keyboardInterrupt, 3,
|
||||||
|
"BOOL to determine whether a keyboard interrupt is pending"), REG_RO },
|
||||||
|
{ HRDATAD (KEYBDH, keyboardInterruptHandler, 16,
|
||||||
|
"Address of keyboard interrupt handler") },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB sio_mod[] = {
|
static MTAB sio_mod[] = {
|
||||||
{ UNIT_SIO_ANSI, 0, "TTY", "TTY", NULL }, /* keep bit 8 as is for output */
|
{ UNIT_SIO_ANSI, 0, "TTY", "TTY", NULL, NULL, NULL,
|
||||||
{ UNIT_SIO_ANSI, UNIT_SIO_ANSI, "ANSI", "ANSI", NULL }, /* set bit 8 to 0 before output */
|
"Do not touch bit 8 of console output"}, /* keep bit 8 as is for output */
|
||||||
{ UNIT_SIO_UPPER, 0, "ALL", "ALL", NULL }, /* do not change case of input characters */
|
{ UNIT_SIO_ANSI, UNIT_SIO_ANSI, "ANSI", "ANSI", NULL, NULL, NULL,
|
||||||
{ UNIT_SIO_UPPER, UNIT_SIO_UPPER, "UPPER", "UPPER", NULL }, /* change input characters to upper case */
|
"Set bit 8 of console output to 0"}, /* set bit 8 to 0 before output */
|
||||||
{ UNIT_SIO_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */
|
{ UNIT_SIO_UPPER, 0, "ALL", "ALL", NULL, NULL, NULL,
|
||||||
{ UNIT_SIO_BS, UNIT_SIO_BS, "DEL", "DEL", NULL }, /* map backspace to delete */
|
"Console input remains unchanged" }, /* do not change case of input characters */
|
||||||
{ UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* quiet, no error messages */
|
{ UNIT_SIO_UPPER, UNIT_SIO_UPPER, "UPPER", "UPPER", NULL, NULL, NULL,
|
||||||
{ UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
"Convert console input to upper case" }, /* change input characters to upper case */
|
||||||
/* verbose, display warning messages */
|
{ UNIT_SIO_BS, 0, "BS", "BS", NULL, NULL, NULL,
|
||||||
{ UNIT_SIO_MAP, 0, "NOMAP", "NOMAP", NULL }, /* disable character mapping */
|
"Map delete to backspace" }, /* map delete to backspace */
|
||||||
{ UNIT_SIO_MAP, UNIT_SIO_MAP, "MAP", "MAP", NULL }, /* enable all character mapping */
|
{ UNIT_SIO_BS, UNIT_SIO_BS, "DEL", "DEL", NULL, NULL, NULL,
|
||||||
{ UNIT_SIO_BELL, 0, "BELL", "BELL", NULL }, /* enable bell character */
|
"Map backspace to delete" }, /* map backspace to delete */
|
||||||
{ UNIT_SIO_BELL, UNIT_SIO_BELL, "NOBELL", "NOBELL", NULL }, /* suppress ringing the bell */
|
{ UNIT_SIO_VERBOSE, 0, "QUIET", "QUIET", NULL, NULL, NULL,
|
||||||
{ UNIT_SIO_SLEEP, 0, "NOSLEEP", "NOSLEEP", NULL }, /* no sleep after keyboard status check */
|
"Do not display SIO error messages" }, /* quiet, no error messages */
|
||||||
{ UNIT_SIO_SLEEP, UNIT_SIO_SLEEP, "SLEEP", "SLEEP", NULL }, /* sleep after keyboard status check */
|
{ UNIT_SIO_VERBOSE, UNIT_SIO_VERBOSE, "VERBOSE", "VERBOSE", NULL, NULL, NULL,
|
||||||
/* no keyboard interrupts */
|
"Display verbose messages" }, /* verbose, display warning messages */
|
||||||
{ UNIT_SIO_INTERRUPT, 0, "NOINTERRUPT","NOINTERRUPT",&sio_dev_set_interruptoff },
|
{ UNIT_SIO_MAP, 0, "NOMAP", "NOMAP", NULL, NULL, NULL,
|
||||||
/* create keyboard interrupts */
|
"Do not map any character" }, /* disable character mapping */
|
||||||
{ UNIT_SIO_INTERRUPT, UNIT_SIO_INTERRUPT, "INTERRUPT","INTERRUPT",&sio_dev_set_interrupton },
|
{ UNIT_SIO_MAP, UNIT_SIO_MAP, "MAP", "MAP", NULL, NULL, NULL,
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "PORT", "PORT", &sio_dev_set_port, &sio_dev_show_port },
|
"Enable mapping of characters" }, /* enable all character mapping */
|
||||||
|
{ UNIT_SIO_BELL, 0, "BELL", "BELL", NULL, NULL, NULL,
|
||||||
|
"Control-G sounds the bell" }, /* enable bell character */
|
||||||
|
{ UNIT_SIO_BELL, UNIT_SIO_BELL, "NOBELL", "NOBELL", NULL, NULL, NULL,
|
||||||
|
"The bell sound is suppressed" }, /* suppress ringing the bell */
|
||||||
|
{ UNIT_SIO_SLEEP, 0, "NOSLEEP", "NOSLEEP", NULL, NULL, NULL,
|
||||||
|
"Do not sleep after SIO status checks" }, /* no sleep after keyboard status check */
|
||||||
|
{ UNIT_SIO_SLEEP, UNIT_SIO_SLEEP, "SLEEP", "SLEEP", NULL, NULL, NULL,
|
||||||
|
"Sleep after SIO status checks" }, /* sleep after keyboard status check */
|
||||||
|
/* no keyboard interrupts */
|
||||||
|
{ UNIT_SIO_INTERRUPT, 0, "NOINTERRUPT", "NOINTERRUPT",
|
||||||
|
&sio_dev_set_interruptoff, NULL, NULL, "Status port 0 does not create interrupts" },
|
||||||
|
/* create keyboard interrupts */
|
||||||
|
{ UNIT_SIO_INTERRUPT, UNIT_SIO_INTERRUPT, "INTERRUPT", "INTERRUPT",
|
||||||
|
&sio_dev_set_interrupton, NULL, NULL,
|
||||||
|
"Status port 0 creates an interrupt when a character becomes available" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV, 0, "PORT", "PORT",
|
||||||
|
&sio_dev_set_port, &sio_dev_show_port, NULL,
|
||||||
|
"Set port to Port/Terminal/Read/NotRead/Write/Reset/Reset/Data" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -334,7 +365,7 @@ static UNIT ptr_unit = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG ptr_reg[] = {
|
static REG ptr_reg[] = {
|
||||||
{ HRDATA (STAT, ptr_unit.u3, 8) },
|
{ HRDATAD (STAT, ptr_unit.u3, 8, "Status register") },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -367,43 +398,70 @@ static UNIT simh_unit = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG simh_reg[] = {
|
static REG simh_reg[] = {
|
||||||
{ DRDATA (CZD, ClockZSDOSDelta, 32) },
|
{ DRDATAD (CZD, ClockZSDOSDelta, 32,
|
||||||
{ DRDATA (SCZP, setClockZSDOSPos, 8), REG_RO },
|
"ZSDOS Clock - Delta between real clock and AltairZ80 clock") },
|
||||||
{ HRDATA (SCZA, setClockZSDOSAdr, 16), REG_RO },
|
{ DRDATAD (SCZP, setClockZSDOSPos, 8,
|
||||||
{ DRDATA (GCZP, getClockZSDOSPos, 8), REG_RO },
|
"ZSDOS Clock - Status register for receiving address of parameter block"), REG_RO },
|
||||||
|
{ HRDATAD (SCZA, setClockZSDOSAdr, 16,
|
||||||
|
"ZSDOS Clock - Address of 6 byte parameter block for setting time"), REG_RO },
|
||||||
|
{ DRDATAD (GCZP, getClockZSDOSPos, 8,
|
||||||
|
"ZSDOS Clock - Status register for sending clock information"), REG_RO },
|
||||||
|
|
||||||
{ DRDATA (CC3D, ClockCPM3Delta, 32) },
|
{ DRDATAD (CC3D, ClockCPM3Delta, 32,
|
||||||
{ DRDATA (SC3DP, setClockCPM3Pos, 8), REG_RO },
|
"CP/M 3 Clock - Delta between real clock and AltairZ80 clock") },
|
||||||
{ HRDATA (SC3DA, setClockCPM3Adr, 16), REG_RO },
|
{ DRDATAD (SC3DP, setClockCPM3Pos, 8,
|
||||||
{ DRDATA (GC3DP, getClockCPM3Pos, 8), REG_RO },
|
"CP/M 3 Clock - Status register for receiving address of parameter block"), REG_RO },
|
||||||
{ DRDATA (D3DO, daysCPM3SinceOrg, 32), REG_RO },
|
{ HRDATAD (SC3DA, setClockCPM3Adr, 16,
|
||||||
|
"CP/M 3 Clock - Address of 5 byte parameter block for setting time"), REG_RO },
|
||||||
|
{ DRDATAD (GC3DP, getClockCPM3Pos, 8,
|
||||||
|
"CP/M 3 Clock - Status register for sending clock information"), REG_RO },
|
||||||
|
{ DRDATAD (D3DO, daysCPM3SinceOrg, 32,
|
||||||
|
"CP/M 3 Clock - Days since 1-Jan-1978"), REG_RO },
|
||||||
|
|
||||||
{ DRDATA (TOFNI, timeOfNextInterrupt, 32), REG_RO },
|
{ DRDATAD (TOFNI, timeOfNextInterrupt, 32,
|
||||||
{ DRDATA (TIMI, timerInterrupt, 3) },
|
"Time when next interrupt is scheduled"), REG_RO },
|
||||||
{ HRDATA (TIMH, timerInterruptHandler, 16) },
|
{ DRDATAD (TIMI, timerInterrupt, 3,
|
||||||
{ DRDATA (STIAP, setTimerInterruptAdrPos,8), REG_RO },
|
"BOOL - determines whether a timer interrupt is pending") },
|
||||||
{ DRDATA (TIMD, timerDelta, 32) },
|
{ HRDATAD (TIMH, timerInterruptHandler, 16,
|
||||||
{ DRDATA (STDP, setTimerDeltaPos, 8), REG_RO },
|
"Address of timer interrupt handling routine") },
|
||||||
{ DRDATA (SLEEP, SIMHSleep, 32) },
|
{ DRDATAD (STIAP, setTimerInterruptAdrPos,8,
|
||||||
{ DRDATA (VOSLP, sleepAllowedStart, 32) },
|
"Status register for receiving address of timer interrupt handler"), REG_RO },
|
||||||
|
{ DRDATAD (TIMD, timerDelta, 32,
|
||||||
|
"Time in milliseconds between timer interrupts") },
|
||||||
|
{ DRDATAD (STDP, setTimerDeltaPos, 8,
|
||||||
|
"Status register for receiving the timer delta"), REG_RO },
|
||||||
|
{ DRDATAD (SLEEP, SIMHSleep, 32,
|
||||||
|
"Sleep time in milliseconds after SIO status check (when enabled)") },
|
||||||
|
{ DRDATAD (VOSLP, sleepAllowedStart, 32,
|
||||||
|
"Only sleep when this many unsuccessful SIO status checks have been made") },
|
||||||
|
|
||||||
{ DRDATA (STPDT, stopWatchDelta, 32), REG_RO },
|
{ DRDATAD (STPDT, stopWatchDelta, 32,
|
||||||
{ DRDATA (STPOS, getStopWatchDeltaPos, 8), REG_RO },
|
"Elapsed time of stop watch"), REG_RO },
|
||||||
{ DRDATA (STPNW, stopWatchNow, 32), REG_RO },
|
{ DRDATAD (STPOS, getStopWatchDeltaPos, 8,
|
||||||
{ DRDATA (MTSP, markTimeSP, 8), REG_RO },
|
"Status register for receiving stop watch delta"), REG_RO },
|
||||||
|
{ DRDATAD (STPNW, stopWatchNow, 32,
|
||||||
|
"Starting time of stop watch"), REG_RO },
|
||||||
|
{ DRDATAD (MTSP, markTimeSP, 8,
|
||||||
|
"Stack pointer of timer stack"), REG_RO },
|
||||||
|
|
||||||
{ DRDATA (VPOS, versionPos, 8), REG_RO },
|
{ DRDATAD (VPOS, versionPos, 8,
|
||||||
{ DRDATA (LCPMS, lastCPMStatus, 8), REG_RO },
|
"Status register for sending version information"), REG_RO },
|
||||||
{ DRDATA (LCMD, lastCommand, 8), REG_RO },
|
{ DRDATAD (LCPMS, lastCPMStatus, 8,
|
||||||
{ DRDATA (CPOS, getCommonPos, 8), REG_RO },
|
"Result of last attachCPM command"), REG_RO },
|
||||||
|
{ DRDATAD (LCMD, lastCommand, 8,
|
||||||
|
"Last command processed on SIMH port"), REG_RO },
|
||||||
|
{ DRDATAD (CPOS, getCommonPos, 8,
|
||||||
|
"Status register for sending the COMMON register"), REG_RO },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB simh_mod[] = {
|
static MTAB simh_mod[] = {
|
||||||
/* timer generated interrupts are off */
|
/* timer generated interrupts are off */
|
||||||
{ UNIT_SIMH_TIMERON, 0, "TIMEROFF", "TIMEROFF", &simh_dev_set_timeroff },
|
{ UNIT_SIMH_TIMERON, 0, "TIMEROFF", "TIMEROFF", &simh_dev_set_timeroff,
|
||||||
|
NULL, NULL, "Stop periodic timer interrupts" },
|
||||||
/* timer generated interrupts are on */
|
/* timer generated interrupts are on */
|
||||||
{ UNIT_SIMH_TIMERON, UNIT_SIMH_TIMERON, "TIMERON", "TIMERON", &simh_dev_set_timeron },
|
{ UNIT_SIMH_TIMERON, UNIT_SIMH_TIMERON, "TIMERON", "TIMERON", &simh_dev_set_timeron,
|
||||||
|
NULL, NULL, "Start periodic timer interrupts" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -456,7 +514,7 @@ static t_stat sio_reset(DEVICE *dptr) {
|
||||||
int32 i;
|
int32 i;
|
||||||
sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT " Reset\n", PCX);
|
sim_debug(VERBOSE_MSG, &sio_dev, "SIO: " ADDRESS_FORMAT " Reset\n", PCX);
|
||||||
sio_unit.u3 = FALSE; /* no character in terminal input buffer */
|
sio_unit.u3 = FALSE; /* no character in terminal input buffer */
|
||||||
sio_unit.buf = 0;
|
sio_unit.buf = 0;
|
||||||
resetSIOWarningFlags();
|
resetSIOWarningFlags();
|
||||||
if (sio_unit.u4) /* is terminal input attached to a file? */
|
if (sio_unit.u4) /* is terminal input attached to a file? */
|
||||||
rewind(sio_unit.fileref); /* yes, rewind input */
|
rewind(sio_unit.fileref); /* yes, rewind input */
|
||||||
|
@ -472,7 +530,7 @@ static t_stat ptr_reset(DEVICE *dptr) {
|
||||||
sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT " Reset\n", PCX);
|
sim_debug(VERBOSE_MSG, &ptr_dev, "PTR: " ADDRESS_FORMAT " Reset\n", PCX);
|
||||||
resetSIOWarningFlags();
|
resetSIOWarningFlags();
|
||||||
ptr_unit.u3 = FALSE; /* End Of File not yet reached */
|
ptr_unit.u3 = FALSE; /* End Of File not yet reached */
|
||||||
ptr_unit.buf = 0;
|
ptr_unit.buf = 0;
|
||||||
if (ptr_unit.flags & UNIT_ATT) /* attached? */
|
if (ptr_unit.flags & UNIT_ATT) /* attached? */
|
||||||
rewind(ptr_unit.fileref);
|
rewind(ptr_unit.fileref);
|
||||||
sim_map_resource(0x12, 1, RESOURCE_TYPE_IO, &sio1s, dptr->flags & DEV_DIS);
|
sim_map_resource(0x12, 1, RESOURCE_TYPE_IO, &sio1s, dptr->flags & DEV_DIS);
|
||||||
|
@ -650,18 +708,18 @@ static int32 sio0sCore(const int32 port, const int32 io, const int32 data) {
|
||||||
pollConnection();
|
pollConnection();
|
||||||
if (io == 0) { /* IN */
|
if (io == 0) { /* IN */
|
||||||
if (sio_unit.u4) { /* attached to a file? */
|
if (sio_unit.u4) { /* attached to a file? */
|
||||||
if (sio_unit.u3) /* character available? */
|
if (sio_unit.u3) /* character available? */
|
||||||
return spi.sio_can_read | spi.sio_can_write;
|
return spi.sio_can_read | spi.sio_can_write;
|
||||||
ch = getc(sio_unit.fileref);
|
ch = getc(sio_unit.fileref);
|
||||||
if (ch == EOF) {
|
if (ch == EOF) {
|
||||||
sio_detach(&sio_unit); /* detach file and switch to keyboard input */
|
sio_detach(&sio_unit); /* detach file and switch to keyboard input */
|
||||||
return spi.sio_cannot_read | spi.sio_can_write;
|
return spi.sio_cannot_read | spi.sio_can_write;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sio_unit.u3 = TRUE; /* indicate character available */
|
sio_unit.u3 = TRUE; /* indicate character available */
|
||||||
sio_unit.buf = ch; /* store character in buffer */
|
sio_unit.buf = ch; /* store character in buffer */
|
||||||
return spi.sio_can_read | spi.sio_can_write;
|
return spi.sio_can_read | spi.sio_can_write;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sio_unit.flags & UNIT_ATT) { /* attached to a port? */
|
if (sio_unit.flags & UNIT_ATT) { /* attached to a port? */
|
||||||
if (tmxr_rqln(&TerminalLines[spi.terminalLine]))
|
if (tmxr_rqln(&TerminalLines[spi.terminalLine]))
|
||||||
|
@ -692,8 +750,8 @@ static int32 sio0sCore(const int32 port, const int32 io, const int32 data) {
|
||||||
return spi.sio_cannot_read | spi.sio_can_write;
|
return spi.sio_cannot_read | spi.sio_can_write;
|
||||||
} /* OUT follows, no fall-through from IN */
|
} /* OUT follows, no fall-through from IN */
|
||||||
if (spi.hasReset && (data == spi.sio_reset)) { /* reset command */
|
if (spi.hasReset && (data == spi.sio_reset)) { /* reset command */
|
||||||
if (!sio_unit.u4) /* only reset for regular console I/O */
|
if (!sio_unit.u4) /* only reset for regular console I/O */
|
||||||
sio_unit.u3 = FALSE; /* indicate that no character is available */
|
sio_unit.u3 = FALSE; /* indicate that no character is available */
|
||||||
sim_debug(CMD_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT
|
sim_debug(CMD_MSG, &sio_dev, "\tSIO_S: " ADDRESS_FORMAT
|
||||||
" Command OUT(0x%03x) = 0x%02x\n", PCX, port, data);
|
" Command OUT(0x%03x) = 0x%02x\n", PCX, port, data);
|
||||||
}
|
}
|
||||||
|
@ -723,7 +781,7 @@ static int32 sio0dCore(const int32 port, const int32 io, const int32 data) {
|
||||||
if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4))
|
if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4))
|
||||||
return mapCharacter(tmxr_getc_ln(&TerminalLines[spi.terminalLine]));
|
return mapCharacter(tmxr_getc_ln(&TerminalLines[spi.terminalLine]));
|
||||||
if (!sio_unit.u3) {
|
if (!sio_unit.u3) {
|
||||||
sim_debug(BUFFER_EMPTY_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT
|
sim_debug(BUFFER_EMPTY_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT
|
||||||
" IN(0x%03x) for empty character buffer\n", PCX, port);
|
" IN(0x%03x) for empty character buffer\n", PCX, port);
|
||||||
}
|
}
|
||||||
sio_unit.u3 = FALSE; /* no character is available any more */
|
sio_unit.u3 = FALSE; /* no character is available any more */
|
||||||
|
@ -733,9 +791,9 @@ static int32 sio0dCore(const int32 port, const int32 io, const int32 data) {
|
||||||
ch = sio_unit.flags & UNIT_SIO_ANSI ? data & 0x7f : data; /* clear highest bit in ANSI mode */
|
ch = sio_unit.flags & UNIT_SIO_ANSI ? data & 0x7f : data; /* clear highest bit in ANSI mode */
|
||||||
if ((ch != CONTROLG_CHAR) || !(sio_unit.flags & UNIT_SIO_BELL)) {
|
if ((ch != CONTROLG_CHAR) || !(sio_unit.flags & UNIT_SIO_BELL)) {
|
||||||
voidSleep();
|
voidSleep();
|
||||||
if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4)) { /* attached to a port and not to a file */
|
if ((sio_unit.flags & UNIT_ATT) && (!sio_unit.u4)) { /* attached to a port and not to a file */
|
||||||
tmxr_putc_ln(&TerminalLines[spi.terminalLine], ch); /* status ignored */
|
tmxr_putc_ln(&TerminalLines[spi.terminalLine], ch); /* status ignored */
|
||||||
tmxr_poll_tx(&altairTMXR); /* poll xmt */
|
tmxr_poll_tx(&altairTMXR); /* poll xmt */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sim_putchar(ch);
|
sim_putchar(ch);
|
||||||
|
@ -745,15 +803,15 @@ static int32 sio0dCore(const int32 port, const int32 io, const int32 data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* printable(char* result, int32 data, const int32 isIn) {
|
static char* printable(char* result, int32 data, const int32 isIn) {
|
||||||
result[0] = 0;
|
result[0] = 0;
|
||||||
data &= 0x7f;
|
data &= 0x7f;
|
||||||
if ((0x20 <= data) && (data < 0x7f))
|
if ((0x20 <= data) && (data < 0x7f))
|
||||||
sprintf(result, isIn ? " <-\"%c\"" : " ->\"%c\"", data);
|
sprintf(result, isIn ? " <-\"%c\"" : " ->\"%c\"", data);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32 sio0d(const int32 port, const int32 io, const int32 data) {
|
int32 sio0d(const int32 port, const int32 io, const int32 data) {
|
||||||
char buffer[8];
|
char buffer[8];
|
||||||
const int32 result = sio0dCore(port, io, data);
|
const int32 result = sio0dCore(port, io, data);
|
||||||
if (io == 0) {
|
if (io == 0) {
|
||||||
sim_debug(IN_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT
|
sim_debug(IN_MSG, &sio_dev, "\tSIO_D: " ADDRESS_FORMAT
|
||||||
|
@ -799,7 +857,7 @@ int32 sio1s(const int32 port, const int32 io, const int32 data) {
|
||||||
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
|
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
|
||||||
sim_debug(IN_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT
|
sim_debug(IN_MSG, &ptp_dev, "PTP_S: " ADDRESS_FORMAT
|
||||||
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
|
" IN(0x%02x) = 0x%02x\n", PCX, port, result);
|
||||||
}
|
}
|
||||||
else if (io) {
|
else if (io) {
|
||||||
sim_debug(OUT_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT
|
sim_debug(OUT_MSG, &ptr_dev, "PTR_S: " ADDRESS_FORMAT
|
||||||
" OUT(0x%02x) = 0x%02x\n", PCX, port, data);
|
" OUT(0x%02x) = 0x%02x\n", PCX, port, data);
|
||||||
|
@ -1070,11 +1128,11 @@ static int32 fromBCD(const int32 x) {
|
||||||
out (0feh),a
|
out (0feh),a
|
||||||
ld a,<p2>
|
ld a,<p2>
|
||||||
out (0feh),a
|
out (0feh),a
|
||||||
... ; send all parameters
|
... ; send all parameters
|
||||||
in a,(0feh) ; <A> contains first byte of result
|
in a,(0feh) ; <A> contains first byte of result
|
||||||
in a,(0feh) ; <A> contains second byte of result
|
in a,(0feh) ; <A> contains second byte of result
|
||||||
...
|
...
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum simhPseudoDeviceCommands { /* do not change order or remove commands, add only at the end */
|
enum simhPseudoDeviceCommands { /* do not change order or remove commands, add only at the end */
|
||||||
|
@ -1108,10 +1166,10 @@ enum simhPseudoDeviceCommands { /* do not change order or remove commands, add o
|
||||||
SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */
|
SIMHSleepCmd, /* 27 let SIMH sleep for SIMHSleep microseconds */
|
||||||
getHostOSPathSeparatorCmd, /* 28 obtain the file path separator of the OS under which SIMH runs */
|
getHostOSPathSeparatorCmd, /* 28 obtain the file path separator of the OS under which SIMH runs */
|
||||||
getHostFilenamesCmd, /* 29 perform wildcard expansion and obtain list of file names */
|
getHostFilenamesCmd, /* 29 perform wildcard expansion and obtain list of file names */
|
||||||
readURLCmd, /* 30 read the contents of an URL */
|
readURLCmd, /* 30 read the contents of an URL */
|
||||||
getCPUClockFrequency, /* 31 get the clock frequency of the CPU */
|
getCPUClockFrequency, /* 31 get the clock frequency of the CPU */
|
||||||
setCPUClockFrequency, /* 32 set the clock frequency of the CPU */
|
setCPUClockFrequency, /* 32 set the clock frequency of the CPU */
|
||||||
kSimhPseudoDeviceCommands
|
kSimhPseudoDeviceCommands
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *cmdNames[kSimhPseudoDeviceCommands] = {
|
static char *cmdNames[kSimhPseudoDeviceCommands] = {
|
||||||
|
@ -1145,9 +1203,9 @@ static char *cmdNames[kSimhPseudoDeviceCommands] = {
|
||||||
"SIMHSleep",
|
"SIMHSleep",
|
||||||
"getHostOSPathSeparator",
|
"getHostOSPathSeparator",
|
||||||
"getHostFilenames",
|
"getHostFilenames",
|
||||||
"readURL",
|
"readURL",
|
||||||
"getCPUClockFrequency",
|
"getCPUClockFrequency",
|
||||||
"setCPUClockFrequency",
|
"setCPUClockFrequency",
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CPM_COMMAND_LINE_LENGTH 128
|
#define CPM_COMMAND_LINE_LENGTH 128
|
||||||
|
@ -1157,7 +1215,7 @@ static struct tm currentTime;
|
||||||
static int32 currentTimeValid = FALSE;
|
static int32 currentTimeValid = FALSE;
|
||||||
static char version[] = "SIMH004";
|
static char version[] = "SIMH004";
|
||||||
|
|
||||||
#define URL_MAX_LENGTH 1024
|
#define URL_MAX_LENGTH 1024
|
||||||
static uint32 urlPointer;
|
static uint32 urlPointer;
|
||||||
static char urlStore[URL_MAX_LENGTH];
|
static char urlStore[URL_MAX_LENGTH];
|
||||||
static uint8 *urlResult = NULL;
|
static uint8 *urlResult = NULL;
|
||||||
|
@ -1184,15 +1242,14 @@ static t_stat simh_dev_reset(DEVICE *dptr) {
|
||||||
lastCommand = 0;
|
lastCommand = 0;
|
||||||
lastCPMStatus = SCPE_OK;
|
lastCPMStatus = SCPE_OK;
|
||||||
timerInterrupt = FALSE;
|
timerInterrupt = FALSE;
|
||||||
urlPointer = 0;
|
urlPointer = 0;
|
||||||
getClockFrequencyPos = 0;
|
getClockFrequencyPos = 0;
|
||||||
setClockFrequencyPos = 0;
|
setClockFrequencyPos = 0;
|
||||||
if (urlResult != NULL) {
|
if (urlResult != NULL) {
|
||||||
free(urlResult);
|
free(urlResult);
|
||||||
urlResult = NULL;
|
urlResult = NULL;
|
||||||
}
|
}
|
||||||
if (simh_unit.flags & UNIT_SIMH_TIMERON)
|
simh_dev_set_timeron(NULL, 0, NULL, NULL);
|
||||||
simh_dev_set_timeron(NULL, 0, NULL, NULL);
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,42 +1259,37 @@ static void warnNoRealTimeClock(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
static t_stat simh_dev_set_timeron(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||||
if (rtc_avail) {
|
timeOfNextInterrupt = sim_os_msec() + timerDelta;
|
||||||
timeOfNextInterrupt = sim_os_msec() + timerDelta;
|
return sim_activate(&simh_unit, simh_unit.wait); /* activate unit */
|
||||||
return sim_activate(&simh_unit, simh_unit.wait); /* activate unit */
|
|
||||||
}
|
|
||||||
warnNoRealTimeClock();
|
|
||||||
return SCPE_ARG;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_stat simh_dev_set_timeroff(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
static t_stat simh_dev_set_timeroff(UNIT *uptr, int32 value, char *cptr, void *desc) {
|
||||||
timerInterrupt = FALSE;
|
timerInterrupt = FALSE;
|
||||||
if (rtc_avail)
|
|
||||||
sim_cancel(&simh_unit);
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_stat simh_svc(UNIT *uptr) {
|
static t_stat simh_svc(UNIT *uptr) {
|
||||||
uint32 now = sim_os_msec();
|
if (simh_unit.flags & UNIT_SIMH_TIMERON) {
|
||||||
if (now >= timeOfNextInterrupt) {
|
uint32 now = sim_os_msec();
|
||||||
timerInterrupt = TRUE;
|
if (now >= timeOfNextInterrupt) {
|
||||||
if (timerDelta == 0)
|
timerInterrupt = TRUE;
|
||||||
timeOfNextInterrupt = now + DEFAULT_TIMER_DELTA;
|
if (timerDelta == 0)
|
||||||
else {
|
timeOfNextInterrupt = now + DEFAULT_TIMER_DELTA;
|
||||||
uint32 newTimeOfNextInterrupt = now + timerDelta - (now - timeOfNextInterrupt) % timerDelta;
|
else {
|
||||||
if (newTimeOfNextInterrupt != timeOfNextInterrupt + timerDelta) {
|
uint32 newTimeOfNextInterrupt = now + timerDelta - (now - timeOfNextInterrupt) % timerDelta;
|
||||||
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
|
if (newTimeOfNextInterrupt != timeOfNextInterrupt + timerDelta) {
|
||||||
" Timer interrupts skipped %i. Delta %i. Expect %i. Got %i.\n",
|
sim_debug(VERBOSE_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
|
||||||
PCX, (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1,
|
" Timer interrupts skipped %i. Delta %i. Expect %i. Got %i.\n",
|
||||||
timerDelta, timeOfNextInterrupt + timerDelta - now,
|
PCX, (newTimeOfNextInterrupt - timeOfNextInterrupt) / timerDelta - 1,
|
||||||
newTimeOfNextInterrupt - now);
|
timerDelta, timeOfNextInterrupt + timerDelta - now,
|
||||||
|
newTimeOfNextInterrupt - now);
|
||||||
|
}
|
||||||
|
timeOfNextInterrupt = newTimeOfNextInterrupt;
|
||||||
}
|
}
|
||||||
timeOfNextInterrupt = newTimeOfNextInterrupt;
|
|
||||||
}
|
}
|
||||||
|
/* post condition: now < timeOfNextInterrupt */
|
||||||
}
|
}
|
||||||
/* post condition: now < timeOfNextInterrupt */
|
sim_activate(&simh_unit, simh_unit.wait); /* activate unit */
|
||||||
if (simh_unit.flags & UNIT_SIMH_TIMERON)
|
|
||||||
sim_activate(&simh_unit, simh_unit.wait); /* activate unit */
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1321,26 +1373,26 @@ static void setClockCPM3(void) {
|
||||||
static int32 simh_in(const int32 port) {
|
static int32 simh_in(const int32 port) {
|
||||||
int32 result = 0;
|
int32 result = 0;
|
||||||
switch(lastCommand) {
|
switch(lastCommand) {
|
||||||
case readURLCmd:
|
case readURLCmd:
|
||||||
if (isInReadPhase) {
|
if (isInReadPhase) {
|
||||||
if (showAvailability) {
|
if (showAvailability) {
|
||||||
if (resultPointer < resultLength)
|
if (resultPointer < resultLength)
|
||||||
result = 1;
|
result = 1;
|
||||||
else {
|
else {
|
||||||
if (urlResult != NULL)
|
if (urlResult != NULL)
|
||||||
free(urlResult);
|
free(urlResult);
|
||||||
urlResult = NULL;
|
urlResult = NULL;
|
||||||
lastCommand = 0;
|
lastCommand = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (resultPointer < resultLength)
|
else if (resultPointer < resultLength)
|
||||||
result = urlResult[resultPointer++];
|
result = urlResult[resultPointer++];
|
||||||
showAvailability = 1 - showAvailability;
|
showAvailability = 1 - showAvailability;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
lastCommand = 0;
|
lastCommand = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getHostFilenamesCmd:
|
case getHostFilenamesCmd:
|
||||||
#if UNIX_PLATFORM
|
#if UNIX_PLATFORM
|
||||||
if (globValid) {
|
if (globValid) {
|
||||||
|
@ -1481,7 +1533,7 @@ static int32 simh_in(const int32 port) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getCPUClockFrequency:
|
case getCPUClockFrequency:
|
||||||
if (getClockFrequencyPos == 0) {
|
if (getClockFrequencyPos == 0) {
|
||||||
result = getClockFrequency() & 0xff;
|
result = getClockFrequency() & 0xff;
|
||||||
getClockFrequencyPos = 1;
|
getClockFrequencyPos = 1;
|
||||||
|
@ -1491,7 +1543,7 @@ static int32 simh_in(const int32 port) {
|
||||||
getClockFrequencyPos = lastCommand = 0;
|
getClockFrequencyPos = lastCommand = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case hasBankedMemoryCmd:
|
case hasBankedMemoryCmd:
|
||||||
result = cpu_unit.flags & UNIT_CPU_BANKED ? MAXBANKS : 0;
|
result = cpu_unit.flags & UNIT_CPU_BANKED ? MAXBANKS : 0;
|
||||||
lastCommand = 0;
|
lastCommand = 0;
|
||||||
|
@ -1544,7 +1596,7 @@ void do_SIMH_sleep(void) {
|
||||||
static int32 simh_out(const int32 port, const int32 data) {
|
static int32 simh_out(const int32 port, const int32 data) {
|
||||||
time_t now;
|
time_t now;
|
||||||
switch(lastCommand) {
|
switch(lastCommand) {
|
||||||
case readURLCmd:
|
case readURLCmd:
|
||||||
if (isInReadPhase)
|
if (isInReadPhase)
|
||||||
lastCommand = 0;
|
lastCommand = 0;
|
||||||
else {
|
else {
|
||||||
|
@ -1561,9 +1613,9 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
showAvailability = 1;
|
showAvailability = 1;
|
||||||
isInReadPhase = TRUE;
|
isInReadPhase = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setClockZSDOSCmd:
|
case setClockZSDOSCmd:
|
||||||
if (setClockZSDOSPos == 0) {
|
if (setClockZSDOSPos == 0) {
|
||||||
setClockZSDOSAdr = data;
|
setClockZSDOSAdr = data;
|
||||||
|
@ -1575,7 +1627,7 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
setClockZSDOSPos = lastCommand = 0;
|
setClockZSDOSPos = lastCommand = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setClockCPM3Cmd:
|
case setClockCPM3Cmd:
|
||||||
if (setClockCPM3Pos == 0) {
|
if (setClockCPM3Pos == 0) {
|
||||||
setClockCPM3Adr = data;
|
setClockCPM3Adr = data;
|
||||||
|
@ -1587,18 +1639,18 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
setClockCPM3Pos = lastCommand = 0;
|
setClockCPM3Pos = lastCommand = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setCPUClockFrequency:
|
case setCPUClockFrequency:
|
||||||
if (setClockFrequencyPos == 0) {
|
if (setClockFrequencyPos == 0) {
|
||||||
newClockFrequency = data;
|
newClockFrequency = data;
|
||||||
setClockFrequencyPos = 1;
|
setClockFrequencyPos = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setClockFrequency((data << 8) | newClockFrequency);
|
setClockFrequency((data << 8) | newClockFrequency);
|
||||||
setClockFrequencyPos = lastCommand = 0;
|
setClockFrequencyPos = lastCommand = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setBankSelectCmd:
|
case setBankSelectCmd:
|
||||||
if (cpu_unit.flags & UNIT_CPU_BANKED)
|
if (cpu_unit.flags & UNIT_CPU_BANKED)
|
||||||
setBankSelect(data & BANKMASK);
|
setBankSelect(data & BANKMASK);
|
||||||
|
@ -1608,7 +1660,7 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
PCX, data & 3);
|
PCX, data & 3);
|
||||||
lastCommand = 0;
|
lastCommand = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setTimerDeltaCmd:
|
case setTimerDeltaCmd:
|
||||||
if (setTimerDeltaPos == 0) {
|
if (setTimerDeltaPos == 0) {
|
||||||
timerDelta = data;
|
timerDelta = data;
|
||||||
|
@ -1625,7 +1677,7 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setTimerInterruptAdrCmd:
|
case setTimerInterruptAdrCmd:
|
||||||
if (setTimerInterruptAdrPos == 0) {
|
if (setTimerInterruptAdrPos == 0) {
|
||||||
timerInterruptHandler = data;
|
timerInterruptHandler = data;
|
||||||
|
@ -1636,21 +1688,21 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
setTimerInterruptAdrPos = lastCommand = 0;
|
setTimerInterruptAdrPos = lastCommand = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* lastCommand not yet set */
|
default: /* lastCommand not yet set */
|
||||||
sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
|
sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
|
||||||
" CMD(0x%02x) <- %i (0x%02x, '%s')\n",
|
" CMD(0x%02x) <- %i (0x%02x, '%s')\n",
|
||||||
PCX, port, data, data,
|
PCX, port, data, data,
|
||||||
(0 <= data) && (data < kSimhPseudoDeviceCommands) ?
|
(0 <= data) && (data < kSimhPseudoDeviceCommands) ?
|
||||||
cmdNames[data] : "Unknown command");
|
cmdNames[data] : "Unknown command");
|
||||||
|
|
||||||
lastCommand = data;
|
lastCommand = data;
|
||||||
switch(data) {
|
switch(data) {
|
||||||
case readURLCmd:
|
case readURLCmd:
|
||||||
urlPointer = 0;
|
urlPointer = 0;
|
||||||
isInReadPhase = FALSE;
|
isInReadPhase = FALSE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getHostFilenamesCmd:
|
case getHostFilenamesCmd:
|
||||||
#if UNIX_PLATFORM
|
#if UNIX_PLATFORM
|
||||||
if (!globValid) {
|
if (!globValid) {
|
||||||
|
@ -1685,18 +1737,18 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SIMHSleepCmd:
|
case SIMHSleepCmd:
|
||||||
do_SIMH_sleep();
|
do_SIMH_sleep();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case printTimeCmd: /* print time */
|
case printTimeCmd: /* print time */
|
||||||
if (rtc_avail)
|
if (rtc_avail)
|
||||||
printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec());
|
printf("SIMH: " ADDRESS_FORMAT " Current time in milliseconds = %d." NLP, PCX, sim_os_msec());
|
||||||
else
|
else
|
||||||
warnNoRealTimeClock();
|
warnNoRealTimeClock();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case startTimerCmd: /* create a new timer on top of stack */
|
case startTimerCmd: /* create a new timer on top of stack */
|
||||||
if (rtc_avail)
|
if (rtc_avail)
|
||||||
if (markTimeSP < TIMER_STACK_LIMIT)
|
if (markTimeSP < TIMER_STACK_LIMIT)
|
||||||
|
@ -1706,7 +1758,7 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
else
|
else
|
||||||
warnNoRealTimeClock();
|
warnNoRealTimeClock();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case stopTimerCmd: /* stop timer on top of stack and show time difference */
|
case stopTimerCmd: /* stop timer on top of stack and show time difference */
|
||||||
if (rtc_avail)
|
if (rtc_avail)
|
||||||
if (markTimeSP > 0) {
|
if (markTimeSP > 0) {
|
||||||
|
@ -1718,23 +1770,23 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
else
|
else
|
||||||
warnNoRealTimeClock();
|
warnNoRealTimeClock();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case resetPTRCmd: /* reset ptr device */
|
case resetPTRCmd: /* reset ptr device */
|
||||||
ptr_reset(&ptr_dev);
|
ptr_reset(&ptr_dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */
|
case attachPTRCmd: /* attach ptr to the file with name at beginning of CP/M command line */
|
||||||
attachCPM(&ptr_unit);
|
attachCPM(&ptr_unit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case detachPTRCmd: /* detach ptr */
|
case detachPTRCmd: /* detach ptr */
|
||||||
detach_unit(&ptr_unit);
|
detach_unit(&ptr_unit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getSIMHVersionCmd:
|
case getSIMHVersionCmd:
|
||||||
versionPos = 0;
|
versionPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getClockZSDOSCmd:
|
case getClockZSDOSCmd:
|
||||||
time(&now);
|
time(&now);
|
||||||
now += ClockZSDOSDelta;
|
now += ClockZSDOSDelta;
|
||||||
|
@ -1742,11 +1794,11 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
currentTimeValid = TRUE;
|
currentTimeValid = TRUE;
|
||||||
getClockZSDOSPos = 0;
|
getClockZSDOSPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setClockZSDOSCmd:
|
case setClockZSDOSCmd:
|
||||||
setClockZSDOSPos = 0;
|
setClockZSDOSPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getClockCPM3Cmd:
|
case getClockCPM3Cmd:
|
||||||
time(&now);
|
time(&now);
|
||||||
now += ClockCPM3Delta;
|
now += ClockCPM3Delta;
|
||||||
|
@ -1755,29 +1807,29 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY);
|
daysCPM3SinceOrg = (int32) ((now - mkCPM3Origin()) / SECONDS_PER_DAY);
|
||||||
getClockCPM3Pos = 0;
|
getClockCPM3Pos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setClockCPM3Cmd:
|
case setClockCPM3Cmd:
|
||||||
setClockCPM3Pos = 0;
|
setClockCPM3Pos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getCommonCmd:
|
case getCommonCmd:
|
||||||
getCommonPos = 0;
|
getCommonPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getCPUClockFrequency:
|
case getCPUClockFrequency:
|
||||||
getClockFrequencyPos = 0;
|
getClockFrequencyPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setCPUClockFrequency:
|
case setCPUClockFrequency:
|
||||||
setClockFrequencyPos = 0;
|
setClockFrequencyPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case getBankSelectCmd:
|
case getBankSelectCmd:
|
||||||
case setBankSelectCmd:
|
case setBankSelectCmd:
|
||||||
case hasBankedMemoryCmd:
|
case hasBankedMemoryCmd:
|
||||||
case getHostOSPathSeparatorCmd:
|
case getHostOSPathSeparatorCmd:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case resetSIMHInterfaceCmd:
|
case resetSIMHInterfaceCmd:
|
||||||
markTimeSP = 0;
|
markTimeSP = 0;
|
||||||
lastCommand = 0;
|
lastCommand = 0;
|
||||||
|
@ -1795,7 +1847,7 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case showTimerCmd: /* show time difference to timer on top of stack */
|
case showTimerCmd: /* show time difference to timer on top of stack */
|
||||||
if (rtc_avail)
|
if (rtc_avail)
|
||||||
if (markTimeSP > 0) {
|
if (markTimeSP > 0) {
|
||||||
|
@ -1807,52 +1859,52 @@ static int32 simh_out(const int32 port, const int32 data) {
|
||||||
else
|
else
|
||||||
warnNoRealTimeClock();
|
warnNoRealTimeClock();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */
|
case attachPTPCmd: /* attach ptp to the file with name at beginning of CP/M command line */
|
||||||
attachCPM(&ptp_unit);
|
attachCPM(&ptp_unit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case detachPTPCmd: /* detach ptp */
|
case detachPTPCmd: /* detach ptp */
|
||||||
detach_unit(&ptp_unit);
|
detach_unit(&ptp_unit);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setZ80CPUCmd:
|
case setZ80CPUCmd:
|
||||||
chiptype = CHIP_TYPE_Z80;
|
chiptype = CHIP_TYPE_Z80;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case set8080CPUCmd:
|
case set8080CPUCmd:
|
||||||
chiptype = CHIP_TYPE_8080;
|
chiptype = CHIP_TYPE_8080;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case startTimerInterruptsCmd:
|
case startTimerInterruptsCmd:
|
||||||
if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) {
|
if (simh_dev_set_timeron(NULL, 0, NULL, NULL) == SCPE_OK) {
|
||||||
timerInterrupt = FALSE;
|
timerInterrupt = FALSE;
|
||||||
simh_unit.flags |= UNIT_SIMH_TIMERON;
|
simh_unit.flags |= UNIT_SIMH_TIMERON;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case stopTimerInterruptsCmd:
|
case stopTimerInterruptsCmd:
|
||||||
simh_unit.flags &= ~UNIT_SIMH_TIMERON;
|
simh_unit.flags &= ~UNIT_SIMH_TIMERON;
|
||||||
simh_dev_set_timeroff(NULL, 0, NULL, NULL);
|
simh_dev_set_timeroff(NULL, 0, NULL, NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setTimerDeltaCmd:
|
case setTimerDeltaCmd:
|
||||||
setTimerDeltaPos = 0;
|
setTimerDeltaPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case setTimerInterruptAdrCmd:
|
case setTimerInterruptAdrCmd:
|
||||||
setTimerInterruptAdrPos = 0;
|
setTimerInterruptAdrPos = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case resetStopWatchCmd:
|
case resetStopWatchCmd:
|
||||||
stopWatchNow = rtc_avail ? sim_os_msec() : 0;
|
stopWatchNow = rtc_avail ? sim_os_msec() : 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case readStopWatchCmd:
|
case readStopWatchCmd:
|
||||||
getStopWatchDeltaPos = 0;
|
getStopWatchDeltaPos = 0;
|
||||||
stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0;
|
stopWatchDelta = rtc_avail ? sim_os_msec() - stopWatchNow : 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
|
sim_debug(CMD_MSG, &simh_device, "SIMH: " ADDRESS_FORMAT
|
||||||
" Unknown command (%i) to SIMH pseudo device on port %03xh ignored.\n",
|
" Unknown command (%i) to SIMH pseudo device on port %03xh ignored.\n",
|
||||||
|
|
|
@ -26,11 +26,11 @@
|
||||||
Based on work by Charles E Owen (c) 1997
|
Based on work by Charles E Owen (c) 1997
|
||||||
Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited)
|
Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited)
|
||||||
|
|
||||||
03/27/14 -- MWD Add MITS Hard Disk device (mhdsk_dev)
|
03/27/14 -- MWD Add MITS Hard Disk device (mhdsk_dev)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "m68k.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "altairz80_defs.h"
|
|
||||||
|
|
||||||
#define SIM_EMAX 6
|
#define SIM_EMAX 6
|
||||||
|
|
||||||
|
@ -72,10 +72,6 @@ extern DEVICE wdi2_dev;
|
||||||
|
|
||||||
extern DEVICE scp300f_dev;
|
extern DEVICE scp300f_dev;
|
||||||
|
|
||||||
#ifdef USE_FPC
|
|
||||||
extern DEVICE fpc_dev;
|
|
||||||
#endif /* USE_FPC */
|
|
||||||
|
|
||||||
extern int32 chiptype;
|
extern int32 chiptype;
|
||||||
extern long disasm (unsigned char *data, char *output, int segsize, long offset);
|
extern long disasm (unsigned char *data, char *output, int segsize, long offset);
|
||||||
|
|
||||||
|
@ -98,7 +94,7 @@ t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char sim_name[] = "Altair 8800 (Z80)";
|
char sim_name[] = "Altair 8800 (Z80)";
|
||||||
REG *sim_PC = &cpu_reg[6];
|
REG *sim_PC = &cpu_reg[CPU_INDEX_8080];
|
||||||
int32 sim_emax = SIM_EMAX;
|
int32 sim_emax = SIM_EMAX;
|
||||||
DEVICE *sim_devices[] = {
|
DEVICE *sim_devices[] = {
|
||||||
/* AltairZ80 Devices */
|
/* AltairZ80 Devices */
|
||||||
|
@ -380,6 +376,7 @@ static void printHex4(char* string, const uint32 value) {
|
||||||
addr = current PC
|
addr = current PC
|
||||||
Outputs:
|
Outputs:
|
||||||
*S = output text
|
*S = output text
|
||||||
|
return = length of instruction in bytes
|
||||||
|
|
||||||
DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997
|
DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997
|
||||||
You are not allowed to distribute this software
|
You are not allowed to distribute this software
|
||||||
|
@ -494,7 +491,7 @@ static int32 DAsm(char *S, const uint32 *val, const int32 useZ80Mnemonics, const
|
||||||
t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) {
|
t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) {
|
||||||
char disasm_result[128];
|
char disasm_result[128];
|
||||||
int32 ch = val[0] & 0x7f;
|
int32 ch = val[0] & 0x7f;
|
||||||
long r;
|
long r = 1;
|
||||||
unsigned char vals[SIM_EMAX];
|
unsigned char vals[SIM_EMAX];
|
||||||
int32 i;
|
int32 i;
|
||||||
if (sw & (SWMASK('A') | SWMASK('C'))) {
|
if (sw & (SWMASK('A') | SWMASK('C'))) {
|
||||||
|
@ -503,13 +500,26 @@ t_stat fprint_sym(FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) {
|
||||||
}
|
}
|
||||||
if (!(sw & SWMASK('M')))
|
if (!(sw & SWMASK('M')))
|
||||||
return SCPE_ARG;
|
return SCPE_ARG;
|
||||||
if (chiptype == CHIP_TYPE_8086) {
|
switch (chiptype) {
|
||||||
for (i = 0; i < SIM_EMAX; i++)
|
case CHIP_TYPE_8080:
|
||||||
vals[i] = val[i] & 0xff;
|
r = DAsm(disasm_result, val, FALSE, addr);
|
||||||
r = disasm(vals, disasm_result, 16, addr);
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_Z80:
|
||||||
|
r = DAsm(disasm_result, val, TRUE, addr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_8086:
|
||||||
|
for (i = 0; i < SIM_EMAX; i++)
|
||||||
|
vals[i] = val[i] & 0xff;
|
||||||
|
r = disasm(vals, disasm_result, 16, addr);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CHIP_TYPE_M68K:
|
||||||
|
r = m68k_disassemble(disasm_result, addr, M68K_CPU_TYPE_68000);
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
r = DAsm(disasm_result, val, chiptype == CHIP_TYPE_Z80, addr);
|
|
||||||
fprintf(of, "%s", disasm_result);
|
fprintf(of, "%s", disasm_result);
|
||||||
return 1 - r;
|
return 1 - r;
|
||||||
}
|
}
|
||||||
|
@ -700,7 +710,7 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co
|
||||||
return -3; /* three additional bytes returned */
|
return -3; /* three additional bytes returned */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return -1; /* one additional byte returned */
|
return -1; /* one additional byte returned */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,7 +741,7 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co
|
||||||
return -2; /* two additional bytes returned */
|
return -2; /* two additional bytes returned */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return -1; /* one additional byte returned */
|
return -1; /* one additional byte returned */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,14 +779,19 @@ static int32 parse_X80(const char *cptr, const int32 addr, uint32 *val, char *co
|
||||||
status = error status
|
status = error status
|
||||||
*/
|
*/
|
||||||
t_stat parse_sym(char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) {
|
t_stat parse_sym(char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) {
|
||||||
static t_bool symbolicInputNotImplementedMessage = FALSE;
|
static t_bool symbolicInputNotImplementedMessage8086 = FALSE;
|
||||||
#define NO_SYMBOLIC_INPUT_MESSAGE "Symbolic input is not supported for the 8086.\n"
|
static t_bool symbolicInputNotImplementedMessageM68K = FALSE;
|
||||||
if (chiptype == CHIP_TYPE_8086) {
|
if ((sw & (SWMASK('M'))) && (chiptype == CHIP_TYPE_8086)) {
|
||||||
if (!symbolicInputNotImplementedMessage) {
|
if (!symbolicInputNotImplementedMessage8086) {
|
||||||
printf(NO_SYMBOLIC_INPUT_MESSAGE);
|
sim_printf("Symbolic input is not supported for the 8086.\n");
|
||||||
if (sim_log)
|
symbolicInputNotImplementedMessage8086 = TRUE;
|
||||||
fprintf(sim_log, NO_SYMBOLIC_INPUT_MESSAGE);
|
}
|
||||||
symbolicInputNotImplementedMessage = TRUE;
|
return SCPE_NOFNC;
|
||||||
|
}
|
||||||
|
if ((sw & (SWMASK('M'))) && (chiptype == CHIP_TYPE_M68K)) {
|
||||||
|
if (!symbolicInputNotImplementedMessageM68K) {
|
||||||
|
sim_printf("Symbolic input is not supported for the M68K.\n");
|
||||||
|
symbolicInputNotImplementedMessageM68K = TRUE;
|
||||||
}
|
}
|
||||||
return SCPE_NOFNC;
|
return SCPE_NOFNC;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,15 @@ static UNIT fw2_unit[] = {
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) }
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, FW2_CAPACITY) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FWII_NAME "Vector Graphic Flashwriter 2 FWII"
|
||||||
|
|
||||||
static MTAB fw2_mod[] = {
|
static MTAB fw2_mod[] = {
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_FW2_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_FW2_VERBOSE, 0, "QUIET", "QUIET", NULL, NULL, NULL,
|
||||||
|
"No verbose messages for unit " FWII_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_FW2_VERBOSE, UNIT_FW2_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_FW2_VERBOSE, UNIT_FW2_VERBOSE, "VERBOSE", "VERBOSE", NULL, NULL, NULL,
|
||||||
|
"Verbose messages for unit " FWII_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,7 +106,7 @@ DEVICE fw2_dev = {
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
NULL, &fw2_attach, &fw2_detach,
|
NULL, &fw2_attach, &fw2_detach,
|
||||||
NULL, (DEV_DISABLE | DEV_DIS), 0,
|
NULL, (DEV_DISABLE | DEV_DIS), 0,
|
||||||
NULL, NULL, "Vector Graphic Flashwriter 2 FWII"
|
NULL, NULL, FWII_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Attach routine */
|
/* Attach routine */
|
||||||
|
|
|
@ -143,8 +143,6 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ
|
||||||
extern void PutByteDMA(const uint32 Addr, const uint32 Value);
|
extern void PutByteDMA(const uint32 Addr, const uint32 Value);
|
||||||
extern uint8 GetByteDMA(const uint32 Addr);
|
extern uint8 GetByteDMA(const uint32 Addr);
|
||||||
|
|
||||||
#define UNIT_V_I8272_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_I8272_WLK (1 << UNIT_V_I8272_WLK)
|
|
||||||
#define UNIT_V_I8272_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_I8272_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
#define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE)
|
#define UNIT_I8272_VERBOSE (1 << UNIT_V_I8272_VERBOSE)
|
||||||
#define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
#define I8272_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
||||||
|
@ -191,29 +189,32 @@ static UNIT i8272_unit[] = {
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) }
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, I8272_CAPACITY) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define I8272_NAME "Intel/NEC(765) FDC Core I8272"
|
||||||
|
|
||||||
static MTAB i8272_mod[] = {
|
static MTAB i8272_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_I8272_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_I8272_WLK, UNIT_I8272_WLK, "WRTLCK", "WRTLCK", NULL },
|
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_I8272_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_I8272_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " I8272_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_I8272_VERBOSE, UNIT_I8272_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_I8272_VERBOSE, UNIT_I8272_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " I8272_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB i8272_dt[] = {
|
static DEBTAB i8272_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "FMT", FMT_MSG },
|
{ "FMT", FMT_MSG, "Format messages" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "IRQ", IRQ_MSG },
|
{ "IRQ", IRQ_MSG, "IRQ messages" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE i8272_dev = {
|
DEVICE i8272_dev = {
|
||||||
|
@ -222,7 +223,7 @@ DEVICE i8272_dev = {
|
||||||
NULL, NULL, &i8272_reset,
|
NULL, NULL, &i8272_reset,
|
||||||
NULL, &i8272_attach, &i8272_detach,
|
NULL, &i8272_attach, &i8272_detach,
|
||||||
&i8272_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&i8272_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
||||||
i8272_dt, NULL, "Intel/NEC(765) FDC Core I8272"
|
i8272_dt, NULL, I8272_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint8 I8272_Setup_Cmd(uint8 fdc_cmd);
|
static uint8 I8272_Setup_Cmd(uint8 fdc_cmd);
|
||||||
|
|
339
AltairZ80/m68k.h
Executable file
339
AltairZ80/m68k.h
Executable file
|
@ -0,0 +1,339 @@
|
||||||
|
#ifndef M68K__HEADER
|
||||||
|
#define M68K__HEADER
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ========================= LICENSING & COPYRIGHT ======================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
/*
|
||||||
|
* MUSASHI
|
||||||
|
* Version 3.3
|
||||||
|
*
|
||||||
|
* A portable Motorola M680x0 processor emulation engine.
|
||||||
|
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code may be freely used for non-commercial purposes as long as this
|
||||||
|
* copyright notice remains unaltered in the source code and any binary files
|
||||||
|
* containing this code in compiled form.
|
||||||
|
*
|
||||||
|
* All other lisencing terms must be negotiated with the author
|
||||||
|
* (Karl Stenerud).
|
||||||
|
*
|
||||||
|
* The latest version of this code can be obtained at:
|
||||||
|
* http://kstenerud.cjb.net
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================ GENERAL DEFINES =========================== */
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* There are 7 levels of interrupt to the 68K.
|
||||||
|
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
|
||||||
|
*/
|
||||||
|
#define M68K_IRQ_NONE 0
|
||||||
|
#define M68K_IRQ_1 1
|
||||||
|
#define M68K_IRQ_2 2
|
||||||
|
#define M68K_IRQ_3 3
|
||||||
|
#define M68K_IRQ_4 4
|
||||||
|
#define M68K_IRQ_5 5
|
||||||
|
#define M68K_IRQ_6 6
|
||||||
|
#define M68K_IRQ_7 7
|
||||||
|
|
||||||
|
|
||||||
|
/* Special interrupt acknowledge values.
|
||||||
|
* Use these as special returns from the interrupt acknowledge callback
|
||||||
|
* (specified later in this header).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Causes an interrupt autovector (0x18 + interrupt level) to be taken.
|
||||||
|
* This happens in a real 68K if VPA or AVEC is asserted during an interrupt
|
||||||
|
* acknowledge cycle instead of DTACK.
|
||||||
|
*/
|
||||||
|
#define M68K_INT_ACK_AUTOVECTOR 0xffffffff
|
||||||
|
|
||||||
|
/* Causes the spurious interrupt vector (0x18) to be taken
|
||||||
|
* This happens in a real 68K if BERR is asserted during the interrupt
|
||||||
|
* acknowledge cycle (i.e. no devices responded to the acknowledge).
|
||||||
|
*/
|
||||||
|
#define M68K_INT_ACK_SPURIOUS 0xfffffffe
|
||||||
|
|
||||||
|
|
||||||
|
/* CPU types for use in m68k_set_cpu_type() */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
M68K_CPU_TYPE_INVALID,
|
||||||
|
M68K_CPU_TYPE_68000,
|
||||||
|
M68K_CPU_TYPE_68010,
|
||||||
|
M68K_CPU_TYPE_68EC020,
|
||||||
|
M68K_CPU_TYPE_68020,
|
||||||
|
M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */
|
||||||
|
M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Registers used by m68k_get_reg() and m68k_set_reg() */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/* Real registers */
|
||||||
|
M68K_REG_D0, /* Data registers */
|
||||||
|
M68K_REG_D1,
|
||||||
|
M68K_REG_D2,
|
||||||
|
M68K_REG_D3,
|
||||||
|
M68K_REG_D4,
|
||||||
|
M68K_REG_D5,
|
||||||
|
M68K_REG_D6,
|
||||||
|
M68K_REG_D7,
|
||||||
|
M68K_REG_A0, /* Address registers */
|
||||||
|
M68K_REG_A1,
|
||||||
|
M68K_REG_A2,
|
||||||
|
M68K_REG_A3,
|
||||||
|
M68K_REG_A4,
|
||||||
|
M68K_REG_A5,
|
||||||
|
M68K_REG_A6,
|
||||||
|
M68K_REG_A7,
|
||||||
|
M68K_REG_PC, /* Program Counter */
|
||||||
|
M68K_REG_SR, /* Status Register */
|
||||||
|
M68K_REG_SP, /* The current Stack Pointer (located in A7) */
|
||||||
|
M68K_REG_USP, /* User Stack Pointer */
|
||||||
|
M68K_REG_ISP, /* Interrupt Stack Pointer */
|
||||||
|
M68K_REG_MSP, /* Master Stack Pointer */
|
||||||
|
M68K_REG_SFC, /* Source Function Code */
|
||||||
|
M68K_REG_DFC, /* Destination Function Code */
|
||||||
|
M68K_REG_VBR, /* Vector Base Register */
|
||||||
|
M68K_REG_CACR, /* Cache Control Register */
|
||||||
|
M68K_REG_CAAR, /* Cache Address Register */
|
||||||
|
|
||||||
|
/* Assumed registers */
|
||||||
|
/* These are cheat registers which emulate the 1-longword prefetch
|
||||||
|
* present in the 68000 and 68010.
|
||||||
|
*/
|
||||||
|
M68K_REG_PREF_ADDR, /* Last prefetch address */
|
||||||
|
M68K_REG_PREF_DATA, /* Last prefetch data */
|
||||||
|
|
||||||
|
/* Convenience registers */
|
||||||
|
M68K_REG_PPC, /* Previous value in the program counter */
|
||||||
|
M68K_REG_IR, /* Instruction register */
|
||||||
|
M68K_REG_CPU_TYPE /* Type of CPU being run */
|
||||||
|
} m68k_register_t;
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* You will have to implement these functions */
|
||||||
|
|
||||||
|
/* read/write functions called by the CPU to access memory.
|
||||||
|
* while values used are 32 bits, only the appropriate number
|
||||||
|
* of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
|
||||||
|
* of value should be written to memory).
|
||||||
|
*
|
||||||
|
* NOTE: I have separated the immediate and PC-relative memory fetches
|
||||||
|
* from the other memory fetches because some systems require
|
||||||
|
* differentiation between PROGRAM and DATA fetches (usually
|
||||||
|
* for security setups such as encryption).
|
||||||
|
* This separation can either be achieved by setting
|
||||||
|
* M68K_SEPARATE_READS in m68kconf.h and defining
|
||||||
|
* the read functions, or by setting M68K_EMULATE_FC and
|
||||||
|
* making a function code callback function.
|
||||||
|
* Using the callback offers better emulation coverage
|
||||||
|
* because you can also monitor whether the CPU is in SYSTEM or
|
||||||
|
* USER mode, but it is also slower.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Read from anywhere */
|
||||||
|
unsigned int m68k_read_memory_8(unsigned int address);
|
||||||
|
unsigned int m68k_read_memory_16(unsigned int address);
|
||||||
|
unsigned int m68k_read_memory_32(unsigned int address);
|
||||||
|
|
||||||
|
/* Read data immediately following the PC */
|
||||||
|
unsigned int m68k_read_immediate_16(unsigned int address);
|
||||||
|
unsigned int m68k_read_immediate_32(unsigned int address);
|
||||||
|
|
||||||
|
/* Read data relative to the PC */
|
||||||
|
unsigned int m68k_read_pcrelative_8(unsigned int address);
|
||||||
|
unsigned int m68k_read_pcrelative_16(unsigned int address);
|
||||||
|
unsigned int m68k_read_pcrelative_32(unsigned int address);
|
||||||
|
|
||||||
|
/* Memory access for the disassembler */
|
||||||
|
unsigned int m68k_read_disassembler_8 (unsigned int address);
|
||||||
|
unsigned int m68k_read_disassembler_16 (unsigned int address);
|
||||||
|
unsigned int m68k_read_disassembler_32 (unsigned int address);
|
||||||
|
|
||||||
|
/* Write to anywhere */
|
||||||
|
void m68k_write_memory_8(unsigned int address, unsigned int value);
|
||||||
|
void m68k_write_memory_16(unsigned int address, unsigned int value);
|
||||||
|
void m68k_write_memory_32(unsigned int address, unsigned int value);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================== CALLBACKS =============================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* These functions allow you to set callbacks to the host when specific events
|
||||||
|
* occur. Note that you must enable the corresponding value in m68kconf.h
|
||||||
|
* in order for these to do anything useful.
|
||||||
|
* Note: I have defined default callbacks which are used if you have enabled
|
||||||
|
* the corresponding #define in m68kconf.h but either haven't assigned a
|
||||||
|
* callback or have assigned a callback of NULL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Set the callback for an interrupt acknowledge.
|
||||||
|
* You must enable M68K_EMULATE_INT_ACK in m68kconf.h.
|
||||||
|
* The CPU will call the callback with the interrupt level being acknowledged.
|
||||||
|
* The host program must return either a vector from 0x02-0xff, or one of the
|
||||||
|
* special interrupt acknowledge values specified earlier in this header.
|
||||||
|
* If this is not implemented, the CPU will always assume an autovectored
|
||||||
|
* interrupt, and will automatically clear the interrupt request when it
|
||||||
|
* services the interrupt.
|
||||||
|
* Default behavior: return M68K_INT_ACK_AUTOVECTOR.
|
||||||
|
*/
|
||||||
|
void m68k_set_int_ack_callback(int (*callback)(int int_level));
|
||||||
|
|
||||||
|
|
||||||
|
/* Set the callback for a breakpoint acknowledge (68010+).
|
||||||
|
* You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h.
|
||||||
|
* The CPU will call the callback with whatever was in the data field of the
|
||||||
|
* BKPT instruction for 68020+, or 0 for 68010.
|
||||||
|
* Default behavior: do nothing.
|
||||||
|
*/
|
||||||
|
void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data));
|
||||||
|
|
||||||
|
|
||||||
|
/* Set the callback for the RESET instruction.
|
||||||
|
* You must enable M68K_EMULATE_RESET in m68kconf.h.
|
||||||
|
* The CPU calls this callback every time it encounters a RESET instruction.
|
||||||
|
* Default behavior: do nothing.
|
||||||
|
*/
|
||||||
|
void m68k_set_reset_instr_callback(void (*callback)(void));
|
||||||
|
|
||||||
|
|
||||||
|
/* Set the callback for informing of a large PC change.
|
||||||
|
* You must enable M68K_MONITOR_PC in m68kconf.h.
|
||||||
|
* The CPU calls this callback with the new PC value every time the PC changes
|
||||||
|
* by a large value (currently set for changes by longwords).
|
||||||
|
* Default behavior: do nothing.
|
||||||
|
*/
|
||||||
|
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc));
|
||||||
|
|
||||||
|
|
||||||
|
/* Set the callback for CPU function code changes.
|
||||||
|
* You must enable M68K_EMULATE_FC in m68kconf.h.
|
||||||
|
* The CPU calls this callback with the function code before every memory
|
||||||
|
* access to set the CPU's function code according to what kind of memory
|
||||||
|
* access it is (supervisor/user, program/data and such).
|
||||||
|
* Default behavior: do nothing.
|
||||||
|
*/
|
||||||
|
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc));
|
||||||
|
|
||||||
|
|
||||||
|
/* Set a callback for the instruction cycle of the CPU.
|
||||||
|
* You must enable M68K_INSTRUCTION_HOOK in m68kconf.h.
|
||||||
|
* The CPU calls this callback just before fetching the opcode in the
|
||||||
|
* instruction cycle.
|
||||||
|
* Default behavior: do nothing.
|
||||||
|
*/
|
||||||
|
void m68k_set_instr_hook_callback(void (*callback)(void));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* Use this function to set the CPU type you want to emulate.
|
||||||
|
* Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68010,
|
||||||
|
* M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020.
|
||||||
|
*/
|
||||||
|
void m68k_set_cpu_type(unsigned int cpu_type);
|
||||||
|
|
||||||
|
/* Pulse the RESET pin on the CPU.
|
||||||
|
* You *MUST* reset the CPU at least once to initialize the emulation
|
||||||
|
* Note: If you didn't call m68k_set_cpu_type() before resetting
|
||||||
|
* the CPU for the first time, the CPU will be set to
|
||||||
|
* M68K_CPU_TYPE_68000.
|
||||||
|
*/
|
||||||
|
void m68k_pulse_reset(void);
|
||||||
|
|
||||||
|
/* execute num_cycles worth of instructions. returns number of cycles used */
|
||||||
|
int m68k_execute(int num_cycles);
|
||||||
|
|
||||||
|
/* These functions let you read/write/modify the number of cycles left to run
|
||||||
|
* while m68k_execute() is running.
|
||||||
|
* These are useful if the 68k accesses a memory-mapped port on another device
|
||||||
|
* that requires immediate processing by another CPU.
|
||||||
|
*/
|
||||||
|
int m68k_cycles_run(void); /* Number of cycles run so far */
|
||||||
|
int m68k_cycles_remaining(void); /* Number of cycles left */
|
||||||
|
void m68k_modify_timeslice(int cycles); /* Modify cycles left */
|
||||||
|
void m68k_end_timeslice(void); /* End timeslice now */
|
||||||
|
|
||||||
|
/* Set the IPL0-IPL2 pins on the CPU (IRQ).
|
||||||
|
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
|
||||||
|
* Setting IRQ to 0 will clear an interrupt request.
|
||||||
|
*/
|
||||||
|
void m68k_set_irq(unsigned int int_level);
|
||||||
|
|
||||||
|
|
||||||
|
/* Halt the CPU as if you pulsed the HALT pin. */
|
||||||
|
void m68k_pulse_halt(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* Context switching to allow multiple CPUs */
|
||||||
|
|
||||||
|
/* Get the size of the cpu context in bytes */
|
||||||
|
unsigned int m68k_context_size(void);
|
||||||
|
|
||||||
|
/* Get a cpu context */
|
||||||
|
unsigned int m68k_get_context(void* dst);
|
||||||
|
|
||||||
|
/* set the current cpu context */
|
||||||
|
void m68k_set_context(void* dst);
|
||||||
|
|
||||||
|
/* Save the current cpu context to disk.
|
||||||
|
* You must provide a function pointer of the form:
|
||||||
|
* void save_value(char* identifier, unsigned int value)
|
||||||
|
*/
|
||||||
|
void m68k_save_context( void (*save_value)(char* identifier, unsigned int value));
|
||||||
|
|
||||||
|
/* Load a cpu context from disk.
|
||||||
|
* You must provide a function pointer of the form:
|
||||||
|
* unsigned int load_value(char* identifier)
|
||||||
|
*/
|
||||||
|
void m68k_load_context(unsigned int (*load_value)(char* identifier));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Peek at the internals of a CPU context. This can either be a context
|
||||||
|
* retrieved using m68k_get_context() or the currently running context.
|
||||||
|
* If context is NULL, the currently running CPU context will be used.
|
||||||
|
*/
|
||||||
|
unsigned int m68k_get_reg(void* context, m68k_register_t reg);
|
||||||
|
|
||||||
|
/* Poke values into the internals of the currently running CPU context */
|
||||||
|
void m68k_set_reg(m68k_register_t reg, unsigned int value);
|
||||||
|
|
||||||
|
/* Check if an instruction is valid for the specified CPU type */
|
||||||
|
unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type);
|
||||||
|
|
||||||
|
/* Disassemble 1 instruction using the epecified CPU type at pc. Stores
|
||||||
|
* disassembly in str_buff and returns the size of the instruction in bytes.
|
||||||
|
*/
|
||||||
|
unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type);
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================= CONFIGURATION ============================ */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* Import the configuration for this build */
|
||||||
|
#include "m68kconf.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================== END OF FILE ============================= */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
#endif /* M68K__HEADER */
|
193
AltairZ80/m68kconf.h
Normal file
193
AltairZ80/m68kconf.h
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ========================= LICENSING & COPYRIGHT ======================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
/*
|
||||||
|
* MUSASHI
|
||||||
|
* Version 3.3
|
||||||
|
*
|
||||||
|
* A portable Motorola M680x0 processor emulation engine.
|
||||||
|
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code may be freely used for non-commercial purposes as long as this
|
||||||
|
* copyright notice remains unaltered in the source code and any binary files
|
||||||
|
* containing this code in compiled form.
|
||||||
|
*
|
||||||
|
* All other lisencing terms must be negotiated with the author
|
||||||
|
* (Karl Stenerud).
|
||||||
|
*
|
||||||
|
* The latest version of this code can be obtained at:
|
||||||
|
* http://kstenerud.cjb.net
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef M68KCONF__HEADER
|
||||||
|
#define M68KCONF__HEADER
|
||||||
|
|
||||||
|
|
||||||
|
/* Configuration switches.
|
||||||
|
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
|
||||||
|
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
|
||||||
|
* or macro you specify, rather than using callback functions whose pointer
|
||||||
|
* must be passed in using m68k_set_xxx_callback().
|
||||||
|
*/
|
||||||
|
#define OPT_OFF 0
|
||||||
|
#define OPT_ON 1
|
||||||
|
#define OPT_SPECIFY_HANDLER 2
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================== MAME STUFF ============================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
|
||||||
|
* to OPT_ON and use m68kmame.h to configure the 68k core.
|
||||||
|
*/
|
||||||
|
#ifndef M68K_COMPILE_FOR_MAME
|
||||||
|
#define M68K_COMPILE_FOR_MAME OPT_OFF
|
||||||
|
#endif /* M68K_COMPILE_FOR_MAME */
|
||||||
|
|
||||||
|
#if M68K_COMPILE_FOR_MAME == OPT_ON
|
||||||
|
#include "m68kmame.h"
|
||||||
|
#else
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================= CONFIGURATION ============================ */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* Turn on if you want to use the following M68K variants */
|
||||||
|
#define M68K_EMULATE_010 OPT_OFF
|
||||||
|
#define M68K_EMULATE_EC020 OPT_OFF
|
||||||
|
#define M68K_EMULATE_020 OPT_OFF
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, the CPU will call m68k_read_immediate_xx() for immediate addressing
|
||||||
|
* and m68k_read_pcrelative_xx() for PC-relative addressing.
|
||||||
|
* If off, all read requests from the CPU will be redirected to m68k_read_xx()
|
||||||
|
*/
|
||||||
|
#define M68K_SEPARATE_READS OPT_OFF
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, CPU will call the interrupt acknowledge callback when it services an
|
||||||
|
* interrupt.
|
||||||
|
* If off, all interrupts will be autovectored and all interrupt requests will
|
||||||
|
* auto-clear when the interrupt is serviced.
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
|
||||||
|
#define M68K_INT_ACK_CALLBACK(A) m68k_cpu_irq_ack(A)
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, CPU will call the breakpoint acknowledge callback when it encounters
|
||||||
|
* a breakpoint instruction and it is running a 68010+.
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_BKPT_ACK OPT_OFF
|
||||||
|
#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, the CPU will monitor the trace flags and take trace exceptions
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_TRACE OPT_OFF
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, CPU will call the output reset callback when it encounters a reset
|
||||||
|
* instruction.
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_RESET OPT_SPECIFY_HANDLER
|
||||||
|
#define M68K_RESET_CALLBACK() m68k_cpu_pulse_reset()
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, CPU will call the set fc callback on every memory access to
|
||||||
|
* differentiate between user/supervisor, program/data access like a real
|
||||||
|
* 68000 would. This should be enabled and the callback should be set if you
|
||||||
|
* want to properly emulate the m68010 or higher. (moves uses function codes
|
||||||
|
* to read/write data from different address spaces)
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_FC OPT_SPECIFY_HANDLER
|
||||||
|
#define M68K_SET_FC_CALLBACK(A) m68k_cpu_set_fc(A)
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, CPU will call the pc changed callback when it changes the PC by a
|
||||||
|
* large value. This allows host programs to be nicer when it comes to
|
||||||
|
* fetching immediate data and instructions on a banked memory system.
|
||||||
|
*/
|
||||||
|
#define M68K_MONITOR_PC OPT_OFF
|
||||||
|
#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, CPU will call the instruction hook callback before every
|
||||||
|
* instruction.
|
||||||
|
*/
|
||||||
|
#define M68K_INSTRUCTION_HOOK OPT_OFF
|
||||||
|
#define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function()
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
|
||||||
|
#define M68K_EMULATE_PREFETCH OPT_ON
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, the CPU will generate address error exceptions if it tries to
|
||||||
|
* access a word or longword at an odd address.
|
||||||
|
* NOTE: Do not enable this! It is not working!
|
||||||
|
*/
|
||||||
|
#define M68K_EMULATE_ADDRESS_ERROR OPT_OFF
|
||||||
|
|
||||||
|
|
||||||
|
/* Turn on to enable logging of illegal instruction calls.
|
||||||
|
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
|
||||||
|
* Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
|
||||||
|
*/
|
||||||
|
#define M68K_LOG_ENABLE OPT_OFF
|
||||||
|
#define M68K_LOG_1010_1111 OPT_OFF
|
||||||
|
#define M68K_LOG_FILEHANDLE some_file_handle
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------- COMPATIBILITY ---------------------------- */
|
||||||
|
|
||||||
|
/* The following options set optimizations that violate the current ANSI
|
||||||
|
* standard, but will be compliant under the forthcoming C9X standard.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* If on, the emulation core will use 64-bit integers to speed up some
|
||||||
|
* operations.
|
||||||
|
*/
|
||||||
|
#define M68K_USE_64_BIT OPT_ON
|
||||||
|
|
||||||
|
|
||||||
|
/* Set to your compiler's static inline keyword to enable it, or
|
||||||
|
* set it to blank to disable it.
|
||||||
|
* If you define INLINE in the makefile, it will override this value.
|
||||||
|
* NOTE: not enabling inline functions will SEVERELY slow down emulation.
|
||||||
|
*/
|
||||||
|
#ifndef INLINE
|
||||||
|
#define INLINE static __inline
|
||||||
|
#endif /* INLINE */
|
||||||
|
|
||||||
|
|
||||||
|
/* If your environment requires special prefixes for system callback functions
|
||||||
|
* such as the argument to qsort(), then set them here or in the makefile.
|
||||||
|
*/
|
||||||
|
#ifndef DECL_SPEC
|
||||||
|
#define DECL_SPEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* M68K_COMPILE_FOR_MAME */
|
||||||
|
|
||||||
|
#include "m68ksim.h"
|
||||||
|
|
||||||
|
#define m68k_read_memory_8(A) m68k_cpu_read_byte(A)
|
||||||
|
#define m68k_read_memory_16(A) m68k_cpu_read_word(A)
|
||||||
|
#define m68k_read_memory_32(A) m68k_cpu_read_long(A)
|
||||||
|
|
||||||
|
#define m68k_write_memory_8(A, V) m68k_cpu_write_byte(A, V)
|
||||||
|
#define m68k_write_memory_16(A, V) m68k_cpu_write_word(A, V)
|
||||||
|
#define m68k_write_memory_32(A, V) m68k_cpu_write_long(A, V)
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================== END OF FILE ============================= */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
#endif /* M68KCONF__HEADER */
|
894
AltairZ80/m68kcpu.c
Executable file
894
AltairZ80/m68kcpu.c
Executable file
|
@ -0,0 +1,894 @@
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ========================= LICENSING & COPYRIGHT ======================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static const char* copyright_notice =
|
||||||
|
"MUSASHI\n"
|
||||||
|
"Version 3.3 (2001-01-29)\n"
|
||||||
|
"A portable Motorola M680x0 processor emulation engine.\n"
|
||||||
|
"Copyright 1998-2001 Karl Stenerud. All rights reserved.\n"
|
||||||
|
"\n"
|
||||||
|
"This code may be freely used for non-commercial purpooses as long as this\n"
|
||||||
|
"copyright notice remains unaltered in the source code and any binary files\n"
|
||||||
|
"containing this code in compiled form.\n"
|
||||||
|
"\n"
|
||||||
|
"All other lisencing terms must be negotiated with the author\n"
|
||||||
|
"(Karl Stenerud).\n"
|
||||||
|
"\n"
|
||||||
|
"The latest version of this code can be obtained at:\n"
|
||||||
|
"http://kstenerud.cjb.net\n"
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ================================= NOTES ================================ */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ================================ INCLUDES ============================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
#include "m68kops.h"
|
||||||
|
#include "m68kcpu.h"
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ================================= DATA ================================= */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
int m68ki_initial_cycles;
|
||||||
|
int m68ki_remaining_cycles = 0; /* Number of clocks remaining */
|
||||||
|
uint m68ki_tracing = 0;
|
||||||
|
uint m68ki_address_space;
|
||||||
|
|
||||||
|
#ifdef M68K_LOG_ENABLE
|
||||||
|
char* m68ki_cpu_names[9] =
|
||||||
|
{
|
||||||
|
"Invalid CPU",
|
||||||
|
"M68000",
|
||||||
|
"M68010",
|
||||||
|
"Invalid CPU",
|
||||||
|
"M68EC020"
|
||||||
|
"Invalid CPU",
|
||||||
|
"Invalid CPU",
|
||||||
|
"Invalid CPU",
|
||||||
|
"M68020"
|
||||||
|
};
|
||||||
|
#endif /* M68K_LOG_ENABLE */
|
||||||
|
|
||||||
|
/* The CPU core */
|
||||||
|
m68ki_cpu_core m68ki_cpu = {0};
|
||||||
|
|
||||||
|
#if M68K_EMULATE_ADDRESS_ERROR
|
||||||
|
jmp_buf m68ki_address_error_trap;
|
||||||
|
#endif /* M68K_EMULATE_ADDRESS_ERROR */
|
||||||
|
|
||||||
|
/* Used by shift & rotate instructions */
|
||||||
|
uint8 m68ki_shift_8_table[65] =
|
||||||
|
{
|
||||||
|
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0xff
|
||||||
|
};
|
||||||
|
uint16 m68ki_shift_16_table[65] =
|
||||||
|
{
|
||||||
|
0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
|
||||||
|
0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||||
|
0xffff, 0xffff
|
||||||
|
};
|
||||||
|
uint m68ki_shift_32_table[65] =
|
||||||
|
{
|
||||||
|
0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
|
||||||
|
0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
|
||||||
|
0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
|
||||||
|
0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
|
||||||
|
0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
|
||||||
|
0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||||
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||||
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||||
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||||
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||||
|
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Number of clock cycles to use for exception processing.
|
||||||
|
* I used 4 for any vectors that are undocumented for processing times.
|
||||||
|
*/
|
||||||
|
uint8 m68ki_exception_cycle_table[3][256] =
|
||||||
|
{
|
||||||
|
{ /* 000 */
|
||||||
|
4, /* 0: Reset - Initial Stack Pointer */
|
||||||
|
4, /* 1: Reset - Initial Program Counter */
|
||||||
|
50, /* 2: Bus Error (unemulated) */
|
||||||
|
50, /* 3: Address Error (unemulated) */
|
||||||
|
34, /* 4: Illegal Instruction */
|
||||||
|
38, /* 5: Divide by Zero -- ASG: changed from 42 */
|
||||||
|
40, /* 6: CHK -- ASG: chanaged from 44 */
|
||||||
|
34, /* 7: TRAPV */
|
||||||
|
34, /* 8: Privilege Violation */
|
||||||
|
34, /* 9: Trace */
|
||||||
|
4, /* 10: 1010 */
|
||||||
|
4, /* 11: 1111 */
|
||||||
|
4, /* 12: RESERVED */
|
||||||
|
4, /* 13: Coprocessor Protocol Violation (unemulated) */
|
||||||
|
4, /* 14: Format Error */
|
||||||
|
44, /* 15: Uninitialized Interrupt */
|
||||||
|
4, /* 16: RESERVED */
|
||||||
|
4, /* 17: RESERVED */
|
||||||
|
4, /* 18: RESERVED */
|
||||||
|
4, /* 19: RESERVED */
|
||||||
|
4, /* 20: RESERVED */
|
||||||
|
4, /* 21: RESERVED */
|
||||||
|
4, /* 22: RESERVED */
|
||||||
|
4, /* 23: RESERVED */
|
||||||
|
44, /* 24: Spurious Interrupt */
|
||||||
|
44, /* 25: Level 1 Interrupt Autovector */
|
||||||
|
44, /* 26: Level 2 Interrupt Autovector */
|
||||||
|
44, /* 27: Level 3 Interrupt Autovector */
|
||||||
|
44, /* 28: Level 4 Interrupt Autovector */
|
||||||
|
44, /* 29: Level 5 Interrupt Autovector */
|
||||||
|
44, /* 30: Level 6 Interrupt Autovector */
|
||||||
|
44, /* 31: Level 7 Interrupt Autovector */
|
||||||
|
34, /* 32: TRAP #0 -- ASG: chanaged from 38 */
|
||||||
|
34, /* 33: TRAP #1 */
|
||||||
|
34, /* 34: TRAP #2 */
|
||||||
|
34, /* 35: TRAP #3 */
|
||||||
|
34, /* 36: TRAP #4 */
|
||||||
|
34, /* 37: TRAP #5 */
|
||||||
|
34, /* 38: TRAP #6 */
|
||||||
|
34, /* 39: TRAP #7 */
|
||||||
|
34, /* 40: TRAP #8 */
|
||||||
|
34, /* 41: TRAP #9 */
|
||||||
|
34, /* 42: TRAP #10 */
|
||||||
|
34, /* 43: TRAP #11 */
|
||||||
|
34, /* 44: TRAP #12 */
|
||||||
|
34, /* 45: TRAP #13 */
|
||||||
|
34, /* 46: TRAP #14 */
|
||||||
|
34, /* 47: TRAP #15 */
|
||||||
|
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
|
||||||
|
4, /* 49: FP Inexact Result (unemulated) */
|
||||||
|
4, /* 50: FP Divide by Zero (unemulated) */
|
||||||
|
4, /* 51: FP Underflow (unemulated) */
|
||||||
|
4, /* 52: FP Operand Error (unemulated) */
|
||||||
|
4, /* 53: FP Overflow (unemulated) */
|
||||||
|
4, /* 54: FP Signaling NAN (unemulated) */
|
||||||
|
4, /* 55: FP Unimplemented Data Type (unemulated) */
|
||||||
|
4, /* 56: MMU Configuration Error (unemulated) */
|
||||||
|
4, /* 57: MMU Illegal Operation Error (unemulated) */
|
||||||
|
4, /* 58: MMU Access Level Violation Error (unemulated) */
|
||||||
|
4, /* 59: RESERVED */
|
||||||
|
4, /* 60: RESERVED */
|
||||||
|
4, /* 61: RESERVED */
|
||||||
|
4, /* 62: RESERVED */
|
||||||
|
4, /* 63: RESERVED */
|
||||||
|
/* 64-255: User Defined */
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||||
|
},
|
||||||
|
{ /* 010 */
|
||||||
|
4, /* 0: Reset - Initial Stack Pointer */
|
||||||
|
4, /* 1: Reset - Initial Program Counter */
|
||||||
|
126, /* 2: Bus Error (unemulated) */
|
||||||
|
126, /* 3: Address Error (unemulated) */
|
||||||
|
38, /* 4: Illegal Instruction */
|
||||||
|
44, /* 5: Divide by Zero */
|
||||||
|
44, /* 6: CHK */
|
||||||
|
34, /* 7: TRAPV */
|
||||||
|
38, /* 8: Privilege Violation */
|
||||||
|
38, /* 9: Trace */
|
||||||
|
4, /* 10: 1010 */
|
||||||
|
4, /* 11: 1111 */
|
||||||
|
4, /* 12: RESERVED */
|
||||||
|
4, /* 13: Coprocessor Protocol Violation (unemulated) */
|
||||||
|
4, /* 14: Format Error */
|
||||||
|
44, /* 15: Uninitialized Interrupt */
|
||||||
|
4, /* 16: RESERVED */
|
||||||
|
4, /* 17: RESERVED */
|
||||||
|
4, /* 18: RESERVED */
|
||||||
|
4, /* 19: RESERVED */
|
||||||
|
4, /* 20: RESERVED */
|
||||||
|
4, /* 21: RESERVED */
|
||||||
|
4, /* 22: RESERVED */
|
||||||
|
4, /* 23: RESERVED */
|
||||||
|
46, /* 24: Spurious Interrupt */
|
||||||
|
46, /* 25: Level 1 Interrupt Autovector */
|
||||||
|
46, /* 26: Level 2 Interrupt Autovector */
|
||||||
|
46, /* 27: Level 3 Interrupt Autovector */
|
||||||
|
46, /* 28: Level 4 Interrupt Autovector */
|
||||||
|
46, /* 29: Level 5 Interrupt Autovector */
|
||||||
|
46, /* 30: Level 6 Interrupt Autovector */
|
||||||
|
46, /* 31: Level 7 Interrupt Autovector */
|
||||||
|
38, /* 32: TRAP #0 */
|
||||||
|
38, /* 33: TRAP #1 */
|
||||||
|
38, /* 34: TRAP #2 */
|
||||||
|
38, /* 35: TRAP #3 */
|
||||||
|
38, /* 36: TRAP #4 */
|
||||||
|
38, /* 37: TRAP #5 */
|
||||||
|
38, /* 38: TRAP #6 */
|
||||||
|
38, /* 39: TRAP #7 */
|
||||||
|
38, /* 40: TRAP #8 */
|
||||||
|
38, /* 41: TRAP #9 */
|
||||||
|
38, /* 42: TRAP #10 */
|
||||||
|
38, /* 43: TRAP #11 */
|
||||||
|
38, /* 44: TRAP #12 */
|
||||||
|
38, /* 45: TRAP #13 */
|
||||||
|
38, /* 46: TRAP #14 */
|
||||||
|
38, /* 47: TRAP #15 */
|
||||||
|
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
|
||||||
|
4, /* 49: FP Inexact Result (unemulated) */
|
||||||
|
4, /* 50: FP Divide by Zero (unemulated) */
|
||||||
|
4, /* 51: FP Underflow (unemulated) */
|
||||||
|
4, /* 52: FP Operand Error (unemulated) */
|
||||||
|
4, /* 53: FP Overflow (unemulated) */
|
||||||
|
4, /* 54: FP Signaling NAN (unemulated) */
|
||||||
|
4, /* 55: FP Unimplemented Data Type (unemulated) */
|
||||||
|
4, /* 56: MMU Configuration Error (unemulated) */
|
||||||
|
4, /* 57: MMU Illegal Operation Error (unemulated) */
|
||||||
|
4, /* 58: MMU Access Level Violation Error (unemulated) */
|
||||||
|
4, /* 59: RESERVED */
|
||||||
|
4, /* 60: RESERVED */
|
||||||
|
4, /* 61: RESERVED */
|
||||||
|
4, /* 62: RESERVED */
|
||||||
|
4, /* 63: RESERVED */
|
||||||
|
/* 64-255: User Defined */
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||||
|
},
|
||||||
|
{ /* 020 */
|
||||||
|
4, /* 0: Reset - Initial Stack Pointer */
|
||||||
|
4, /* 1: Reset - Initial Program Counter */
|
||||||
|
50, /* 2: Bus Error (unemulated) */
|
||||||
|
50, /* 3: Address Error (unemulated) */
|
||||||
|
20, /* 4: Illegal Instruction */
|
||||||
|
38, /* 5: Divide by Zero */
|
||||||
|
40, /* 6: CHK */
|
||||||
|
20, /* 7: TRAPV */
|
||||||
|
34, /* 8: Privilege Violation */
|
||||||
|
25, /* 9: Trace */
|
||||||
|
20, /* 10: 1010 */
|
||||||
|
20, /* 11: 1111 */
|
||||||
|
4, /* 12: RESERVED */
|
||||||
|
4, /* 13: Coprocessor Protocol Violation (unemulated) */
|
||||||
|
4, /* 14: Format Error */
|
||||||
|
30, /* 15: Uninitialized Interrupt */
|
||||||
|
4, /* 16: RESERVED */
|
||||||
|
4, /* 17: RESERVED */
|
||||||
|
4, /* 18: RESERVED */
|
||||||
|
4, /* 19: RESERVED */
|
||||||
|
4, /* 20: RESERVED */
|
||||||
|
4, /* 21: RESERVED */
|
||||||
|
4, /* 22: RESERVED */
|
||||||
|
4, /* 23: RESERVED */
|
||||||
|
30, /* 24: Spurious Interrupt */
|
||||||
|
30, /* 25: Level 1 Interrupt Autovector */
|
||||||
|
30, /* 26: Level 2 Interrupt Autovector */
|
||||||
|
30, /* 27: Level 3 Interrupt Autovector */
|
||||||
|
30, /* 28: Level 4 Interrupt Autovector */
|
||||||
|
30, /* 29: Level 5 Interrupt Autovector */
|
||||||
|
30, /* 30: Level 6 Interrupt Autovector */
|
||||||
|
30, /* 31: Level 7 Interrupt Autovector */
|
||||||
|
20, /* 32: TRAP #0 */
|
||||||
|
20, /* 33: TRAP #1 */
|
||||||
|
20, /* 34: TRAP #2 */
|
||||||
|
20, /* 35: TRAP #3 */
|
||||||
|
20, /* 36: TRAP #4 */
|
||||||
|
20, /* 37: TRAP #5 */
|
||||||
|
20, /* 38: TRAP #6 */
|
||||||
|
20, /* 39: TRAP #7 */
|
||||||
|
20, /* 40: TRAP #8 */
|
||||||
|
20, /* 41: TRAP #9 */
|
||||||
|
20, /* 42: TRAP #10 */
|
||||||
|
20, /* 43: TRAP #11 */
|
||||||
|
20, /* 44: TRAP #12 */
|
||||||
|
20, /* 45: TRAP #13 */
|
||||||
|
20, /* 46: TRAP #14 */
|
||||||
|
20, /* 47: TRAP #15 */
|
||||||
|
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
|
||||||
|
4, /* 49: FP Inexact Result (unemulated) */
|
||||||
|
4, /* 50: FP Divide by Zero (unemulated) */
|
||||||
|
4, /* 51: FP Underflow (unemulated) */
|
||||||
|
4, /* 52: FP Operand Error (unemulated) */
|
||||||
|
4, /* 53: FP Overflow (unemulated) */
|
||||||
|
4, /* 54: FP Signaling NAN (unemulated) */
|
||||||
|
4, /* 55: FP Unimplemented Data Type (unemulated) */
|
||||||
|
4, /* 56: MMU Configuration Error (unemulated) */
|
||||||
|
4, /* 57: MMU Illegal Operation Error (unemulated) */
|
||||||
|
4, /* 58: MMU Access Level Violation Error (unemulated) */
|
||||||
|
4, /* 59: RESERVED */
|
||||||
|
4, /* 60: RESERVED */
|
||||||
|
4, /* 61: RESERVED */
|
||||||
|
4, /* 62: RESERVED */
|
||||||
|
4, /* 63: RESERVED */
|
||||||
|
/* 64-255: User Defined */
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||||
|
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8 m68ki_ea_idx_cycle_table[64] =
|
||||||
|
{
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, /* ..01.000 no memory indirect, base NULL */
|
||||||
|
5, /* ..01..01 memory indirect, base NULL, outer NULL */
|
||||||
|
7, /* ..01..10 memory indirect, base NULL, outer 16 */
|
||||||
|
7, /* ..01..11 memory indirect, base NULL, outer 32 */
|
||||||
|
0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7,
|
||||||
|
2, /* ..10.000 no memory indirect, base 16 */
|
||||||
|
7, /* ..10..01 memory indirect, base 16, outer NULL */
|
||||||
|
9, /* ..10..10 memory indirect, base 16, outer 16 */
|
||||||
|
9, /* ..10..11 memory indirect, base 16, outer 32 */
|
||||||
|
0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9,
|
||||||
|
6, /* ..11.000 no memory indirect, base 32 */
|
||||||
|
11, /* ..11..01 memory indirect, base 32, outer NULL */
|
||||||
|
13, /* ..11..10 memory indirect, base 32, outer 16 */
|
||||||
|
13, /* ..11..11 memory indirect, base 32, outer 32 */
|
||||||
|
0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* =============================== CALLBACKS ============================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* Default callbacks used if the callback hasn't been set yet, or if the
|
||||||
|
* callback is set to NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Interrupt acknowledge */
|
||||||
|
static int default_int_ack_callback_data;
|
||||||
|
static int default_int_ack_callback(int int_level)
|
||||||
|
{
|
||||||
|
default_int_ack_callback_data = int_level;
|
||||||
|
CPU_INT_LEVEL = 0;
|
||||||
|
return M68K_INT_ACK_AUTOVECTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Breakpoint acknowledge */
|
||||||
|
static unsigned int default_bkpt_ack_callback_data;
|
||||||
|
static void default_bkpt_ack_callback(unsigned int data)
|
||||||
|
{
|
||||||
|
default_bkpt_ack_callback_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when a reset instruction is executed */
|
||||||
|
static void default_reset_instr_callback(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when the program counter changed by a large value */
|
||||||
|
static unsigned int default_pc_changed_callback_data;
|
||||||
|
static void default_pc_changed_callback(unsigned int new_pc)
|
||||||
|
{
|
||||||
|
default_pc_changed_callback_data = new_pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called every time there's bus activity (read/write to/from memory */
|
||||||
|
static unsigned int default_set_fc_callback_data;
|
||||||
|
static void default_set_fc_callback(unsigned int new_fc)
|
||||||
|
{
|
||||||
|
default_set_fc_callback_data = new_fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called every instruction cycle prior to execution */
|
||||||
|
static void default_instr_hook_callback(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ================================= API ================================== */
|
||||||
|
/* ======================================================================== */
|
||||||
|
|
||||||
|
/* Access the internals of the CPU */
|
||||||
|
unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
|
||||||
|
{
|
||||||
|
m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu;
|
||||||
|
|
||||||
|
switch(regnum)
|
||||||
|
{
|
||||||
|
case M68K_REG_D0: return cpu->dar[0];
|
||||||
|
case M68K_REG_D1: return cpu->dar[1];
|
||||||
|
case M68K_REG_D2: return cpu->dar[2];
|
||||||
|
case M68K_REG_D3: return cpu->dar[3];
|
||||||
|
case M68K_REG_D4: return cpu->dar[4];
|
||||||
|
case M68K_REG_D5: return cpu->dar[5];
|
||||||
|
case M68K_REG_D6: return cpu->dar[6];
|
||||||
|
case M68K_REG_D7: return cpu->dar[7];
|
||||||
|
case M68K_REG_A0: return cpu->dar[8];
|
||||||
|
case M68K_REG_A1: return cpu->dar[9];
|
||||||
|
case M68K_REG_A2: return cpu->dar[10];
|
||||||
|
case M68K_REG_A3: return cpu->dar[11];
|
||||||
|
case M68K_REG_A4: return cpu->dar[12];
|
||||||
|
case M68K_REG_A5: return cpu->dar[13];
|
||||||
|
case M68K_REG_A6: return cpu->dar[14];
|
||||||
|
case M68K_REG_A7: return cpu->dar[15];
|
||||||
|
case M68K_REG_PC: return MASK_OUT_ABOVE_32(cpu->pc);
|
||||||
|
case M68K_REG_SR: return cpu->t1_flag |
|
||||||
|
cpu->t0_flag |
|
||||||
|
(cpu->s_flag << 11) |
|
||||||
|
(cpu->m_flag << 11) |
|
||||||
|
cpu->int_mask |
|
||||||
|
((cpu->x_flag & XFLAG_SET) >> 4) |
|
||||||
|
((cpu->n_flag & NFLAG_SET) >> 4) |
|
||||||
|
((!cpu->not_z_flag) << 2) |
|
||||||
|
((cpu->v_flag & VFLAG_SET) >> 6) |
|
||||||
|
((cpu->c_flag & CFLAG_SET) >> 8);
|
||||||
|
case M68K_REG_SP: return cpu->dar[15];
|
||||||
|
case M68K_REG_USP: return cpu->s_flag ? cpu->sp[0] : cpu->dar[15];
|
||||||
|
case M68K_REG_ISP: return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4];
|
||||||
|
case M68K_REG_MSP: return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6];
|
||||||
|
case M68K_REG_SFC: return cpu->sfc;
|
||||||
|
case M68K_REG_DFC: return cpu->dfc;
|
||||||
|
case M68K_REG_VBR: return cpu->vbr;
|
||||||
|
case M68K_REG_CACR: return cpu->cacr;
|
||||||
|
case M68K_REG_CAAR: return cpu->caar;
|
||||||
|
case M68K_REG_PREF_ADDR: return cpu->pref_addr;
|
||||||
|
case M68K_REG_PREF_DATA: return cpu->pref_data;
|
||||||
|
case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc);
|
||||||
|
case M68K_REG_IR: return cpu->ir;
|
||||||
|
case M68K_REG_CPU_TYPE:
|
||||||
|
switch(cpu->cpu_type)
|
||||||
|
{
|
||||||
|
case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000;
|
||||||
|
case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010;
|
||||||
|
case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020;
|
||||||
|
case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020;
|
||||||
|
}
|
||||||
|
return M68K_CPU_TYPE_INVALID;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_set_reg(m68k_register_t regnum, unsigned int value)
|
||||||
|
{
|
||||||
|
switch(regnum)
|
||||||
|
{
|
||||||
|
case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
|
||||||
|
case M68K_REG_SR: m68ki_set_sr(value); return;
|
||||||
|
case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_USP: if(FLAG_S)
|
||||||
|
REG_USP = MASK_OUT_ABOVE_32(value);
|
||||||
|
else
|
||||||
|
REG_SP = MASK_OUT_ABOVE_32(value);
|
||||||
|
return;
|
||||||
|
case M68K_REG_ISP: if(FLAG_S && !FLAG_M)
|
||||||
|
REG_SP = MASK_OUT_ABOVE_32(value);
|
||||||
|
else
|
||||||
|
REG_ISP = MASK_OUT_ABOVE_32(value);
|
||||||
|
return;
|
||||||
|
case M68K_REG_MSP: if(FLAG_S && FLAG_M)
|
||||||
|
REG_SP = MASK_OUT_ABOVE_32(value);
|
||||||
|
else
|
||||||
|
REG_MSP = MASK_OUT_ABOVE_32(value);
|
||||||
|
return;
|
||||||
|
case M68K_REG_VBR: REG_VBR = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_SFC: REG_SFC = value & 7; return;
|
||||||
|
case M68K_REG_DFC: REG_DFC = value & 7; return;
|
||||||
|
case M68K_REG_CACR: REG_CACR = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_CAAR: REG_CAAR = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_PPC: REG_PPC = MASK_OUT_ABOVE_32(value); return;
|
||||||
|
case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return;
|
||||||
|
case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the callbacks */
|
||||||
|
void m68k_set_int_ack_callback(int (*callback)(int int_level))
|
||||||
|
{
|
||||||
|
CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data))
|
||||||
|
{
|
||||||
|
CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_set_reset_instr_callback(void (*callback)(void))
|
||||||
|
{
|
||||||
|
CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc))
|
||||||
|
{
|
||||||
|
CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
|
||||||
|
{
|
||||||
|
CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_set_instr_hook_callback(void (*callback)(void))
|
||||||
|
{
|
||||||
|
CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
/* Set the CPU type. */
|
||||||
|
void m68k_set_cpu_type(unsigned int cpu_type)
|
||||||
|
{
|
||||||
|
switch(cpu_type)
|
||||||
|
{
|
||||||
|
case M68K_CPU_TYPE_68000:
|
||||||
|
CPU_TYPE = CPU_TYPE_000;
|
||||||
|
CPU_ADDRESS_MASK = 0x00ffffff;
|
||||||
|
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
|
||||||
|
CYC_INSTRUCTION = m68ki_cycles[0];
|
||||||
|
CYC_EXCEPTION = m68ki_exception_cycle_table[0];
|
||||||
|
CYC_BCC_NOTAKE_B = -2;
|
||||||
|
CYC_BCC_NOTAKE_W = 2;
|
||||||
|
CYC_DBCC_F_NOEXP = -2;
|
||||||
|
CYC_DBCC_F_EXP = 2;
|
||||||
|
CYC_SCC_R_FALSE = 2;
|
||||||
|
CYC_MOVEM_W = 2;
|
||||||
|
CYC_MOVEM_L = 3;
|
||||||
|
CYC_SHIFT = 1;
|
||||||
|
CYC_RESET = 132;
|
||||||
|
return;
|
||||||
|
case M68K_CPU_TYPE_68010:
|
||||||
|
CPU_TYPE = CPU_TYPE_010;
|
||||||
|
CPU_ADDRESS_MASK = 0x00ffffff;
|
||||||
|
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
|
||||||
|
CYC_INSTRUCTION = m68ki_cycles[1];
|
||||||
|
CYC_EXCEPTION = m68ki_exception_cycle_table[1];
|
||||||
|
CYC_BCC_NOTAKE_B = -4;
|
||||||
|
CYC_BCC_NOTAKE_W = 0;
|
||||||
|
CYC_DBCC_F_NOEXP = 0;
|
||||||
|
CYC_DBCC_F_EXP = 6;
|
||||||
|
CYC_SCC_R_FALSE = 0;
|
||||||
|
CYC_MOVEM_W = 2;
|
||||||
|
CYC_MOVEM_L = 3;
|
||||||
|
CYC_SHIFT = 1;
|
||||||
|
CYC_RESET = 130;
|
||||||
|
return;
|
||||||
|
case M68K_CPU_TYPE_68EC020:
|
||||||
|
CPU_TYPE = CPU_TYPE_EC020;
|
||||||
|
CPU_ADDRESS_MASK = 0x00ffffff;
|
||||||
|
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
|
||||||
|
CYC_INSTRUCTION = m68ki_cycles[2];
|
||||||
|
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
|
||||||
|
CYC_BCC_NOTAKE_B = -2;
|
||||||
|
CYC_BCC_NOTAKE_W = 0;
|
||||||
|
CYC_DBCC_F_NOEXP = 0;
|
||||||
|
CYC_DBCC_F_EXP = 4;
|
||||||
|
CYC_SCC_R_FALSE = 0;
|
||||||
|
CYC_MOVEM_W = 2;
|
||||||
|
CYC_MOVEM_L = 2;
|
||||||
|
CYC_SHIFT = 0;
|
||||||
|
CYC_RESET = 518;
|
||||||
|
return;
|
||||||
|
case M68K_CPU_TYPE_68020:
|
||||||
|
CPU_TYPE = CPU_TYPE_020;
|
||||||
|
CPU_ADDRESS_MASK = 0xffffffff;
|
||||||
|
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
|
||||||
|
CYC_INSTRUCTION = m68ki_cycles[2];
|
||||||
|
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
|
||||||
|
CYC_BCC_NOTAKE_B = -2;
|
||||||
|
CYC_BCC_NOTAKE_W = 0;
|
||||||
|
CYC_DBCC_F_NOEXP = 0;
|
||||||
|
CYC_DBCC_F_EXP = 4;
|
||||||
|
CYC_SCC_R_FALSE = 0;
|
||||||
|
CYC_MOVEM_W = 2;
|
||||||
|
CYC_MOVEM_L = 2;
|
||||||
|
CYC_SHIFT = 0;
|
||||||
|
CYC_RESET = 518;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute some instructions until we use up num_cycles clock cycles */
|
||||||
|
/* ASG: removed per-instruction interrupt checks */
|
||||||
|
int m68k_execute(int num_cycles)
|
||||||
|
{
|
||||||
|
/* Make sure we're not stopped */
|
||||||
|
if(!CPU_STOPPED)
|
||||||
|
{
|
||||||
|
/* Set our pool of clock cycles available */
|
||||||
|
SET_CYCLES(num_cycles);
|
||||||
|
m68ki_initial_cycles = num_cycles;
|
||||||
|
|
||||||
|
/* ASG: update cycles */
|
||||||
|
USE_CYCLES(CPU_INT_CYCLES);
|
||||||
|
CPU_INT_CYCLES = 0;
|
||||||
|
|
||||||
|
/* Return point if we had an address error */
|
||||||
|
m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
|
||||||
|
|
||||||
|
/* Main loop. Keep going until we run out of clock cycles */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* Set tracing accodring to T1. (T0 is done inside instruction) */
|
||||||
|
m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
|
||||||
|
|
||||||
|
/* Set the address space for reads */
|
||||||
|
m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
|
||||||
|
|
||||||
|
/* Call external hook to peek at CPU */
|
||||||
|
m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */
|
||||||
|
|
||||||
|
/* Record previous program counter */
|
||||||
|
REG_PPC = REG_PC;
|
||||||
|
|
||||||
|
/* Read an instruction and call its handler */
|
||||||
|
REG_IR = m68ki_read_imm_16();
|
||||||
|
m68ki_instruction_jump_table[REG_IR]();
|
||||||
|
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
|
||||||
|
|
||||||
|
/* Trace m68k_exception, if necessary */
|
||||||
|
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
|
||||||
|
} while(GET_CYCLES() > 0);
|
||||||
|
|
||||||
|
/* set previous PC to current PC for the next entry into the loop */
|
||||||
|
REG_PPC = REG_PC;
|
||||||
|
|
||||||
|
/* ASG: update cycles */
|
||||||
|
USE_CYCLES(CPU_INT_CYCLES);
|
||||||
|
CPU_INT_CYCLES = 0;
|
||||||
|
|
||||||
|
/* return how many clocks we used */
|
||||||
|
return m68ki_initial_cycles - GET_CYCLES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We get here if the CPU is stopped or halted */
|
||||||
|
SET_CYCLES(0);
|
||||||
|
CPU_INT_CYCLES = 0;
|
||||||
|
|
||||||
|
return num_cycles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int m68k_cycles_run(void)
|
||||||
|
{
|
||||||
|
return m68ki_initial_cycles - GET_CYCLES();
|
||||||
|
}
|
||||||
|
|
||||||
|
int m68k_cycles_remaining(void)
|
||||||
|
{
|
||||||
|
return GET_CYCLES();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the timeslice */
|
||||||
|
void m68k_modify_timeslice(int cycles)
|
||||||
|
{
|
||||||
|
m68ki_initial_cycles += cycles;
|
||||||
|
ADD_CYCLES(cycles);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void m68k_end_timeslice(void)
|
||||||
|
{
|
||||||
|
m68ki_initial_cycles = GET_CYCLES();
|
||||||
|
SET_CYCLES(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
|
||||||
|
/* KS: Modified so that IPL* bits match with mask positions in the SR
|
||||||
|
* and cleaned out remenants of the interrupt controller.
|
||||||
|
*/
|
||||||
|
void m68k_set_irq(unsigned int int_level)
|
||||||
|
{
|
||||||
|
uint old_level = CPU_INT_LEVEL;
|
||||||
|
CPU_INT_LEVEL = int_level << 8;
|
||||||
|
|
||||||
|
/* A transition from < 7 to 7 always interrupts (NMI) */
|
||||||
|
/* Note: Level 7 can also level trigger like a normal IRQ */
|
||||||
|
if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700)
|
||||||
|
m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */
|
||||||
|
else
|
||||||
|
m68ki_check_interrupts(); /* Level triggered (IRQ) */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Pulse the RESET line on the CPU */
|
||||||
|
void m68k_pulse_reset(void)
|
||||||
|
{
|
||||||
|
static uint emulation_initialized = 0;
|
||||||
|
|
||||||
|
/* The first call to this function initializes the opcode handler jump table */
|
||||||
|
if(!emulation_initialized)
|
||||||
|
{
|
||||||
|
m68ki_build_opcode_table();
|
||||||
|
m68k_set_int_ack_callback(NULL);
|
||||||
|
m68k_set_bkpt_ack_callback(NULL);
|
||||||
|
m68k_set_reset_instr_callback(NULL);
|
||||||
|
m68k_set_pc_changed_callback(NULL);
|
||||||
|
m68k_set_fc_callback(NULL);
|
||||||
|
m68k_set_instr_hook_callback(NULL);
|
||||||
|
|
||||||
|
emulation_initialized = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(CPU_TYPE == 0) /* KW 990319 */
|
||||||
|
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||||
|
|
||||||
|
/* Clear all stop levels and eat up all remaining cycles */
|
||||||
|
CPU_STOPPED = 0;
|
||||||
|
SET_CYCLES(0);
|
||||||
|
|
||||||
|
/* Turn off tracing */
|
||||||
|
FLAG_T1 = FLAG_T0 = 0;
|
||||||
|
m68ki_clear_trace();
|
||||||
|
/* Interrupt mask to level 7 */
|
||||||
|
FLAG_INT_MASK = 0x0700;
|
||||||
|
/* Reset VBR */
|
||||||
|
REG_VBR = 0;
|
||||||
|
/* Go to supervisor mode */
|
||||||
|
m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR);
|
||||||
|
|
||||||
|
/* Invalidate the prefetch queue */
|
||||||
|
#if M68K_EMULATE_PREFETCH
|
||||||
|
/* Set to arbitrary number since our first fetch is from 0 */
|
||||||
|
CPU_PREF_ADDR = 0x1000;
|
||||||
|
#endif /* M68K_EMULATE_PREFETCH */
|
||||||
|
|
||||||
|
/* Read the initial stack pointer and program counter */
|
||||||
|
m68ki_jump(0);
|
||||||
|
REG_SP = m68ki_read_imm_32();
|
||||||
|
REG_PC = m68ki_read_imm_32();
|
||||||
|
m68ki_jump(REG_PC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pulse the HALT line on the CPU */
|
||||||
|
void m68k_pulse_halt(void)
|
||||||
|
{
|
||||||
|
CPU_STOPPED |= STOP_LEVEL_HALT;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Get and set the current CPU context */
|
||||||
|
/* This is to allow for multiple CPUs */
|
||||||
|
unsigned int m68k_context_size()
|
||||||
|
{
|
||||||
|
return sizeof(m68ki_cpu_core);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int m68k_get_context(void* dst)
|
||||||
|
{
|
||||||
|
if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu;
|
||||||
|
return sizeof(m68ki_cpu_core);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_set_context(void* src)
|
||||||
|
{
|
||||||
|
if(src) m68ki_cpu = *(m68ki_cpu_core*)src;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_save_context( void (*save_value)(char*, unsigned int))
|
||||||
|
{
|
||||||
|
if(!save_value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
save_value("CPU_TYPE" , m68k_get_reg(NULL, M68K_REG_CPU_TYPE));
|
||||||
|
save_value("D0" , REG_D[0]);
|
||||||
|
save_value("D1" , REG_D[1]);
|
||||||
|
save_value("D2" , REG_D[2]);
|
||||||
|
save_value("D3" , REG_D[3]);
|
||||||
|
save_value("D4" , REG_D[4]);
|
||||||
|
save_value("D5" , REG_D[5]);
|
||||||
|
save_value("D6" , REG_D[6]);
|
||||||
|
save_value("D7" , REG_D[7]);
|
||||||
|
save_value("A0" , REG_A[0]);
|
||||||
|
save_value("A1" , REG_A[1]);
|
||||||
|
save_value("A2" , REG_A[2]);
|
||||||
|
save_value("A3" , REG_A[3]);
|
||||||
|
save_value("A4" , REG_A[4]);
|
||||||
|
save_value("A5" , REG_A[5]);
|
||||||
|
save_value("A6" , REG_A[6]);
|
||||||
|
save_value("A7" , REG_A[7]);
|
||||||
|
save_value("PPC" , REG_PPC);
|
||||||
|
save_value("PC" , REG_PC);
|
||||||
|
save_value("USP" , REG_USP);
|
||||||
|
save_value("ISP" , REG_ISP);
|
||||||
|
save_value("MSP" , REG_MSP);
|
||||||
|
save_value("VBR" , REG_VBR);
|
||||||
|
save_value("SFC" , REG_SFC);
|
||||||
|
save_value("DFC" , REG_DFC);
|
||||||
|
save_value("CACR" , REG_CACR);
|
||||||
|
save_value("CAAR" , REG_CAAR);
|
||||||
|
save_value("SR" , m68ki_get_sr());
|
||||||
|
save_value("INT_LEVEL" , CPU_INT_LEVEL);
|
||||||
|
save_value("INT_CYCLES", CPU_INT_CYCLES);
|
||||||
|
save_value("STOPPED" , (CPU_STOPPED & STOP_LEVEL_STOP) != 0);
|
||||||
|
save_value("HALTED" , (CPU_STOPPED & STOP_LEVEL_HALT) != 0);
|
||||||
|
save_value("PREF_ADDR" , CPU_PREF_ADDR);
|
||||||
|
save_value("PREF_DATA" , CPU_PREF_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_load_context(unsigned int (*load_value)(char*))
|
||||||
|
{
|
||||||
|
unsigned int temp;
|
||||||
|
|
||||||
|
m68k_set_cpu_type(load_value("CPU_TYPE"));
|
||||||
|
REG_PPC = load_value("PPC");
|
||||||
|
REG_PC = load_value("PC");
|
||||||
|
m68ki_jump(REG_PC);
|
||||||
|
CPU_INT_LEVEL = 0;
|
||||||
|
m68ki_set_sr_noint(load_value("SR"));
|
||||||
|
REG_D[0] = load_value("D0");
|
||||||
|
REG_D[1] = load_value("D1");
|
||||||
|
REG_D[2] = load_value("D2");
|
||||||
|
REG_D[3] = load_value("D3");
|
||||||
|
REG_D[4] = load_value("D4");
|
||||||
|
REG_D[5] = load_value("D5");
|
||||||
|
REG_D[6] = load_value("D6");
|
||||||
|
REG_D[7] = load_value("D7");
|
||||||
|
REG_A[0] = load_value("A0");
|
||||||
|
REG_A[1] = load_value("A1");
|
||||||
|
REG_A[2] = load_value("A2");
|
||||||
|
REG_A[3] = load_value("A3");
|
||||||
|
REG_A[4] = load_value("A4");
|
||||||
|
REG_A[5] = load_value("A5");
|
||||||
|
REG_A[6] = load_value("A6");
|
||||||
|
REG_A[7] = load_value("A7");
|
||||||
|
REG_USP = load_value("USP");
|
||||||
|
REG_ISP = load_value("ISP");
|
||||||
|
REG_MSP = load_value("MSP");
|
||||||
|
REG_VBR = load_value("VBR");
|
||||||
|
REG_SFC = load_value("SFC");
|
||||||
|
REG_DFC = load_value("DFC");
|
||||||
|
REG_CACR = load_value("CACR");
|
||||||
|
REG_CAAR = load_value("CAAR");
|
||||||
|
CPU_INT_LEVEL = load_value("INT_LEVEL");
|
||||||
|
CPU_INT_CYCLES = load_value("INT_CYCLES");
|
||||||
|
|
||||||
|
CPU_STOPPED = 0;
|
||||||
|
temp = load_value("STOPPED");
|
||||||
|
if(temp) CPU_STOPPED |= STOP_LEVEL_STOP;
|
||||||
|
temp = load_value("HALTED");
|
||||||
|
if(temp) CPU_STOPPED |= STOP_LEVEL_HALT;
|
||||||
|
|
||||||
|
CPU_PREF_ADDR = load_value("PREF_ADDR");
|
||||||
|
CPU_PREF_DATA = load_value("PREF_DATA");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ======================================================================== */
|
||||||
|
/* ============================== END OF FILE ============================= */
|
||||||
|
/* ======================================================================== */
|
1841
AltairZ80/m68kcpu.h
Executable file
1841
AltairZ80/m68kcpu.h
Executable file
File diff suppressed because it is too large
Load diff
3443
AltairZ80/m68kdasm.c
Executable file
3443
AltairZ80/m68kdasm.c
Executable file
File diff suppressed because it is too large
Load diff
11948
AltairZ80/m68kopac.c
Normal file
11948
AltairZ80/m68kopac.c
Normal file
File diff suppressed because it is too large
Load diff
13221
AltairZ80/m68kopdm.c
Normal file
13221
AltairZ80/m68kopdm.c
Normal file
File diff suppressed because it is too large
Load diff
8710
AltairZ80/m68kopnz.c
Normal file
8710
AltairZ80/m68kopnz.c
Normal file
File diff suppressed because it is too large
Load diff
2093
AltairZ80/m68kops.c
Normal file
2093
AltairZ80/m68kops.c
Normal file
File diff suppressed because it is too large
Load diff
1984
AltairZ80/m68kops.h
Normal file
1984
AltairZ80/m68kops.h
Normal file
File diff suppressed because it is too large
Load diff
543
AltairZ80/m68ksim.c
Normal file
543
AltairZ80/m68ksim.c
Normal file
|
@ -0,0 +1,543 @@
|
||||||
|
/* m68kcpmsim.c: CP/M for Motorola 68000 definitions
|
||||||
|
|
||||||
|
Copyright (c) 2014, Peter Schorn
|
||||||
|
|
||||||
|
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
|
||||||
|
PETER SCHORN 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 Peter Schorn shall not
|
||||||
|
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
|
in this Software without prior written authorization from Peter Schorn.
|
||||||
|
|
||||||
|
Based on work by David W. Schultz http://home.earthlink.net/~david.schultz (c) 2014
|
||||||
|
|
||||||
|
|
||||||
|
MC68000 simulation tailored to support CP/M-68K. It includes:
|
||||||
|
|
||||||
|
16MB of memory. (Flat, function codes and address space types ignored.)
|
||||||
|
|
||||||
|
Console I/O using a MC6850 like serial port with interrupts.
|
||||||
|
|
||||||
|
Simulated disk system:
|
||||||
|
|
||||||
|
Since the intent is to support CP/M-68K and it does disk I/O in 128 byte
|
||||||
|
chunks, so will this. Control is via several registers mapped into memory:
|
||||||
|
|
||||||
|
Offset Function Description
|
||||||
|
0 DMA address to read/write data to
|
||||||
|
4 drive select disk drive
|
||||||
|
8 read sector sector (128 byte) offset on disk
|
||||||
|
12 write sector sector (128 byte) offset on disk
|
||||||
|
16 status read status of operation
|
||||||
|
|
||||||
|
Operation is simple: Set the drive and DMA address and then write the
|
||||||
|
sector number to the sector register. This write triggers the requested
|
||||||
|
operation. The status of the operation can be determined by reading the
|
||||||
|
status register.
|
||||||
|
A zero indicates that no error occured.
|
||||||
|
|
||||||
|
Note that these operations invoke read() and write() system calls directly
|
||||||
|
so that they will alter the image on the hard disk. KEEP BACKUPS!
|
||||||
|
|
||||||
|
In addition Linux will buffer the writes so they may note be really complete
|
||||||
|
for a while. The BIOS flush function invokes a fsync on all open files.
|
||||||
|
|
||||||
|
There are two options for booting CPM:
|
||||||
|
|
||||||
|
S-records: This loads CPM in two parts. The first is in cpm400.bin which
|
||||||
|
is created from the srecords in cpm400.sr. The second is in simbios.bin
|
||||||
|
which contains the BIOS. Both of these files must be binaries and not
|
||||||
|
srecords.
|
||||||
|
|
||||||
|
If you want to alter the bios, rebuild simbios.bin using:
|
||||||
|
|
||||||
|
asl simbios.s
|
||||||
|
p2bin simbios.p
|
||||||
|
|
||||||
|
Use altairz80 cpm68k_s to boot.
|
||||||
|
|
||||||
|
Boot track: A CPM loader is in the boot track of simulated drive C. 32K of
|
||||||
|
data is loaded from that file to memory starting at $400.
|
||||||
|
|
||||||
|
Use altairz80 cpm68k to boot.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "m68k.h"
|
||||||
|
|
||||||
|
/* Read/write macros */
|
||||||
|
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
|
||||||
|
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR] << 8) | \
|
||||||
|
(BASE)[(ADDR) + 1])
|
||||||
|
#define READ_LONG(BASE, ADDR) (((BASE)[ADDR] << 24) | \
|
||||||
|
((BASE)[(ADDR) + 1] << 16) | \
|
||||||
|
((BASE)[(ADDR) + 2] << 8) | \
|
||||||
|
(BASE)[(ADDR) + 3])
|
||||||
|
|
||||||
|
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = (VAL) & 0xff
|
||||||
|
#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL) >> 8) & 0xff; \
|
||||||
|
(BASE)[(ADDR)+1] = (VAL)&0xff
|
||||||
|
#define WRITE_LONG(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL) >> 24) & 0xff; \
|
||||||
|
(BASE)[(ADDR) + 1] = ((VAL) >> 16) & 0xff; \
|
||||||
|
(BASE)[(ADDR) + 2] = ((VAL) >> 8) & 0xff; \
|
||||||
|
(BASE)[(ADDR) + 3] = (VAL) & 0xff
|
||||||
|
|
||||||
|
/* Memory-mapped IO ports */
|
||||||
|
|
||||||
|
/* 6850 serial port like thing. Implements a reduced set of functionallity. */
|
||||||
|
#define MC6850_STAT 0xff1000L // command/status register
|
||||||
|
#define MC6850_DATA 0xff1002L // receive/transmit data register
|
||||||
|
|
||||||
|
/* Memory mapped disk system */
|
||||||
|
#define DISK_BASE 0xff0000L
|
||||||
|
#define DISK_SET_DMA (DISK_BASE)
|
||||||
|
#define DISK_SET_DRIVE (DISK_BASE + 4)
|
||||||
|
#define DISK_SET_SECTOR (DISK_BASE + 8)
|
||||||
|
#define DISK_READ (DISK_BASE + 12)
|
||||||
|
#define DISK_WRITE (DISK_BASE + 16)
|
||||||
|
#define DISK_STATUS (DISK_BASE + 20)
|
||||||
|
#define DISK_FLUSH (DISK_BASE + 24)
|
||||||
|
|
||||||
|
/* Miscellaneous */
|
||||||
|
#define M68K_GET_TIME (0xff7ff8) // read long to get time in seconds
|
||||||
|
#define M68K_STOP_CPU (0xff7ffc) // write long to stop CPU and return to SIMH prompt
|
||||||
|
|
||||||
|
/* IRQ connections */
|
||||||
|
#define IRQ_NMI_DEVICE 7
|
||||||
|
#define IRQ_MC6850 5
|
||||||
|
|
||||||
|
extern uint32 PCX;
|
||||||
|
|
||||||
|
/* Prototypes */
|
||||||
|
static void MC6850_reset(void);
|
||||||
|
static void m68k_input_device_update(void);
|
||||||
|
static int nmi_device_ack(void);
|
||||||
|
static void int_controller_set(uint32 value);
|
||||||
|
static void int_controller_clear(uint32 value);
|
||||||
|
|
||||||
|
/* Data */
|
||||||
|
static int m68k_MC6850_control = 0; /* MC6850 control register */
|
||||||
|
static int m68k_MC6850_status = 2; /* MC6850 status register */
|
||||||
|
static t_stat keyboardCharacter; /* one character buffer */
|
||||||
|
static t_bool characterAvailable = FALSE; /* buffer initially empty */
|
||||||
|
|
||||||
|
static uint32 m68k_int_controller_pending = 0; /* list of pending interrupts */
|
||||||
|
static uint32 m68k_int_controller_highest_int = 0; /* Highest pending interrupt */
|
||||||
|
|
||||||
|
static uint8 m68k_ram[M68K_MAX_RAM + 1]; /* RAM */
|
||||||
|
|
||||||
|
/* Interface to HDSK device */
|
||||||
|
extern void hdsk_prepareRead(void);
|
||||||
|
extern void hdsk_prepareWrite(void);
|
||||||
|
extern void hdsk_setSelectedDisk(const int32 disk);
|
||||||
|
extern void hdsk_setSelectedSector(const int32 sector);
|
||||||
|
extern void hdsk_setSelectedTrack(const int32 track);
|
||||||
|
extern void hdsk_setSelectedDMA(const int32 dma);
|
||||||
|
extern int32 hdsk_getStatus(void);
|
||||||
|
extern t_bool hdsk_checkParameters(void);
|
||||||
|
extern int32 hdsk_read(void);
|
||||||
|
extern int32 hdsk_write(void);
|
||||||
|
extern int32 hdsk_flush(void);
|
||||||
|
|
||||||
|
static uint32 m68k_fc; /* Current function code from CPU */
|
||||||
|
|
||||||
|
extern uint32 m68k_registers[M68K_REG_CPU_TYPE + 1];
|
||||||
|
extern UNIT cpu_unit;
|
||||||
|
|
||||||
|
#define M68K_BOOT_LENGTH (32 * 1024) /* size of bootstrap */
|
||||||
|
#define M68K_BOOT_PC 0x000400 /* initial PC for boot */
|
||||||
|
#define M68K_BOOT_SP 0xfe0000 /* initial SP for boot */
|
||||||
|
|
||||||
|
t_stat m68k_hdsk_boot(const int32 unitno, DEVICE *dptr,
|
||||||
|
const uint32 verboseMessage, const uint32 hdskNumber) {
|
||||||
|
UNIT *uptr;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if ((unitno < 0) || (unitno >= hdskNumber))
|
||||||
|
return SCPE_ARG;
|
||||||
|
|
||||||
|
uptr = (dptr -> units) + unitno;
|
||||||
|
if (((uptr -> flags) & UNIT_ATT) == 0) {
|
||||||
|
sim_debug(verboseMessage, dptr, "HDSK%d: Boot drive is not attached.\n", unitno);
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sim_fseek(uptr -> fileref, 0, SEEK_SET) != 0) {
|
||||||
|
sim_debug(verboseMessage, dptr, "HDSK%d: Boot error seeking start.\n", unitno);
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = sim_fread(&m68k_ram[M68K_BOOT_PC], 1, M68K_BOOT_LENGTH, uptr -> fileref);
|
||||||
|
if (i != M68K_BOOT_LENGTH) {
|
||||||
|
sim_debug(verboseMessage, dptr,
|
||||||
|
"HDSK%d: Error: Failed to read %i bytes from boot drive.\n",
|
||||||
|
unitno, M68K_BOOT_LENGTH);
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now put in values for the stack and PC vectors
|
||||||
|
WRITE_LONG(m68k_ram, 0, M68K_BOOT_SP); // SP
|
||||||
|
WRITE_LONG(m68k_ram, 4, M68K_BOOT_PC); // PC
|
||||||
|
m68k_pulse_reset(); // also calls MC6850_reset()
|
||||||
|
m68k_CPUToView();
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_CPUToView(void) {
|
||||||
|
uint32 reg;
|
||||||
|
for (reg = M68K_REG_D0; reg <= M68K_REG_CPU_TYPE; reg++)
|
||||||
|
m68k_registers[reg] = m68k_get_reg(NULL, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_viewToCPU(void) {
|
||||||
|
uint32 reg;
|
||||||
|
for (reg = M68K_REG_D0; reg <= M68K_REG_CPU_TYPE; reg++)
|
||||||
|
m68k_set_reg(reg, m68k_registers[reg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat sim_instr_m68k(void) {
|
||||||
|
t_stat reason = SCPE_OK;
|
||||||
|
m68k_viewToCPU();
|
||||||
|
while (TRUE) {
|
||||||
|
if (sim_interval <= 0) { /* check clock queue */
|
||||||
|
#if !UNIX_PLATFORM
|
||||||
|
if ((reason = sim_poll_kbd()) == SCPE_STOP) /* poll on platforms without reliable
|
||||||
|
signalling */
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
if ((reason = sim_process_event()))
|
||||||
|
break;
|
||||||
|
m68k_input_device_update();
|
||||||
|
}
|
||||||
|
if (sim_brk_summ && sim_brk_test(m68k_get_reg(NULL, M68K_REG_PC), SWMASK('E'))) {
|
||||||
|
/* breakpoint? */
|
||||||
|
reason = STOP_IBKPT; /* stop simulation */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
PCX = m68k_get_reg(NULL, M68K_REG_PC);
|
||||||
|
sim_interval--;
|
||||||
|
m68k_execute(1);
|
||||||
|
if (stop_cpu) {
|
||||||
|
reason = SCPE_STOP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m68k_CPUToView();
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_clear_memory(void ) {
|
||||||
|
uint32 i;
|
||||||
|
for (i = 0; i <= M68K_MAX_RAM; i++)
|
||||||
|
m68k_ram[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_cpu_reset(void) {
|
||||||
|
WRITE_LONG(m68k_ram, 0, 0x00006000); // SP
|
||||||
|
WRITE_LONG(m68k_ram, 4, 0x00000200); // PC
|
||||||
|
m68k_pulse_reset(); // also calls MC6850_reset()
|
||||||
|
m68k_CPUToView();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation for the MC6850 like device
|
||||||
|
|
||||||
|
Only those bits of the control register that enable/disable receive and
|
||||||
|
transmit interrupts are implemented.
|
||||||
|
|
||||||
|
In the status register, the Receive Data Register Full, Transmit Data
|
||||||
|
Register Empty, and IRQ flags are implemented. Although the transmit
|
||||||
|
data register is always empty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void MC6850_reset(void) {
|
||||||
|
m68k_MC6850_control = 0;
|
||||||
|
m68k_MC6850_status = 2;
|
||||||
|
characterAvailable = FALSE;
|
||||||
|
int_controller_clear(IRQ_MC6850);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INITIAL_IDLE 100
|
||||||
|
#define IDLE_SLEEP 20
|
||||||
|
static uint32 idleCount = INITIAL_IDLE;
|
||||||
|
|
||||||
|
static void m68k_input_device_update(void) {
|
||||||
|
if (characterAvailable) {
|
||||||
|
m68k_MC6850_status |= 1;
|
||||||
|
if ((m68k_MC6850_control & 0x80) && !(m68k_MC6850_status & 0x80)) {
|
||||||
|
int_controller_set(IRQ_MC6850);
|
||||||
|
m68k_MC6850_status |= 0x80;
|
||||||
|
}
|
||||||
|
} else if (--idleCount == 0) {
|
||||||
|
const t_stat ch = sim_poll_kbd();
|
||||||
|
idleCount = INITIAL_IDLE;
|
||||||
|
if (IDLE_SLEEP)
|
||||||
|
sim_os_ms_sleep(IDLE_SLEEP);
|
||||||
|
if (ch) {
|
||||||
|
characterAvailable = TRUE;
|
||||||
|
keyboardCharacter = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait until character becomes available */
|
||||||
|
static uint32 MC6850_data_read(void) {
|
||||||
|
t_stat ch;
|
||||||
|
int_controller_clear(IRQ_MC6850);
|
||||||
|
m68k_MC6850_status &= ~0x81; // clear data ready and interrupt flag
|
||||||
|
if (characterAvailable) {
|
||||||
|
ch = keyboardCharacter;
|
||||||
|
characterAvailable = FALSE;
|
||||||
|
} else
|
||||||
|
ch = sim_poll_kbd();
|
||||||
|
while ((ch <= 0) && (!stop_cpu)) {
|
||||||
|
if (IDLE_SLEEP)
|
||||||
|
sim_os_ms_sleep(IDLE_SLEEP);
|
||||||
|
ch = sim_poll_kbd();
|
||||||
|
}
|
||||||
|
if (ch == SCPE_STOP)
|
||||||
|
stop_cpu = TRUE;
|
||||||
|
return (((ch > 0) && (!stop_cpu)) ? ch & 0xff : 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int MC6850_status_read() {
|
||||||
|
return m68k_MC6850_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation for the output device */
|
||||||
|
static int MC6850_device_ack(void) {
|
||||||
|
return M68K_INT_ACK_AUTOVECTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MC6850_data_write(uint32 value) {
|
||||||
|
sim_putchar(value);
|
||||||
|
if ((m68k_MC6850_control & 0x60) == 0x20) { // transmit interupt enabled?
|
||||||
|
int_controller_clear(IRQ_MC6850);
|
||||||
|
int_controller_set(IRQ_MC6850);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MC6850_control_write(uint32 val) {
|
||||||
|
m68k_MC6850_control = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read data from RAM */
|
||||||
|
unsigned int m68k_cpu_read_byte_raw(unsigned int address) {
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to read byte from non existing memory 0x%08x." NLP,
|
||||||
|
PCX, address);
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
return READ_BYTE(m68k_ram, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int m68k_cpu_read_byte(unsigned int address) {
|
||||||
|
switch(address) {
|
||||||
|
case MC6850_DATA:
|
||||||
|
return MC6850_data_read();
|
||||||
|
case MC6850_STAT:
|
||||||
|
return MC6850_status_read();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to read byte from non existing memory 0x%08x." NLP,
|
||||||
|
PCX, address);
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
return READ_BYTE(m68k_ram, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int m68k_cpu_read_word(unsigned int address) {
|
||||||
|
switch(address) {
|
||||||
|
case DISK_STATUS:
|
||||||
|
return hdsk_getStatus();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to read word from non existing memory 0x%08x." NLP,
|
||||||
|
PCX, address);
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
return READ_WORD(m68k_ram, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int m68k_cpu_read_long(unsigned int address) {
|
||||||
|
switch(address) {
|
||||||
|
case DISK_STATUS:
|
||||||
|
return hdsk_getStatus();
|
||||||
|
case M68K_GET_TIME:
|
||||||
|
return time(NULL);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to read long from non existing memory 0x%08x." NLP,
|
||||||
|
PCX, address);
|
||||||
|
return 0xffffffff;
|
||||||
|
}
|
||||||
|
return READ_LONG(m68k_ram, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write data to RAM or a device */
|
||||||
|
void m68k_cpu_write_byte_raw(unsigned int address, unsigned int value) {
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to write byte 0x%02x to non existing memory 0x%08x." NLP,
|
||||||
|
PCX, value & 0xff, address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WRITE_BYTE(m68k_ram, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_cpu_write_byte(unsigned int address, unsigned int value) {
|
||||||
|
switch(address) {
|
||||||
|
case MC6850_DATA:
|
||||||
|
MC6850_data_write(value & 0xff);
|
||||||
|
return;
|
||||||
|
case MC6850_STAT:
|
||||||
|
MC6850_control_write(value & 0xff);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to write byte 0x%02x to non existing memory 0x%08x." NLP,
|
||||||
|
PCX, value & 0xff, address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WRITE_BYTE(m68k_ram, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_cpu_write_word(unsigned int address, unsigned int value) {
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to write word 0x%04x to non existing memory 0x%08x." NLP,
|
||||||
|
PCX, value & 0xffff, address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WRITE_WORD(m68k_ram, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m68k_cpu_write_long(unsigned int address, unsigned int value) {
|
||||||
|
switch(address) {
|
||||||
|
case DISK_SET_DRIVE:
|
||||||
|
hdsk_setSelectedDisk(value);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DISK_SET_DMA:
|
||||||
|
hdsk_setSelectedDMA(value);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DISK_SET_SECTOR:
|
||||||
|
hdsk_setSelectedSector(value);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DISK_READ:
|
||||||
|
hdsk_setSelectedSector(value);
|
||||||
|
hdsk_setSelectedTrack(0);
|
||||||
|
hdsk_prepareRead();
|
||||||
|
if (hdsk_checkParameters())
|
||||||
|
hdsk_read();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DISK_WRITE:
|
||||||
|
hdsk_setSelectedSector(value);
|
||||||
|
hdsk_setSelectedTrack(0);
|
||||||
|
hdsk_prepareWrite();
|
||||||
|
if (hdsk_checkParameters())
|
||||||
|
hdsk_write();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DISK_FLUSH:
|
||||||
|
hdsk_flush();
|
||||||
|
return;
|
||||||
|
|
||||||
|
case M68K_STOP_CPU:
|
||||||
|
stop_cpu = TRUE;
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (address > M68K_MAX_RAM) {
|
||||||
|
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
|
||||||
|
printf("M68K: 0x%08x Attempt to write long 0x%08x to non existing memory 0x%08x." NLP,
|
||||||
|
PCX, value, address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
WRITE_LONG(m68k_ram, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when the CPU pulses the RESET line */
|
||||||
|
void m68k_cpu_pulse_reset(void) {
|
||||||
|
MC6850_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when the CPU changes the function code pins */
|
||||||
|
void m68k_cpu_set_fc(unsigned int fc) {
|
||||||
|
m68k_fc = fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called when the CPU acknowledges an interrupt */
|
||||||
|
int m68k_cpu_irq_ack(int level) {
|
||||||
|
switch(level) {
|
||||||
|
case IRQ_NMI_DEVICE:
|
||||||
|
return nmi_device_ack();
|
||||||
|
case IRQ_MC6850:
|
||||||
|
return MC6850_device_ack();
|
||||||
|
}
|
||||||
|
return M68K_INT_ACK_SPURIOUS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation for the NMI device */
|
||||||
|
static int nmi_device_ack(void) {
|
||||||
|
int_controller_clear(IRQ_NMI_DEVICE);
|
||||||
|
return M68K_INT_ACK_AUTOVECTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation for the interrupt controller */
|
||||||
|
static void int_controller_set(uint32 value) {
|
||||||
|
const uint32 old_pending = m68k_int_controller_pending;
|
||||||
|
m68k_int_controller_pending |= (1<<value);
|
||||||
|
if (old_pending != m68k_int_controller_pending && value > m68k_int_controller_highest_int) {
|
||||||
|
m68k_int_controller_highest_int = value;
|
||||||
|
m68k_set_irq(m68k_int_controller_highest_int);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void int_controller_clear(uint32 value) {
|
||||||
|
m68k_int_controller_pending &= ~(1<<value);
|
||||||
|
for (m68k_int_controller_highest_int = 7; m68k_int_controller_highest_int > 0;m68k_int_controller_highest_int--)
|
||||||
|
if (m68k_int_controller_pending & (1<<m68k_int_controller_highest_int))
|
||||||
|
break;
|
||||||
|
m68k_set_irq(m68k_int_controller_highest_int);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int m68k_read_disassembler_16(unsigned int address) {
|
||||||
|
return m68k_cpu_read_word(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int m68k_read_disassembler_32(unsigned int address) {
|
||||||
|
return m68k_cpu_read_long(address);
|
||||||
|
}
|
57
AltairZ80/m68ksim.h
Normal file
57
AltairZ80/m68ksim.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/* m68kcpmsim.h: CP/M for Motorola 68000 definitions
|
||||||
|
|
||||||
|
Copyright (c) 2014, Peter Schorn
|
||||||
|
|
||||||
|
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
|
||||||
|
PETER SCHORN 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 Peter Schorn shall not
|
||||||
|
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||||
|
in this Software without prior written authorization from Peter Schorn.
|
||||||
|
|
||||||
|
Based on work by David W. Schultz http://home.earthlink.net/~david.schultz (c) 2014
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef M68KSIM__HEADER
|
||||||
|
#define M68KSIM__HEADER
|
||||||
|
|
||||||
|
#include "altairz80_defs.h"
|
||||||
|
|
||||||
|
unsigned int m68k_cpu_read_byte(unsigned int address);
|
||||||
|
unsigned int m68k_cpu_read_byte_raw(unsigned int address);
|
||||||
|
unsigned int m68k_cpu_read_word(unsigned int address);
|
||||||
|
unsigned int m68k_cpu_read_long(unsigned int address);
|
||||||
|
void m68k_cpu_write_byte(unsigned int address, unsigned int value);
|
||||||
|
void m68k_cpu_write_byte_raw(unsigned int address, unsigned int value);
|
||||||
|
void m68k_cpu_write_word(unsigned int address, unsigned int value);
|
||||||
|
void m68k_cpu_write_long(unsigned int address, unsigned int value);
|
||||||
|
void m68k_cpu_pulse_reset(void);
|
||||||
|
void m68k_cpu_set_fc(unsigned int fc);
|
||||||
|
int m68k_cpu_irq_ack(int level);
|
||||||
|
|
||||||
|
t_stat sim_instr_m68k(void);
|
||||||
|
void m68k_cpu_reset(void);
|
||||||
|
void m68k_clear_memory(void);
|
||||||
|
void m68k_CPUToView(void);
|
||||||
|
void m68k_viewToCPU(void);
|
||||||
|
t_stat m68k_hdsk_boot(const int32 unitno, DEVICE *dptr,
|
||||||
|
const uint32 verboseMessage, const uint32 hdskNumber);
|
||||||
|
|
||||||
|
#define M68K_MAX_RAM 0xffffff // highest address of 16MB of RAM
|
||||||
|
#define M68K_MAX_RAM_LOG2 24 // 24 bit addresses
|
||||||
|
|
||||||
|
#endif /* M68KSIM__HEADER */
|
|
@ -59,13 +59,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define STATUS_MSG (1 << 0)
|
||||||
#define SEEK_MSG (1 << 1)
|
#define SEEK_MSG (1 << 1)
|
||||||
#define CMD_MSG (1 << 2)
|
#define CMD_MSG (1 << 2)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define RD_DATA_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
#define WR_DATA_MSG (1 << 4)
|
||||||
#define STATUS_MSG (1 << 5)
|
|
||||||
#define ORDERS_MSG (1 << 7)
|
|
||||||
|
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
|
@ -150,27 +148,32 @@ static REG mfdc_reg[] = {
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MDSK_NAME "Micropolis FD Control MDSK"
|
||||||
|
|
||||||
static MTAB mfdc_mod[] = {
|
static MTAB mfdc_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
|
||||||
{ UNIT_MFDC_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_membase, &show_membase, NULL, "Sets disk controller base address" },
|
||||||
{ UNIT_MFDC_WLK, UNIT_MFDC_WLK, "WRTLCK", "WRTLCK", NULL },
|
{ UNIT_MFDC_WLK, 0, "WRTENB", "WRTENB",
|
||||||
|
NULL, NULL, NULL, "Enables " MDSK_NAME "n for writing" },
|
||||||
|
{ UNIT_MFDC_WLK, UNIT_MFDC_WLK, "WRTLCK", "WRTLCK",
|
||||||
|
NULL, NULL, NULL, "Locks " MDSK_NAME "n for writing" },
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_MFDC_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_MFDC_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " MDSK_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_MFDC_VERBOSE, UNIT_MFDC_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_MFDC_VERBOSE, UNIT_MFDC_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " MDSK_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB mfdc_dt[] = {
|
static DEBTAB mfdc_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek activity" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Commands" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Disk read activity" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Disk write activity" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ NULL, 0 }
|
||||||
{ "ORDERS", ORDERS_MSG },
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE mfdc_dev = {
|
DEVICE mfdc_dev = {
|
||||||
|
@ -178,8 +181,8 @@ DEVICE mfdc_dev = {
|
||||||
MFDC_MAX_DRIVES, 10, 31, 1, MFDC_MAX_DRIVES, MFDC_MAX_DRIVES,
|
MFDC_MAX_DRIVES, 10, 31, 1, MFDC_MAX_DRIVES, MFDC_MAX_DRIVES,
|
||||||
NULL, NULL, &mfdc_reset,
|
NULL, NULL, &mfdc_reset,
|
||||||
NULL, &mfdc_attach, &mfdc_detach,
|
NULL, &mfdc_attach, &mfdc_detach,
|
||||||
&mfdc_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&mfdc_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
||||||
mfdc_dt, NULL, "Micropolis FD Control MDSK"
|
mfdc_dt, NULL, MDSK_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Micropolis FD Control Boot ROM
|
/* Micropolis FD Control Boot ROM
|
||||||
|
|
|
@ -55,13 +55,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define PIO_MSG (1 << 0)
|
||||||
#define PIO_MSG (1 << 1)
|
#define UART_MSG (1 << 1)
|
||||||
#define UART_MSG (1 << 2)
|
#define MPCL_MSG (1 << 2)
|
||||||
#define RTC_MSG (1 << 3)
|
#define ROM_MSG (1 << 3)
|
||||||
#define MPCL_MSG (1 << 4)
|
#define VERBOSE_MSG (1 << 4)
|
||||||
#define ROM_MSG (1 << 5)
|
|
||||||
#define VERBOSE_MSG (1 << 7)
|
|
||||||
|
|
||||||
#define N8VEM_MAX_DRIVES 2
|
#define N8VEM_MAX_DRIVES 2
|
||||||
|
|
||||||
|
@ -86,7 +84,6 @@ extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern REG *sim_PC;
|
|
||||||
extern int32 find_unit_index (UNIT *uptr);
|
extern int32 find_unit_index (UNIT *uptr);
|
||||||
|
|
||||||
static t_stat n8vem_reset(DEVICE *n8vem_dev);
|
static t_stat n8vem_reset(DEVICE *n8vem_dev);
|
||||||
|
@ -121,30 +118,38 @@ static UNIT n8vem_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG n8vem_reg[] = {
|
static REG n8vem_reg[] = {
|
||||||
{ HRDATA (SAVEROM, save_rom, 1), },
|
{ HRDATAD (SAVEROM, save_rom, 1,
|
||||||
{ HRDATA (SAVERAM, save_ram, 1), },
|
"When 1, saves the ROM back to file on disk at detach time"), },
|
||||||
{ HRDATA (PIO1A, n8vem_pio1a, 8), },
|
{ HRDATAD (SAVERAM, save_ram, 1,
|
||||||
{ HRDATA (PIO1B, n8vem_pio1b, 8), },
|
"When 1 save the RAM back to file on disk at detach time"), },
|
||||||
{ HRDATA (PIO1C, n8vem_pio1c, 8), },
|
{ HRDATAD (PIO1A, n8vem_pio1a, 8,
|
||||||
{ HRDATA (PIO1CTRL, n8vem_pio1ctrl, 8), },
|
"8255 PIO1A IN Port"), },
|
||||||
|
{ HRDATAD (PIO1B, n8vem_pio1b, 8,
|
||||||
|
"8255 PIO1B OUT Port"), },
|
||||||
|
{ HRDATAD (PIO1C, n8vem_pio1c, 8,
|
||||||
|
"8255 PIO1C IN Port"), },
|
||||||
|
{ HRDATAD (PIO1CTRL, n8vem_pio1ctrl, 8,
|
||||||
|
"8255 PIO1 Control Port"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define N8VEM_NAME "Single-Board Computer N8VEM"
|
||||||
|
|
||||||
static MTAB n8vem_mod[] = {
|
static MTAB n8vem_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase,
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
NULL, "Sets device base address" },
|
||||||
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase,
|
||||||
|
NULL, "Sets device I/O address" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB n8vem_dt[] = {
|
static DEBTAB n8vem_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "PIO", PIO_MSG, "PIP activity"} ,
|
||||||
{ "PIO", PIO_MSG },
|
{ "UART", UART_MSG, "UART activity" },
|
||||||
{ "UART", UART_MSG },
|
{ "ROM", ROM_MSG, "ROM activity" },
|
||||||
{ "RTC", RTC_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "ROM", ROM_MSG },
|
{ NULL, 0 }
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE n8vem_dev = {
|
DEVICE n8vem_dev = {
|
||||||
|
@ -152,7 +157,7 @@ DEVICE n8vem_dev = {
|
||||||
N8VEM_MAX_DRIVES, 10, 31, 1, N8VEM_MAX_DRIVES, N8VEM_MAX_DRIVES,
|
N8VEM_MAX_DRIVES, 10, 31, 1, N8VEM_MAX_DRIVES, N8VEM_MAX_DRIVES,
|
||||||
NULL, NULL, &n8vem_reset,
|
NULL, NULL, &n8vem_reset,
|
||||||
&n8vem_boot, &n8vem_attach, &n8vem_detach,
|
&n8vem_boot, &n8vem_attach, &n8vem_detach,
|
||||||
&n8vem_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&n8vem_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
||||||
n8vem_dt, NULL, "Single-Board Computer N8VEM"
|
n8vem_dt, NULL, "Single-Board Computer N8VEM"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -59,15 +59,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define STATUS_MSG (1 << 0)
|
||||||
#define SEEK_MSG (1 << 1)
|
#define DRIVE_MSG (1 << 1)
|
||||||
#define CMD_MSG (1 << 2)
|
#define VERBOSE_MSG (1 << 2)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define IRQ_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
|
||||||
#define STATUS_MSG (1 << 5)
|
|
||||||
#define DRIVE_MSG (1 << 6)
|
|
||||||
#define VERBOSE_MSG (1 << 7)
|
|
||||||
#define IRQ_MSG (1 << 8)
|
|
||||||
|
|
||||||
#define CROMFDC_MAX_DRIVES 4
|
#define CROMFDC_MAX_DRIVES 4
|
||||||
#define CROMFDC_ROM_SIZE (8 * 1024)
|
#define CROMFDC_ROM_SIZE (8 * 1024)
|
||||||
|
@ -100,13 +95,8 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ
|
||||||
|
|
||||||
static t_stat cromfdc_svc (UNIT *uptr);
|
static t_stat cromfdc_svc (UNIT *uptr);
|
||||||
|
|
||||||
extern REG *sim_PC;
|
|
||||||
extern uint32 PCX; /* external view of PC */
|
extern uint32 PCX; /* external view of PC */
|
||||||
|
|
||||||
#define UNIT_V_CROMFDC_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_CROMFDC_WLK (1 << UNIT_V_CROMFDC_WLK)
|
|
||||||
#define UNIT_V_CROMFDC_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
|
||||||
#define UNIT_CROMFDC_VERBOSE (1 << UNIT_V_CROMFDC_VERBOSE)
|
|
||||||
#define UNIT_V_CROMFDC_ROM (UNIT_V_UF + 2) /* boot ROM enabled */
|
#define UNIT_V_CROMFDC_ROM (UNIT_V_UF + 2) /* boot ROM enabled */
|
||||||
#define UNIT_CROMFDC_ROM (1 << UNIT_V_CROMFDC_ROM)
|
#define UNIT_CROMFDC_ROM (1 << UNIT_V_CROMFDC_ROM)
|
||||||
#define CROMFDC_CAPACITY (77*1*26*128) /* Default SSSD 8" (IBM 3740) Disk Capacity */
|
#define CROMFDC_CAPACITY (77*1*26*128) /* Default SSSD 8" (IBM 3740) Disk Capacity */
|
||||||
|
@ -226,40 +216,41 @@ static UNIT cromfdc_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG cromfdc_reg[] = {
|
static REG cromfdc_reg[] = {
|
||||||
{ HRDATA (DIPSW, dipswitch, 8), },
|
{ HRDATAD (DIPSW, dipswitch, 8,
|
||||||
{ DRDATA (BOOTSTRAP, bootstrap, 2), },
|
"5-position DIP switch on 64FDC card"), },
|
||||||
{ DRDATA (FDCTYPE, crofdc_type, 8), },
|
{ DRDATAD (BOOTSTRAP, bootstrap, 2,
|
||||||
{ DRDATA (BOOT, crofdc_boot, 10), },
|
"0 for RDOS 2.52, 1 for RDOS 3.12"), },
|
||||||
{ DRDATA (INHINIT, crofdc_inh_init, 10), },
|
{ DRDATAD (FDCTYPE, crofdc_type, 8,
|
||||||
|
"Controller type, either 4, 16, or 64 for Cromemco, 50 for CCS-2422"), },
|
||||||
|
{ DRDATAD (BOOT, crofdc_boot, 10,
|
||||||
|
"BOOT jumper setting, default is auto-boot"), },
|
||||||
|
{ DRDATAD (INHINIT, crofdc_inh_init, 10,
|
||||||
|
"Inhibit Init (Format) switch, default is not inhibited"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define CROMFDC_NAME "Cromemco 4/16/64 FDC CROMFDC"
|
||||||
|
|
||||||
static MTAB cromfdc_mod[] = {
|
static MTAB cromfdc_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
&set_membase, &show_membase, NULL, "Sets disk controller memory base address" },
|
||||||
{ UNIT_CROMFDC_WLK, 0, "WRTENB", "WRTENB", NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_CROMFDC_WLK, UNIT_CROMFDC_WLK, "WRTLCK", "WRTLCK", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_CROMFDC_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_CROMFDC_ROM, 0, "NOROM", "NOROM",
|
||||||
/* verbose, show warning messages */
|
NULL, NULL, NULL, "Disables boot ROM for unit " CROMFDC_NAME "n" },
|
||||||
{ UNIT_CROMFDC_VERBOSE, UNIT_CROMFDC_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_CROMFDC_ROM, UNIT_CROMFDC_ROM, "ROM", "ROM",
|
||||||
{ UNIT_CROMFDC_ROM, 0, "NOROM", "NOROM", NULL },
|
NULL, NULL, NULL, "Enables boot ROM for unit " CROMFDC_NAME "n" },
|
||||||
{ UNIT_CROMFDC_ROM, UNIT_CROMFDC_ROM, "ROM", "ROM", NULL },
|
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB cromfdc_dt[] = {
|
static DEBTAB cromfdc_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "DRIVE", DRIVE_MSG, "Drive messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "IRQ", IRQ_MSG, "IRQ messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ NULL, 0 }
|
||||||
{ "STATUS", STATUS_MSG },
|
|
||||||
{ "DRIVE", DRIVE_MSG },
|
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
|
||||||
{ "IRQ", IRQ_MSG },
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE cromfdc_dev = {
|
DEVICE cromfdc_dev = {
|
||||||
|
@ -267,8 +258,8 @@ DEVICE cromfdc_dev = {
|
||||||
CROMFDC_MAX_DRIVES, 10, 31, 1, CROMFDC_MAX_DRIVES, CROMFDC_MAX_DRIVES,
|
CROMFDC_MAX_DRIVES, 10, 31, 1, CROMFDC_MAX_DRIVES, CROMFDC_MAX_DRIVES,
|
||||||
NULL, NULL, &cromfdc_reset,
|
NULL, NULL, &cromfdc_reset,
|
||||||
&cromfdc_boot, &wd179x_attach, &wd179x_detach,
|
&cromfdc_boot, &wd179x_attach, &wd179x_detach,
|
||||||
&cromfdc_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&cromfdc_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
||||||
cromfdc_dt, NULL, "Cromemco 4/16/64 FDC CROMFDC"
|
cromfdc_dt, NULL, CROMFDC_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is the CROMFDC RDOS-II ROM.
|
/* This is the CROMFDC RDOS-II ROM.
|
||||||
|
|
|
@ -62,15 +62,9 @@
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define ERROR_MSG (1 << 0)
|
||||||
#define SEEK_MSG (1 << 1)
|
#define DRIVE_MSG (1 << 1)
|
||||||
#define CMD_MSG (1 << 2)
|
#define VERBOSE_MSG (1 << 2)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define DMA_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
|
||||||
#define STATUS_MSG (1 << 5)
|
|
||||||
#define DRIVE_MSG (1 << 6)
|
|
||||||
#define VERBOSE_MSG (1 << 7)
|
|
||||||
#define IRQ_MSG (1 << 8)
|
|
||||||
#define DMA_MSG (1 << 9)
|
|
||||||
|
|
||||||
#define ADCS6_MAX_DRIVES 4
|
#define ADCS6_MAX_DRIVES 4
|
||||||
#define ADCS6_ROM_SIZE (2 * 1024)
|
#define ADCS6_ROM_SIZE (2 * 1024)
|
||||||
|
@ -102,13 +96,8 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ
|
||||||
|
|
||||||
static t_stat adcs6_svc (UNIT *uptr);
|
static t_stat adcs6_svc (UNIT *uptr);
|
||||||
|
|
||||||
extern REG *sim_PC;
|
|
||||||
extern uint32 PCX; /* external view of PC */
|
extern uint32 PCX; /* external view of PC */
|
||||||
|
|
||||||
#define UNIT_V_ADCS6_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_ADCS6_WLK (1 << UNIT_V_ADCS6_WLK)
|
|
||||||
#define UNIT_V_ADCS6_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
|
||||||
#define UNIT_ADCS6_VERBOSE (1 << UNIT_V_ADCS6_VERBOSE)
|
|
||||||
#define UNIT_V_ADCS6_ROM (UNIT_V_UF + 2) /* boot ROM enabled */
|
#define UNIT_V_ADCS6_ROM (UNIT_V_UF + 2) /* boot ROM enabled */
|
||||||
#define UNIT_ADCS6_ROM (1 << UNIT_V_ADCS6_ROM)
|
#define UNIT_ADCS6_ROM (1 << UNIT_V_ADCS6_ROM)
|
||||||
#define ADCS6_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
#define ADCS6_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
||||||
|
@ -189,37 +178,32 @@ static UNIT adcs6_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG adcs6_reg[] = {
|
static REG adcs6_reg[] = {
|
||||||
{ HRDATA (J7, dipswitch, 8), },
|
{ HRDATAD (J7, dipswitch, 8, "5-position DIP switch on 64FDC card"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ADCS6_NAME "ADC Super-Six ADCS6"
|
||||||
|
|
||||||
static MTAB adcs6_mod[] = {
|
static MTAB adcs6_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
&set_membase, &show_membase, NULL, "Sets disk controller memory base address" },
|
||||||
{ UNIT_ADCS6_WLK, 0, "WRTENB", "WRTENB", NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_ADCS6_WLK, UNIT_ADCS6_WLK, "WRTLCK", "WRTLCK", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_ADCS6_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_ADCS6_ROM, 0, "NOROM", "NOROM",
|
||||||
/* verbose, show warning messages */
|
NULL, NULL, NULL, "Disables boot ROM for unit " ADCS6_NAME "n" },
|
||||||
{ UNIT_ADCS6_VERBOSE, UNIT_ADCS6_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_ADCS6_ROM, UNIT_ADCS6_ROM, "ROM", "ROM",
|
||||||
{ UNIT_ADCS6_ROM, 0, "NOROM", "NOROM", NULL },
|
NULL, NULL, NULL, "Enables boot ROM for unit " ADCS6_NAME "n" },
|
||||||
{ UNIT_ADCS6_ROM, UNIT_ADCS6_ROM, "ROM", "ROM", NULL },
|
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB adcs6_dt[] = {
|
static DEBTAB adcs6_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "DRIVE", DRIVE_MSG, "Drive messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "DMA", DMA_MSG, "DMA messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ NULL, 0 }
|
||||||
{ "STATUS", STATUS_MSG },
|
|
||||||
{ "DRIVE", DRIVE_MSG },
|
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
|
||||||
{ "IRQ", IRQ_MSG },
|
|
||||||
{ "DMA", DMA_MSG },
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE adcs6_dev = {
|
DEVICE adcs6_dev = {
|
||||||
|
@ -228,7 +212,7 @@ DEVICE adcs6_dev = {
|
||||||
NULL, NULL, &adcs6_reset,
|
NULL, NULL, &adcs6_reset,
|
||||||
&adcs6_boot, &adcs6_attach, &adcs6_detach,
|
&adcs6_boot, &adcs6_attach, &adcs6_detach,
|
||||||
&adcs6_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&adcs6_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
||||||
adcs6_dt, NULL, "ADC Super-Six ADCS6"
|
adcs6_dt, NULL, ADCS6_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is the DIGITEX Monitor version 1.2.A -- 10/06/83
|
/* This is the DIGITEX Monitor version 1.2.A -- 10/06/83
|
||||||
|
|
|
@ -59,14 +59,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define CMD_MSG (1 << 0)
|
||||||
#define SEEK_MSG (1 << 1)
|
#define RD_DATA_MSG (1 << 1)
|
||||||
#define CMD_MSG (1 << 2)
|
#define STATUS_MSG (1 << 2)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define VERBOSE_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
#define IRQ_MSG (1 << 4)
|
||||||
#define STATUS_MSG (1 << 5)
|
|
||||||
#define VERBOSE_MSG (1 << 7)
|
|
||||||
#define IRQ_MSG (1 << 8)
|
|
||||||
|
|
||||||
#define DISK1A_MAX_DRIVES 4
|
#define DISK1A_MAX_DRIVES 4
|
||||||
|
|
||||||
|
@ -88,13 +85,8 @@ extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_typ
|
||||||
|
|
||||||
extern void raise_ss1_interrupt(uint8 intnum);
|
extern void raise_ss1_interrupt(uint8 intnum);
|
||||||
|
|
||||||
extern REG *sim_PC;
|
|
||||||
extern uint32 PCX; /* external view of PC */
|
extern uint32 PCX; /* external view of PC */
|
||||||
|
|
||||||
#define UNIT_V_DISK1A_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_DISK1A_WLK (1 << UNIT_V_DISK1A_WLK)
|
|
||||||
#define UNIT_V_DISK1A_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
|
||||||
#define UNIT_DISK1A_VERBOSE (1 << UNIT_V_DISK1A_VERBOSE)
|
|
||||||
#define UNIT_V_DISK1A_ROM (UNIT_V_UF + 2) /* boot ROM enabled */
|
#define UNIT_V_DISK1A_ROM (UNIT_V_UF + 2) /* boot ROM enabled */
|
||||||
#define UNIT_DISK1A_ROM (1 << UNIT_V_DISK1A_ROM)
|
#define UNIT_DISK1A_ROM (1 << UNIT_V_DISK1A_ROM)
|
||||||
#define DISK1A_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
#define DISK1A_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
||||||
|
@ -127,35 +119,32 @@ static UNIT disk1a_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG disk1a_reg[] = {
|
static REG disk1a_reg[] = {
|
||||||
{ DRDATA (BOOTSTRAP, bootstrap, 10), },
|
{ DRDATAD (BOOTSTRAP, bootstrap, 10, "Bootstrap selector, 0 is default"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DISK1A_NAME "Compupro Floppy Controller DISK1A"
|
||||||
|
|
||||||
static MTAB disk1a_mod[] = {
|
static MTAB disk1a_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
&set_membase, &show_membase, NULL, "Sets disk controller memory base address" },
|
||||||
{ UNIT_DISK1A_WLK, 0, "WRTENB", "WRTENB", NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_DISK1A_WLK, UNIT_DISK1A_WLK, "WRTLCK", "WRTLCK", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
/* quiet, no warning messages */
|
{ UNIT_DISK1A_ROM, 0, "NOROM", "NOROM",
|
||||||
{ UNIT_DISK1A_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
NULL, NULL, NULL, "Disables boot ROM for unit " DISK1A_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
{ UNIT_DISK1A_ROM, UNIT_DISK1A_ROM, "ROM", "ROM",
|
||||||
{ UNIT_DISK1A_VERBOSE, UNIT_DISK1A_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
NULL, NULL, NULL, "Enables boot ROM for unit " DISK1A_NAME "n" },
|
||||||
{ UNIT_DISK1A_ROM, 0, "NOROM", "NOROM", NULL },
|
|
||||||
{ UNIT_DISK1A_ROM, UNIT_DISK1A_ROM, "ROM", "ROM", NULL },
|
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB disk1a_dt[] = {
|
static DEBTAB disk1a_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "RDDATA", RD_DATA_MSG, "Read data messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "IRQ", IRQ_MSG, "IRQ messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ NULL, 0 }
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
|
||||||
{ "IRQ", IRQ_MSG },
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE disk1a_dev = {
|
DEVICE disk1a_dev = {
|
||||||
|
@ -163,8 +152,8 @@ DEVICE disk1a_dev = {
|
||||||
DISK1A_MAX_DRIVES, 10, 31, 1, DISK1A_MAX_DRIVES, DISK1A_MAX_DRIVES,
|
DISK1A_MAX_DRIVES, 10, 31, 1, DISK1A_MAX_DRIVES, DISK1A_MAX_DRIVES,
|
||||||
NULL, NULL, &disk1a_reset,
|
NULL, NULL, &disk1a_reset,
|
||||||
&disk1a_boot, &disk1a_attach, &disk1a_detach,
|
&disk1a_boot, &disk1a_attach, &disk1a_detach,
|
||||||
&disk1a_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&disk1a_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 9,
|
||||||
disk1a_dt, NULL, "Compupro Floppy Controller DISK1A"
|
disk1a_dt, NULL, DISK1A_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This is the DISK1A Boot ROM.
|
/* This is the DISK1A Boot ROM.
|
||||||
|
|
|
@ -118,7 +118,6 @@ static int32 nsectors = C20MB_NSECTORS;
|
||||||
static int32 sectsize = C20MB_SECTSIZE;
|
static int32 sectsize = C20MB_SECTSIZE;
|
||||||
|
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern REG *sim_PC;
|
|
||||||
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
|
@ -127,8 +126,6 @@ extern int32 selchan_dma(uint8 *buf, uint32 len);
|
||||||
extern int32 find_unit_index(UNIT *uptr);
|
extern int32 find_unit_index(UNIT *uptr);
|
||||||
extern void raise_ss1_interrupt(uint8 intnum);
|
extern void raise_ss1_interrupt(uint8 intnum);
|
||||||
|
|
||||||
#define UNIT_V_DISK2_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_DISK2_WLK (1 << UNIT_V_DISK2_WLK)
|
|
||||||
#define UNIT_V_DISK2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_DISK2_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
#define UNIT_DISK2_VERBOSE (1 << UNIT_V_DISK2_VERBOSE)
|
#define UNIT_DISK2_VERBOSE (1 << UNIT_V_DISK2_VERBOSE)
|
||||||
#define DISK2_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */
|
#define DISK2_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */
|
||||||
|
@ -151,40 +148,51 @@ static UNIT disk2_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG disk2_reg[] = {
|
static REG disk2_reg[] = {
|
||||||
{ DRDATA (NTRACKS, ntracks, 10), },
|
{ DRDATAD (NTRACKS, ntracks, 10,
|
||||||
{ DRDATA (NHEADS, nheads, 8), },
|
"Number of tracks"), },
|
||||||
{ DRDATA (NSECTORS, nsectors, 8), },
|
{ DRDATAD (NHEADS, nheads, 8,
|
||||||
{ DRDATA (SECTSIZE, sectsize, 11), },
|
"Number of heads"), },
|
||||||
{ HRDATA (SEL_DRIVE, disk2_info_data.sel_drive, 3), },
|
{ DRDATAD (NSECTORS, nsectors, 8,
|
||||||
{ HRDATA (CYL, disk2_info_data.cyl, 8), },
|
"Number of sectors per track"), },
|
||||||
{ HRDATA (HEAD, disk2_info_data.head, 8), },
|
{ DRDATAD (SECTSIZE, sectsize, 11,
|
||||||
{ HRDATA (SECTOR, disk2_info_data.sector, 8), },
|
"Sector size not including pre/postamble"), },
|
||||||
|
{ HRDATAD (SEL_DRIVE, disk2_info_data.sel_drive, 3,
|
||||||
|
"Currently selected drive"), },
|
||||||
|
{ HRDATAD (CYL, disk2_info_data.cyl, 8,
|
||||||
|
"Cylinder that the current operation is targetting"), },
|
||||||
|
{ HRDATAD (HEAD, disk2_info_data.head, 8,
|
||||||
|
"Head that the current operation is targetting"), },
|
||||||
|
{ HRDATAD (SECTOR, disk2_info_data.sector, 8,
|
||||||
|
"Sector that the current operation is targetting"), },
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DISK2_NAME "Compupro Hard Disk Controller DISK2"
|
||||||
|
|
||||||
static MTAB disk2_mod[] = {
|
static MTAB disk2_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_DISK2_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_DISK2_WLK, UNIT_DISK2_WLK, "WRTLCK", "WRTLCK", NULL },
|
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_DISK2_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_DISK2_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " DISK2_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_DISK2_VERBOSE, UNIT_DISK2_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_DISK2_VERBOSE, UNIT_DISK2_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " DISK2_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB disk2_dt[] = {
|
static DEBTAB disk2_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "IRQ", IRQ_MSG },
|
{ "IRQ", IRQ_MSG, "IRQ messages" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE disk2_dev = {
|
DEVICE disk2_dev = {
|
||||||
|
@ -193,7 +201,7 @@ DEVICE disk2_dev = {
|
||||||
NULL, NULL, &disk2_reset,
|
NULL, NULL, &disk2_reset,
|
||||||
NULL, &disk2_attach, &disk2_detach,
|
NULL, &disk2_attach, &disk2_detach,
|
||||||
&disk2_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&disk2_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
||||||
disk2_dt, NULL, "Compupro Hard Disk Controller DISK2"
|
disk2_dt, NULL, DISK2_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Reset routine */
|
/* Reset routine */
|
||||||
|
|
|
@ -53,10 +53,9 @@
|
||||||
#define CMD_MSG (1 << 2)
|
#define CMD_MSG (1 << 2)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define RD_DATA_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
#define WR_DATA_MSG (1 << 4)
|
||||||
#define STATUS_MSG (1 << 5)
|
#define IRQ_MSG (1 << 5)
|
||||||
#define IRQ_MSG (1 << 6)
|
#define VERBOSE_MSG (1 << 6)
|
||||||
#define VERBOSE_MSG (1 << 7)
|
#define SPECIFY_MSG (1 << 7)
|
||||||
#define SPECIFY_MSG (1 << 8)
|
|
||||||
|
|
||||||
#define DISK3_MAX_DRIVES 4
|
#define DISK3_MAX_DRIVES 4
|
||||||
|
|
||||||
|
@ -176,7 +175,6 @@ static int32 nsectors = C20MB_NSECTORS;
|
||||||
static int32 sectsize = C20MB_SECTSIZE;
|
static int32 sectsize = C20MB_SECTSIZE;
|
||||||
|
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern REG *sim_PC;
|
|
||||||
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
|
@ -188,8 +186,6 @@ extern void raise_ss1_interrupt(uint8 intnum);
|
||||||
extern void PutByteDMA(const uint32 Addr, const uint32 Value);
|
extern void PutByteDMA(const uint32 Addr, const uint32 Value);
|
||||||
extern uint8 GetByteDMA(const uint32 Addr);
|
extern uint8 GetByteDMA(const uint32 Addr);
|
||||||
|
|
||||||
#define UNIT_V_DISK3_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_DISK3_WLK (1 << UNIT_V_DISK3_WLK)
|
|
||||||
#define UNIT_V_DISK3_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_DISK3_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
#define UNIT_DISK3_VERBOSE (1 << UNIT_V_DISK3_VERBOSE)
|
#define UNIT_DISK3_VERBOSE (1 << UNIT_V_DISK3_VERBOSE)
|
||||||
#define DISK3_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */
|
#define DISK3_CAPACITY (C20MB_NTRACKS*C20MB_NHEADS*C20MB_NSECTORS*C20MB_SECTSIZE) /* Default Disk Capacity */
|
||||||
|
@ -212,43 +208,56 @@ static UNIT disk3_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG disk3_reg[] = {
|
static REG disk3_reg[] = {
|
||||||
{ DRDATA (NTRACKS, ntracks, 10), },
|
{ DRDATAD (NTRACKS, ntracks, 10,
|
||||||
{ DRDATA (NHEADS, nheads, 8), },
|
"Number of tracks"), },
|
||||||
{ DRDATA (NSECTORS, nsectors, 8), },
|
{ DRDATAD (NHEADS, nheads, 8,
|
||||||
{ DRDATA (SECTSIZE, sectsize, 11), },
|
"Number of heads"), },
|
||||||
{ HRDATA (SEL_DRIVE, disk3_info_data.sel_drive, 3), },
|
{ DRDATAD (NSECTORS, nsectors, 8,
|
||||||
{ HRDATA (MODE, disk3_info_data.mode, 8), },
|
"Number of sectors per track"), },
|
||||||
{ HRDATA (RETRIES, disk3_info_data.retries, 8), },
|
{ DRDATAD (SECTSIZE, sectsize, 11,
|
||||||
{ HRDATA (NDRIVES, disk3_info_data.ndrives, 8), },
|
"Sector size not including pre/postamble"), },
|
||||||
{ HRDATA (LINK_ADDR, disk3_info_data.link_addr, 32), },
|
{ HRDATAD (SEL_DRIVE, disk3_info_data.sel_drive, 3,
|
||||||
{ HRDATA (DMA_ADDR, disk3_info_data.dma_addr, 32), },
|
"Currently selected drive"), },
|
||||||
{ BRDATA (IOPB, &disk3_info_data.iopb[DISK3_IOPB_CMD], 16, 8, 16), },
|
{ HRDATAD (MODE, disk3_info_data.mode, 8,
|
||||||
|
"Mode (0xFF=absolute, 0x00=logical)"), },
|
||||||
|
{ HRDATAD (RETRIES, disk3_info_data.retries, 8,
|
||||||
|
"Number of retries to attempt"), },
|
||||||
|
{ HRDATAD (NDRIVES, disk3_info_data.ndrives, 8,
|
||||||
|
"Number of drives attached to the controller"), },
|
||||||
|
{ HRDATAD (LINK_ADDR, disk3_info_data.link_addr, 32,
|
||||||
|
"Link address for next IOPB"), },
|
||||||
|
{ HRDATAD (DMA_ADDR, disk3_info_data.dma_addr, 32,
|
||||||
|
"DMA address for the current IOPB"), },
|
||||||
|
{ BRDATAD (IOPB, &disk3_info_data.iopb[DISK3_IOPB_CMD], 16, 8, 16,
|
||||||
|
"IOPB command register"), } ,
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define DISK3_NAME "Compupro ST-506 Disk Controller DISK3"
|
||||||
|
|
||||||
static MTAB disk3_mod[] = {
|
static MTAB disk3_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_DISK3_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_DISK3_WLK, UNIT_DISK3_WLK, "WRTLCK", "WRTLCK", NULL },
|
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_DISK3_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_DISK3_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " DISK3_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_DISK3_VERBOSE, UNIT_DISK3_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_DISK3_VERBOSE, UNIT_DISK3_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " DISK3_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB disk3_dt[] = {
|
static DEBTAB disk3_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ "IRQ", IRQ_MSG, "IRQ messages" },
|
||||||
{ "IRQ", IRQ_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ "SPECIFY", SPECIFY_MSG, "Specify messages" },
|
||||||
{ "SPECIFY",SPECIFY_MSG },
|
{ NULL, 0 }
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE disk3_dev = {
|
DEVICE disk3_dev = {
|
||||||
|
@ -257,7 +266,7 @@ DEVICE disk3_dev = {
|
||||||
NULL, NULL, &disk3_reset,
|
NULL, NULL, &disk3_reset,
|
||||||
NULL, &disk3_attach, &disk3_detach,
|
NULL, &disk3_attach, &disk3_detach,
|
||||||
&disk3_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&disk3_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
||||||
disk3_dt, NULL, "Compupro ST-506 Disk Controller DISK3"
|
disk3_dt, NULL, DISK3_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Reset routine */
|
/* Reset routine */
|
||||||
|
|
|
@ -31,8 +31,6 @@
|
||||||
|
|
||||||
#include "altairz80_defs.h"
|
#include "altairz80_defs.h"
|
||||||
|
|
||||||
#define UNIT_V_DSK_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_DSK_WLK (1 << UNIT_V_DSK_WLK)
|
|
||||||
#define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
#define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE)
|
#define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE)
|
||||||
#define DSK_SECTSIZE 137 /* size of sector */
|
#define DSK_SECTSIZE 137 /* size of sector */
|
||||||
|
@ -60,7 +58,6 @@ extern uint32 PCX;
|
||||||
current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */
|
current_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */
|
||||||
static int32 current_disk = NUM_OF_DSK;
|
static int32 current_disk = NUM_OF_DSK;
|
||||||
static int32 warnLevelDSK = 3;
|
static int32 warnLevelDSK = 3;
|
||||||
static int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
static int32 warnAttached [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
static int32 warnDSK11 = 0;
|
static int32 warnDSK11 = 0;
|
||||||
|
|
||||||
|
@ -84,23 +81,29 @@ static UNIT fif_unit[] = {
|
||||||
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }
|
{ UDATA (NULL, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FIF_NAME "IMSAI FIF"
|
||||||
|
|
||||||
static REG fif_reg[] = {
|
static REG fif_reg[] = {
|
||||||
{ DRDATA (DISK, current_disk, 4) },
|
{ DRDATAD (DISK, current_disk, 4,
|
||||||
{ DRDATA (DSKWL, warnLevelDSK, 32) },
|
"Current selected disk") },
|
||||||
{ BRDATA (WARNLOCK, warnLock, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
{ DRDATAD (DSKWL, warnLevelDSK, 32,
|
||||||
{ BRDATA (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK), REG_CIRC + REG_RO },
|
"Warn level register") },
|
||||||
{ DRDATA (WARNDSK11, warnDSK11, 4), REG_RO },
|
{ BRDATAD (WARNATTACHED, warnAttached, 10, 32, NUM_OF_DSK,
|
||||||
|
"Count for selection of unattached disk register array"), REG_CIRC + REG_RO },
|
||||||
|
{ DRDATAD (WARNDSK11, warnDSK11, 4,
|
||||||
|
"Count of IN/OUT(9) on unattached disk register"), REG_RO },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB fif_mod[] = {
|
static MTAB fif_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_DSK_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_DSK_WLK, UNIT_DSK_WLK, "WRTLCK", "WRTLCK", NULL },
|
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " FIF_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE", &fif_set_verbose },
|
{ UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
&fif_set_verbose, NULL, NULL, "Verbose messages for unit " FIF_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,15 +113,13 @@ DEVICE fif_dev = {
|
||||||
NULL, NULL, &fif_reset,
|
NULL, NULL, &fif_reset,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
&fif_info_data, (DEV_DISABLE | DEV_DIS), 0,
|
&fif_info_data, (DEV_DISABLE | DEV_DIS), 0,
|
||||||
NULL, NULL, "IMSAI FIF"
|
NULL, NULL, FIF_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
static void resetDSKWarningFlags(void) {
|
static void resetDSKWarningFlags(void) {
|
||||||
int32 i;
|
int32 i;
|
||||||
for (i = 0; i < NUM_OF_DSK; i++) {
|
for (i = 0; i < NUM_OF_DSK; i++)
|
||||||
warnLock[i] = 0;
|
warnAttached[i] = 0;
|
||||||
warnAttached[i] = 0;
|
|
||||||
}
|
|
||||||
warnDSK11 = 0;
|
warnDSK11 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,7 @@
|
||||||
#define CMD_MSG (1 << 2)
|
#define CMD_MSG (1 << 2)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define RD_DATA_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
#define WR_DATA_MSG (1 << 4)
|
||||||
#define STATUS_MSG (1 << 5)
|
#define VERBOSE_MSG (1 << 5)
|
||||||
#define VERBOSE_MSG (1 << 7)
|
|
||||||
|
|
||||||
#define HDC1001_MAX_DRIVES 4
|
#define HDC1001_MAX_DRIVES 4
|
||||||
|
|
||||||
|
@ -96,7 +95,6 @@ static HDC1001_INFO hdc1001_info_data = { { 0x0, 0, 0xC8, 8 } };
|
||||||
static HDC1001_INFO *hdc1001_info = &hdc1001_info_data;
|
static HDC1001_INFO *hdc1001_info = &hdc1001_info_data;
|
||||||
|
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern REG *sim_PC;
|
|
||||||
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
extern t_stat set_iobase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
|
@ -107,8 +105,6 @@ extern int32 find_unit_index(UNIT *uptr);
|
||||||
extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
|
extern void PutBYTEWrapper(const uint32 Addr, const uint32 Value);
|
||||||
extern uint8 GetBYTEWrapper(const uint32 Addr);
|
extern uint8 GetBYTEWrapper(const uint32 Addr);
|
||||||
|
|
||||||
#define UNIT_V_HDC1001_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_HDC1001_WLK (1 << UNIT_V_HDC1001_WLK)
|
|
||||||
#define UNIT_V_HDC1001_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_HDC1001_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
#define UNIT_HDC1001_VERBOSE (1 << UNIT_V_HDC1001_VERBOSE)
|
#define UNIT_HDC1001_VERBOSE (1 << UNIT_V_HDC1001_VERBOSE)
|
||||||
#define HDC1001_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
#define HDC1001_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
||||||
|
@ -133,27 +129,29 @@ static REG hdc1001_reg[] = {
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define HDC1001_NAME "ADC Hard Disk Controller HDC1001"
|
||||||
|
|
||||||
static MTAB hdc1001_mod[] = {
|
static MTAB hdc1001_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_HDC1001_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_HDC1001_WLK, UNIT_HDC1001_WLK, "WRTLCK", "WRTLCK", NULL },
|
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_HDC1001_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_HDC1001_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " HDC1001_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_HDC1001_VERBOSE, UNIT_HDC1001_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_HDC1001_VERBOSE, UNIT_HDC1001_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " HDC1001_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB hdc1001_dt[] = {
|
static DEBTAB hdc1001_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ NULL, 0 }
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE hdc1001_dev = {
|
DEVICE hdc1001_dev = {
|
||||||
|
@ -162,7 +160,7 @@ DEVICE hdc1001_dev = {
|
||||||
NULL, NULL, &hdc1001_reset,
|
NULL, NULL, &hdc1001_reset,
|
||||||
NULL, &hdc1001_attach, &hdc1001_detach,
|
NULL, &hdc1001_attach, &hdc1001_detach,
|
||||||
&hdc1001_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&hdc1001_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
||||||
hdc1001_dt, NULL, "ADC Hard Disk Controller HDC1001"
|
hdc1001_dt, NULL, HDC1001_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Reset routine */
|
/* Reset routine */
|
||||||
|
|
|
@ -58,11 +58,10 @@
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define ERROR_MSG (1 << 0)
|
||||||
#define TRACE_MSG (1 << 1)
|
#define RXIRQ_MSG (1 << 1)
|
||||||
#define RXIRQ_MSG (1 << 2)
|
#define TXIRQ_MSG (1 << 2)
|
||||||
#define TXIRQ_MSG (1 << 3)
|
#define UART_MSG (1 << 3)
|
||||||
#define UART_MSG (1 << 4)
|
#define USER_MSG (1 << 4)
|
||||||
#define USER_MSG (1 << 5)
|
|
||||||
|
|
||||||
#define IF3_MAX_BOARDS 4
|
#define IF3_MAX_BOARDS 4
|
||||||
|
|
||||||
|
@ -110,31 +109,35 @@ static uint8 if3_risr[IF3_MAX_BOARDS] = { 0, 0, 0, 0 };
|
||||||
static uint8 if3_tisr[IF3_MAX_BOARDS] = { 0, 0, 0, 0 };
|
static uint8 if3_tisr[IF3_MAX_BOARDS] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
static REG if3_reg[] = {
|
static REG if3_reg[] = {
|
||||||
{ HRDATA (USER, if3_user, 3), },
|
{ HRDATAD (USER, if3_user, 3, "IF3 user register"), },
|
||||||
{ HRDATA (BOARD, if3_board, 2), },
|
{ HRDATAD (BOARD, if3_board, 2, "IF3 board register"), },
|
||||||
{ BRDATA (RIMR, &if3_rimr[0], 16, 8, 4), },
|
{ BRDATAD (RIMR, &if3_rimr[0], 16, 8, 4, "IF3 RIMR register array"), },
|
||||||
{ BRDATA (RISR, &if3_risr[0], 16, 8, 4), },
|
{ BRDATAD (RISR, &if3_risr[0], 16, 8, 4, "IF3 RISR register array"), },
|
||||||
{ BRDATA (TIMR, &if3_timr[0], 16, 8, 4), },
|
{ BRDATAD (TIMR, &if3_timr[0], 16, 8, 4, "IF3 TIMR register array"), },
|
||||||
{ BRDATA (TISR, &if3_tisr[0], 16, 8, 4), },
|
{ BRDATAD (TISR, &if3_tisr[0], 16, 8, 4, "IF3 TISR register array"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define IF3_NAME "Compupro Interfacer 3 IF3"
|
||||||
|
|
||||||
static MTAB if3_mod[] = {
|
static MTAB if3_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_IF3_CONNECT, UNIT_IF3_CONNECT,"INSTALLED", "INSTALLED", &set_if3_connect, NULL, NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_IF3_CONNECT, 0, "UNINSTALLED","UNINSTALLED", &set_if3_connect, NULL, NULL },
|
{ UNIT_IF3_CONNECT, UNIT_IF3_CONNECT,"INSTALLED", "INSTALLED",
|
||||||
|
&set_if3_connect, NULL, NULL, "Installs board for unit " IF3_NAME "n" },
|
||||||
|
{ UNIT_IF3_CONNECT, 0, "UNINSTALLED","UNINSTALLED",
|
||||||
|
&set_if3_connect, NULL, NULL, "Uninstalls board for unit " IF3_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB if3_dt[] = {
|
static DEBTAB if3_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "TRACE", TRACE_MSG },
|
{ "RXIRQ", RXIRQ_MSG, "RX IRQ messages" },
|
||||||
{ "RXIRQ", RXIRQ_MSG },
|
{ "TXIRQ", TXIRQ_MSG, "TX IRQ messages" },
|
||||||
{ "TXIRQ", TXIRQ_MSG },
|
{ "UART", UART_MSG, "UART messages" },
|
||||||
{ "UART", UART_MSG },
|
{ "USER", USER_MSG, "User messages" },
|
||||||
{ "USER", USER_MSG },
|
{ NULL, 0 }
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE if3_dev = {
|
DEVICE if3_dev = {
|
||||||
|
@ -143,7 +146,7 @@ DEVICE if3_dev = {
|
||||||
NULL, NULL, &if3_reset,
|
NULL, NULL, &if3_reset,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
&if3_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
&if3_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
||||||
if3_dt, NULL, "Compupro Interfacer 3 IF3"
|
if3_dt, NULL, IF3_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
static t_stat set_if3_connect(UNIT *uptr, int32 val, char *cptr, void *desc)
|
static t_stat set_if3_connect(UNIT *uptr, int32 val, char *cptr, void *desc)
|
||||||
|
|
|
@ -54,11 +54,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define SEEK_MSG (1 << 0)
|
||||||
#define SEEK_MSG (1 << 1)
|
#define RD_DATA_MSG (1 << 1)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define WR_DATA_MSG (1 << 2)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
#define VERBOSE_MSG (1 << 3)
|
||||||
#define VERBOSE_MSG (1 << 7)
|
|
||||||
|
|
||||||
#define MDRIVEH_MAX_DRIVES 8
|
#define MDRIVEH_MAX_DRIVES 8
|
||||||
|
|
||||||
|
@ -78,8 +77,6 @@ extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
||||||
|
|
||||||
extern REG *sim_PC;
|
|
||||||
|
|
||||||
#define UNIT_V_MDRIVEH_WLK (UNIT_V_UF + 0) /* write locked */
|
#define UNIT_V_MDRIVEH_WLK (UNIT_V_UF + 0) /* write locked */
|
||||||
#define UNIT_MDRIVEH_WLK (1 << UNIT_V_MDRIVEH_WLK)
|
#define UNIT_MDRIVEH_WLK (1 << UNIT_V_MDRIVEH_WLK)
|
||||||
#define UNIT_V_MDRIVEH_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_MDRIVEH_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
|
@ -107,25 +104,33 @@ static REG mdriveh_reg[] = {
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MDRIVEH_NAME "Compupro Memory Drive MDRIVEH"
|
||||||
|
|
||||||
static MTAB mdriveh_mod[] = {
|
static MTAB mdriveh_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_MDRIVEH_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_MDRIVEH_WLK, UNIT_MDRIVEH_WLK, "WRTLCK", "WRTLCK", NULL },
|
{ UNIT_MDRIVEH_WLK, 0, "WRTENB", "WRTENB",
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
"Enables " MDRIVEH_NAME "n for writing" },
|
||||||
|
{ UNIT_MDRIVEH_WLK, UNIT_MDRIVEH_WLK, "WRTLCK", "WRTLCK",
|
||||||
|
NULL, NULL, NULL,
|
||||||
|
"Locks " MDRIVEH_NAME "n for writing" },
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_MDRIVEH_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_MDRIVEH_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " MDRIVEH_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_MDRIVEH_VERBOSE, UNIT_MDRIVEH_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_MDRIVEH_VERBOSE, UNIT_MDRIVEH_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " MDRIVEH_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB mdriveh_dt[] = {
|
static DEBTAB mdriveh_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ NULL, 0 }
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE mdriveh_dev = {
|
DEVICE mdriveh_dev = {
|
||||||
|
@ -133,8 +138,8 @@ DEVICE mdriveh_dev = {
|
||||||
MDRIVEH_MAX_DRIVES, 10, 31, 1, MDRIVEH_MAX_DRIVES, MDRIVEH_MAX_DRIVES,
|
MDRIVEH_MAX_DRIVES, 10, 31, 1, MDRIVEH_MAX_DRIVES, MDRIVEH_MAX_DRIVES,
|
||||||
NULL, NULL, &mdriveh_reset,
|
NULL, NULL, &mdriveh_reset,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
&mdriveh_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&mdriveh_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
||||||
mdriveh_dt, NULL, "Compupro Memory Drive MDRIVEH"
|
mdriveh_dt, NULL, MDRIVEH_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,23 +55,21 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define ERROR_MSG (1 << 0)
|
||||||
#define SEEK_MSG (1 << 1)
|
#define SEEK_MSG (1 << 1)
|
||||||
#define CMD_MSG (1 << 2)
|
#define CMD_MSG (1 << 2)
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define RD_DATA_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
#define WR_DATA_MSG (1 << 4)
|
||||||
#define STATUS_MSG (1 << 5)
|
#define STATUS_MSG (1 << 5)
|
||||||
#define ORDERS_MSG (1 << 6)
|
#define ORDERS_MSG (1 << 6)
|
||||||
#define VERBOSE_MSG (1 << 7)
|
#define RD_DATA_DETAIL_MSG (1 << 7)
|
||||||
#define RD_DATA_DETAIL_MSG (1 << 8)
|
#define WR_DATA_DETAIL_MSG (1 << 8)
|
||||||
#define WR_DATA_DETAIL_MSG (1 << 9)
|
|
||||||
|
|
||||||
extern uint32 PCX;
|
extern uint32 PCX;
|
||||||
extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
extern t_stat set_membase(UNIT *uptr, int32 val, char *cptr, void *desc);
|
||||||
extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
extern t_stat show_membase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
||||||
extern REG *sim_PC;
|
|
||||||
|
|
||||||
#define MDSAD_MAX_DRIVES 4
|
#define MDSAD_MAX_DRIVES 4
|
||||||
#define MDSAD_SECTOR_LEN 512
|
#define MDSAD_SECTOR_LEN 512
|
||||||
|
@ -156,8 +154,6 @@ static MDSAD_INFO *mdsad_info = &mdsad_info_data;
|
||||||
|
|
||||||
static SECTOR_FORMAT sdata;
|
static SECTOR_FORMAT sdata;
|
||||||
|
|
||||||
#define UNIT_V_MDSAD_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_MDSAD_WLK (1 << UNIT_V_MDSAD_WLK)
|
|
||||||
#define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_MDSAD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
#define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE)
|
#define UNIT_MDSAD_VERBOSE (1 << UNIT_V_MDSAD_VERBOSE)
|
||||||
#define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN) /* Default North Star Disk Capacity */
|
#define MDSAD_CAPACITY (70*10*MDSAD_SECTOR_LEN) /* Default North Star Disk Capacity */
|
||||||
|
@ -232,30 +228,32 @@ static REG mdsad_reg[] = {
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MDSAD_NAME "North Star Floppy Controller MDSAD"
|
||||||
|
|
||||||
static MTAB mdsad_mod[] = {
|
static MTAB mdsad_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
|
||||||
{ UNIT_MDSAD_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_membase, &show_membase, NULL, "Sets disk controller memory base address" },
|
||||||
{ UNIT_MDSAD_WLK, UNIT_MDSAD_WLK, "WRTLCK", "WRTLCK", NULL },
|
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_MDSAD_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_MDSAD_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " MDSAD_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_MDSAD_VERBOSE, UNIT_MDSAD_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_MDSAD_VERBOSE, UNIT_MDSAD_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " MDSAD_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB mdsad_dt[] = {
|
static DEBTAB mdsad_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "ORDERS", ORDERS_MSG },
|
{ "ORDERS", ORDERS_MSG, "Orders messages" },
|
||||||
{ "RDDETAIL", RD_DATA_DETAIL_MSG },
|
{ "RDDETAIL", RD_DATA_DETAIL_MSG, "Read detail messages" },
|
||||||
{ "WRDETAIL", WR_DATA_DETAIL_MSG },
|
{ "WRDETAIL", WR_DATA_DETAIL_MSG, "Write detail messags" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ NULL, 0 }
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE mdsad_dev = {
|
DEVICE mdsad_dev = {
|
||||||
|
|
|
@ -54,13 +54,9 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define UART_MSG (1 << 0)
|
||||||
#define PIO_MSG (1 << 1)
|
#define ROM_MSG (1 << 1)
|
||||||
#define UART_MSG (1 << 2)
|
#define VERBOSE_MSG (1 << 2)
|
||||||
#define RTC_MSG (1 << 3)
|
|
||||||
#define ROM_MSG (1 << 5)
|
|
||||||
#define VERBOSE_MSG (1 << 7)
|
|
||||||
#define IRQ_MSG (1 << 8)
|
|
||||||
|
|
||||||
#define SCP300F_MAX_DRIVES 1
|
#define SCP300F_MAX_DRIVES 1
|
||||||
#define SCP300F_ROM_SIZE (2048)
|
#define SCP300F_ROM_SIZE (2048)
|
||||||
|
@ -69,9 +65,6 @@
|
||||||
#define SCP300F_IO_SIZE (16)
|
#define SCP300F_IO_SIZE (16)
|
||||||
#define SCP300F_IO_MASK (SCP300F_IO_SIZE - 1)
|
#define SCP300F_IO_MASK (SCP300F_IO_SIZE - 1)
|
||||||
|
|
||||||
#define UNIT_V_SCP300F_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
|
||||||
#define UNIT_SCP300F_VERBOSE (1 << UNIT_V_SCP300F_VERBOSE)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PNP_INFO pnp; /* Plug and Play */
|
PNP_INFO pnp; /* Plug and Play */
|
||||||
uint8 *ram;
|
uint8 *ram;
|
||||||
|
@ -106,30 +99,24 @@ static UNIT scp300f_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG scp300f_reg[] = {
|
static REG scp300f_reg[] = {
|
||||||
{ HRDATA (SR, scp300f_sr, 8), },
|
{ HRDATAD (SR, scp300f_sr, 8, "Sense switch register, 0=monitor prompt, 1=disk boot"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB scp300f_mod[] = {
|
static MTAB scp300f_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE", &set_membase, &show_membase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "MEMBASE", "MEMBASE",
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
&set_membase, &show_membase, NULL, "Sets support module memory base address" },
|
||||||
/* quiet, no warning messages */
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_SCP300F_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets support module I/O base address" },
|
||||||
/* verbose, show warning messages */
|
|
||||||
{ UNIT_SCP300F_VERBOSE, UNIT_SCP300F_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB scp300f_dt[] = {
|
static DEBTAB scp300f_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "UART", UART_MSG, "UART messages" },
|
||||||
{ "PIO", PIO_MSG },
|
{ "ROM", ROM_MSG, "ROM messages" },
|
||||||
{ "UART", UART_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "RTC", RTC_MSG },
|
{ NULL, 0 }
|
||||||
{ "ROM", ROM_MSG },
|
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
|
||||||
{ "IRQ", IRQ_MSG },
|
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,7 +125,7 @@ DEVICE scp300f_dev = {
|
||||||
SCP300F_MAX_DRIVES, 10, 31, 1, SCP300F_MAX_DRIVES, SCP300F_MAX_DRIVES,
|
SCP300F_MAX_DRIVES, 10, 31, 1, SCP300F_MAX_DRIVES, SCP300F_MAX_DRIVES,
|
||||||
NULL, NULL, &scp300f_reset,
|
NULL, NULL, &scp300f_reset,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
&scp300f_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&scp300f_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
||||||
scp300f_dt, NULL, "SCP Support Board SCP300F"
|
scp300f_dt, NULL, "SCP Support Board SCP300F"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -54,15 +54,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Debug flags */
|
/* Debug flags */
|
||||||
#define ERROR_MSG (1 << 0)
|
#define VERBOSE_MSG (1 << 0)
|
||||||
#define VERBOSE_MSG (1 << 1)
|
#define DMA_MSG (1 << 1)
|
||||||
#define DMA_MSG (1 << 2)
|
|
||||||
|
|
||||||
#define SELCHAN_MAX_DRIVES 1
|
#define SELCHAN_MAX_DRIVES 1
|
||||||
|
|
||||||
#define UNIT_V_SELCHAN_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
|
||||||
#define UNIT_SELCHAN_VERBOSE (1 << UNIT_V_SELCHAN_VERBOSE)
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PNP_INFO pnp; /* Plug and Play */
|
PNP_INFO pnp; /* Plug and Play */
|
||||||
uint32 selchan; /* Selector Channel Register */
|
uint32 selchan; /* Selector Channel Register */
|
||||||
|
@ -95,26 +91,22 @@ static UNIT selchan_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG selchan_reg[] = {
|
static REG selchan_reg[] = {
|
||||||
{ HRDATA (DMA_MODE, selchan_info_data.dma_mode, 8), },
|
{ HRDATAD (DMA_MODE, selchan_info_data.dma_mode, 8, "DMA mode register"), },
|
||||||
{ HRDATA (DMA_ADDR, selchan_info_data.dma_addr, 24), },
|
{ HRDATAD (DMA_ADDR, selchan_info_data.dma_addr, 24, "DMA transfer address register"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB selchan_mod[] = {
|
static MTAB selchan_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL,
|
||||||
/* quiet, no warning messages */
|
"Sets disk controller I/O base address" },
|
||||||
{ UNIT_SELCHAN_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
|
||||||
/* verbose, show warning messages */
|
|
||||||
{ UNIT_SELCHAN_VERBOSE, UNIT_SELCHAN_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB selchan_dt[] = {
|
static DEBTAB selchan_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ "DMA", DMA_MSG, "DMA messages" },
|
||||||
{ "DMA", DMA_MSG },
|
{ NULL, 0 }
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE selchan_dev = {
|
DEVICE selchan_dev = {
|
||||||
|
@ -122,7 +114,7 @@ DEVICE selchan_dev = {
|
||||||
SELCHAN_MAX_DRIVES, 10, 31, 1, SELCHAN_MAX_DRIVES, SELCHAN_MAX_DRIVES,
|
SELCHAN_MAX_DRIVES, 10, 31, 1, SELCHAN_MAX_DRIVES, SELCHAN_MAX_DRIVES,
|
||||||
NULL, NULL, &selchan_reset,
|
NULL, NULL, &selchan_reset,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
&selchan_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&selchan_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), 0,
|
||||||
selchan_dt, NULL, "Compupro Selector Channel SELCHAN"
|
selchan_dt, NULL, "Compupro Selector Channel SELCHAN"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -177,47 +177,48 @@ static UNIT ss1_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG ss1_reg[] = {
|
static REG ss1_reg[] = {
|
||||||
{ HRDATA (MPIC_IMR, ss1_pic[MASTER_PIC].IMR, 8), },
|
{ HRDATAD (MPIC_IMR, ss1_pic[MASTER_PIC].IMR, 8, "Master IMR register"), },
|
||||||
{ HRDATA (MPIC_IRR, ss1_pic[MASTER_PIC].IRR, 8), },
|
{ HRDATAD (MPIC_IRR, ss1_pic[MASTER_PIC].IRR, 8, "Master IRR register"), },
|
||||||
{ HRDATA (MPIC_ISR, ss1_pic[MASTER_PIC].ISR, 8), },
|
{ HRDATAD (MPIC_ISR, ss1_pic[MASTER_PIC].ISR, 8, "Master ISR register"), },
|
||||||
{ HRDATA (MPIC_OCW2, ss1_pic[MASTER_PIC].OCW2, 8), },
|
{ HRDATAD (MPIC_OCW2, ss1_pic[MASTER_PIC].OCW2, 8, "Master OCW2 register"), },
|
||||||
{ HRDATA (MPIC_OCW3, ss1_pic[MASTER_PIC].OCW3, 8), },
|
{ HRDATAD (MPIC_OCW3, ss1_pic[MASTER_PIC].OCW3, 8, "Master OCW3 register"), },
|
||||||
|
|
||||||
{ HRDATA (SPIC_IMR, ss1_pic[SLAVE_PIC].IMR, 8), },
|
{ HRDATAD (SPIC_IMR, ss1_pic[SLAVE_PIC].IMR, 8, "Slave IMR register"), },
|
||||||
{ HRDATA (SPIC_IRR, ss1_pic[SLAVE_PIC].IRR, 8), },
|
{ HRDATAD (SPIC_IRR, ss1_pic[SLAVE_PIC].IRR, 8, "Slave IRR register"), },
|
||||||
{ HRDATA (SPIC_ISR, ss1_pic[SLAVE_PIC].ISR, 8), },
|
{ HRDATAD (SPIC_ISR, ss1_pic[SLAVE_PIC].ISR, 8, "Slave ISR register"), },
|
||||||
{ HRDATA (SPIC_OCW2, ss1_pic[SLAVE_PIC].OCW2, 8), },
|
{ HRDATAD (SPIC_OCW2, ss1_pic[SLAVE_PIC].OCW2, 8, "Slave OCW2 register"), },
|
||||||
{ HRDATA (SPIC_OCW3, ss1_pic[SLAVE_PIC].OCW3, 8), },
|
{ HRDATAD (SPIC_OCW3, ss1_pic[SLAVE_PIC].OCW3, 8, "Slave OCW3 register"), },
|
||||||
|
|
||||||
{ HRDATA (T0_MODE, ss1_tc[0].mode, 3), },
|
{ HRDATAD (T0_MODE, ss1_tc[0].mode, 3, "Timer 0 mode register"), },
|
||||||
{ HRDATA (T0_COUNT, ss1_tc[0].count, 16), },
|
{ HRDATAD (T0_COUNT, ss1_tc[0].count, 16, "Timer 0 count register"), },
|
||||||
{ HRDATA (T1_MODE, ss1_tc[1].mode, 3), },
|
{ HRDATAD (T1_MODE, ss1_tc[1].mode, 3, "Timer 1 mode register"), },
|
||||||
{ HRDATA (T1_COUNT, ss1_tc[1].count, 16), },
|
{ HRDATAD (T1_COUNT, ss1_tc[1].count, 16, "Timer 1 count register"), },
|
||||||
{ HRDATA (T2_MODE, ss1_tc[2].mode, 3), },
|
{ HRDATAD (T2_MODE, ss1_tc[2].mode, 3, "Timer 2 mode register"), },
|
||||||
{ HRDATA (T2_COUNT, ss1_tc[2].count, 16), },
|
{ HRDATAD (T2_COUNT, ss1_tc[2].count, 16, "Timer 2 count register"), },
|
||||||
|
|
||||||
{ HRDATA (RTC_DIGIT, ss1_rtc[0].digit_sel, 4), },
|
{ HRDATAD (RTC_DIGIT, ss1_rtc[0].digit_sel, 4, "Digit selector register"), },
|
||||||
{ HRDATA (RTC_FLAGS, ss1_rtc[0].flags, 4), },
|
{ HRDATAD (RTC_FLAGS, ss1_rtc[0].flags, 4, "Flags register"), },
|
||||||
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static MTAB ss1_mod[] = {
|
static MTAB ss1_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
|
&set_iobase, &show_iobase, NULL, "Sets system support module base address" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB ss1_dt[] = {
|
static DEBTAB ss1_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "TRACE", TRACE_MSG },
|
{ "TRACE", TRACE_MSG, "Trace messages" },
|
||||||
{ "PIC", PIC_MSG },
|
{ "PIC", PIC_MSG, "PIC messages" },
|
||||||
{ "TC", TC_MSG },
|
{ "TC", TC_MSG, "TC messages" },
|
||||||
{ "RTC", RTC_MSG },
|
{ "RTC", RTC_MSG, "RTC messages" },
|
||||||
{ "MATH", MATH_MSG },
|
{ "MATH", MATH_MSG, "Math messages" },
|
||||||
{ "UART", UART_MSG },
|
{ "UART", UART_MSG, "UART messages" },
|
||||||
{ "IRQ", IRQ_MSG },
|
{ "IRQ", IRQ_MSG, "IRQ messages" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE ss1_dev = {
|
DEVICE ss1_dev = {
|
||||||
|
|
|
@ -65,7 +65,6 @@
|
||||||
#define RD_DATA_MSG (1 << 3)
|
#define RD_DATA_MSG (1 << 3)
|
||||||
#define WR_DATA_MSG (1 << 4)
|
#define WR_DATA_MSG (1 << 4)
|
||||||
#define STATUS_MSG (1 << 5)
|
#define STATUS_MSG (1 << 5)
|
||||||
#define ORDERS_MSG (1 << 7)
|
|
||||||
|
|
||||||
static void VFDHD_Command(void);
|
static void VFDHD_Command(void);
|
||||||
|
|
||||||
|
@ -141,8 +140,6 @@ extern t_stat show_iobase(FILE *st, UNIT *uptr, int32 val, void *desc);
|
||||||
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
extern uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
|
||||||
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
int32 (*routine)(const int32, const int32, const int32), uint8 unmap);
|
||||||
|
|
||||||
#define UNIT_V_VFDHD_WLK (UNIT_V_UF + 0) /* write locked */
|
|
||||||
#define UNIT_VFDHD_WLK (1 << UNIT_V_VFDHD_WLK)
|
|
||||||
#define UNIT_V_VFDHD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
#define UNIT_V_VFDHD_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
|
||||||
#define UNIT_VFDHD_VERBOSE (1 << UNIT_V_VFDHD_VERBOSE)
|
#define UNIT_VFDHD_VERBOSE (1 << UNIT_V_VFDHD_VERBOSE)
|
||||||
#define VFDHD_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
#define VFDHD_CAPACITY (77*2*16*256) /* Default Micropolis Disk Capacity */
|
||||||
|
@ -166,31 +163,33 @@ static UNIT vfdhd_unit[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static REG vfdhd_reg[] = {
|
static REG vfdhd_reg[] = {
|
||||||
{ DRDATA (HDSIZE, hdSize, 10), },
|
{ DRDATAD (HDSIZE, hdSize, 10, "Size register"), },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define VFDHD_NAME "Vector Graphic FD-HD Controller VFDHD"
|
||||||
|
|
||||||
static MTAB vfdhd_mod[] = {
|
static MTAB vfdhd_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_VFDHD_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_VFDHD_WLK, UNIT_VFDHD_WLK, "WRTLCK", "WRTLCK", NULL },
|
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_VFDHD_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_VFDHD_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " VFDHD_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_VFDHD_VERBOSE, UNIT_VFDHD_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_VFDHD_VERBOSE, UNIT_VFDHD_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " VFDHD_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB vfdhd_dt[] = {
|
static DEBTAB vfdhd_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "ORDERS", ORDERS_MSG },
|
{ NULL, 0 }
|
||||||
{ NULL, 0 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE vfdhd_dev = {
|
DEVICE vfdhd_dev = {
|
||||||
|
@ -199,7 +198,7 @@ DEVICE vfdhd_dev = {
|
||||||
NULL, NULL, &vfdhd_reset,
|
NULL, NULL, &vfdhd_reset,
|
||||||
NULL, &vfdhd_attach, &vfdhd_detach,
|
NULL, &vfdhd_attach, &vfdhd_detach,
|
||||||
&vfdhd_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&vfdhd_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
||||||
vfdhd_dt, NULL, "Vector Graphic FD-HD Controller VFDHD"
|
vfdhd_dt, NULL, VFDHD_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Reset routine */
|
/* Reset routine */
|
||||||
|
|
|
@ -208,28 +208,35 @@ static UNIT wd179x_unit[] = {
|
||||||
{ UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }
|
{ UDATA (&wd179x_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, WD179X_CAPACITY), 58200 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define WD179X_NAME "Western Digital FDC Core WD179X"
|
||||||
|
|
||||||
static MTAB wd179x_mod[] = {
|
static MTAB wd179x_mod[] = {
|
||||||
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE", &set_iobase, &show_iobase, NULL },
|
{ MTAB_XTD|MTAB_VDV, 0, "IOBASE", "IOBASE",
|
||||||
{ UNIT_WD179X_WLK, 0, "WRTENB", "WRTENB", NULL },
|
&set_iobase, &show_iobase, NULL, "Sets disk controller I/O base address" },
|
||||||
{ UNIT_WD179X_WLK, UNIT_WD179X_WLK, "WRTLCK", "WRTLCK", NULL },
|
{ UNIT_WD179X_WLK, 0, "WRTENB", "WRTENB",
|
||||||
|
NULL, NULL, NULL, "Enables " WD179X_NAME "n for writing" },
|
||||||
|
{ UNIT_WD179X_WLK, UNIT_WD179X_WLK, "WRTLCK", "WRTLCK",
|
||||||
|
NULL, NULL, NULL, "Locks " WD179X_NAME "n for writing" },
|
||||||
/* quiet, no warning messages */
|
/* quiet, no warning messages */
|
||||||
{ UNIT_WD179X_VERBOSE, 0, "QUIET", "QUIET", NULL },
|
{ UNIT_WD179X_VERBOSE, 0, "QUIET", "QUIET",
|
||||||
|
NULL, NULL, NULL, "No verbose messages for unit " WD179X_NAME "n" },
|
||||||
/* verbose, show warning messages */
|
/* verbose, show warning messages */
|
||||||
{ UNIT_WD179X_VERBOSE, UNIT_WD179X_VERBOSE, "VERBOSE", "VERBOSE", NULL },
|
{ UNIT_WD179X_VERBOSE, UNIT_WD179X_VERBOSE, "VERBOSE", "VERBOSE",
|
||||||
|
NULL, NULL, NULL, "Verbose messages for unit " WD179X_NAME "n" },
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug Flags */
|
/* Debug Flags */
|
||||||
static DEBTAB wd179x_dt[] = {
|
static DEBTAB wd179x_dt[] = {
|
||||||
{ "ERROR", ERROR_MSG },
|
{ "ERROR", ERROR_MSG, "Error messages" },
|
||||||
{ "SEEK", SEEK_MSG },
|
{ "SEEK", SEEK_MSG, "Seek messages" },
|
||||||
{ "CMD", CMD_MSG },
|
{ "CMD", CMD_MSG, "Command messages" },
|
||||||
{ "RDDATA", RD_DATA_MSG },
|
{ "READ", RD_DATA_MSG, "Read messages" },
|
||||||
{ "WRDATA", WR_DATA_MSG },
|
{ "WRITE", WR_DATA_MSG, "Write messages" },
|
||||||
{ "STATUS", STATUS_MSG },
|
{ "STATUS", STATUS_MSG, "Status messages" },
|
||||||
{ "FMT", FMT_MSG },
|
{ "FMT", FMT_MSG, "Format messages" },
|
||||||
{ "VERBOSE",VERBOSE_MSG },
|
{ "VERBOSE", VERBOSE_MSG, "Verbose messages" },
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE wd179x_dev = {
|
DEVICE wd179x_dev = {
|
||||||
|
@ -238,7 +245,7 @@ DEVICE wd179x_dev = {
|
||||||
NULL, NULL, &wd179x_reset,
|
NULL, NULL, &wd179x_reset,
|
||||||
NULL, &wd179x_attach, &wd179x_detach,
|
NULL, &wd179x_attach, &wd179x_detach,
|
||||||
&wd179x_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
&wd179x_info_data, (DEV_DISABLE | DEV_DIS | DEV_DEBUG), ERROR_MSG,
|
||||||
wd179x_dt, NULL, "Western Digital FDC Core WD179X"
|
wd179x_dt, NULL, WD179X_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Unit service routine */
|
/* Unit service routine */
|
||||||
|
|
|
@ -201,6 +201,41 @@
|
||||||
RelativePath="..\AltairZ80\altairz80_mhdsk.c"
|
RelativePath="..\AltairZ80\altairz80_mhdsk.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\AltairZ80\m68kcpu.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
|
||||||
|
<File
|
||||||
|
RelativePath="..\AltairZ80\m68kdasm.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
|
||||||
|
<File
|
||||||
|
RelativePath="..\AltairZ80\m68kopac.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
|
||||||
|
<File
|
||||||
|
RelativePath="..\AltairZ80\m68kopdm.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
|
||||||
|
<File
|
||||||
|
RelativePath="..\AltairZ80\m68kopnz.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
|
||||||
|
<File
|
||||||
|
RelativePath="..\AltairZ80\m68kops.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
|
||||||
|
<File
|
||||||
|
RelativePath="..\AltairZ80\m68ksim.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\AltairZ80\altairz80_net.c"
|
RelativePath="..\AltairZ80\altairz80_net.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -330,7 +330,10 @@ ALTAIRZ80_SOURCE2 = $(ALTAIRZ80_DIR)S100_DISK1A.C,$(ALTAIRZ80_DIR)S100_DISK2.C,\
|
||||||
$(ALTAIRZ80_DIR)S100_SCP300F.C,$(ALTAIRZ80_DIR)SIM_IMD.C,\
|
$(ALTAIRZ80_DIR)S100_SCP300F.C,$(ALTAIRZ80_DIR)SIM_IMD.C,\
|
||||||
$(ALTAIRZ80_DIR)WD179X.C,$(ALTAIRZ80_DIR)S100_DISK3.C,\
|
$(ALTAIRZ80_DIR)WD179X.C,$(ALTAIRZ80_DIR)S100_DISK3.C,\
|
||||||
$(ALTAIRZ80_DIR)S100_ADCS6.C,$(ALTAIRZ80_DIR)S100_HDC1001.C,\
|
$(ALTAIRZ80_DIR)S100_ADCS6.C,$(ALTAIRZ80_DIR)S100_HDC1001.C,\
|
||||||
$(ALTAIRZ80_DIR)S100_IF3.C,$(ALTAIRZ80_DIR)ALTAIRZ80_MHDSK.C
|
$(ALTAIRZ80_DIR)S100_IF3.C,$(ALTAIRZ80_DIR)ALTAIRZ80_MHDSK.C,\
|
||||||
|
$(ALTAIRZ80_DIR)M68KCPU.C,$(ALTAIRZ80_DIR)M68KDASM.C,\
|
||||||
|
$(ALTAIRZ80_DIR)M68KOPAC.C,$(ALTAIRZ80_DIR)M68KOPDM.C,\
|
||||||
|
$(ALTAIRZ80_DIR)M68KOPNZ.C,$(ALTAIRZ80_DIR)M68KOPS.C,$(ALTAIRZ80_DIR)M68KSIM.C
|
||||||
ALTAIRZ80_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIRZ80_DIR))/DEF=($(CC_DEFS))
|
ALTAIRZ80_OPTIONS = /INCL=($(SIMH_DIR),$(ALTAIRZ80_DIR))/DEF=($(CC_DEFS))
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
5
makefile
5
makefile
|
@ -1021,7 +1021,10 @@ ALTAIRZ80 = ${ALTAIRZ80D}/altairz80_cpu.c ${ALTAIRZ80D}/altairz80_cpu_nommu.c \
|
||||||
${ALTAIRZ80D}/s100_ss1.c ${ALTAIRZ80D}/s100_64fdc.c \
|
${ALTAIRZ80D}/s100_ss1.c ${ALTAIRZ80D}/s100_64fdc.c \
|
||||||
${ALTAIRZ80D}/s100_scp300f.c ${ALTAIRZ80D}/sim_imd.c \
|
${ALTAIRZ80D}/s100_scp300f.c ${ALTAIRZ80D}/sim_imd.c \
|
||||||
${ALTAIRZ80D}/wd179x.c ${ALTAIRZ80D}/s100_hdc1001.c \
|
${ALTAIRZ80D}/wd179x.c ${ALTAIRZ80D}/s100_hdc1001.c \
|
||||||
${ALTAIRZ80D}/s100_if3.c ${ALTAIRZ80D}/s100_adcs6.c
|
${ALTAIRZ80D}/s100_if3.c ${ALTAIRZ80D}/s100_adcs6.c \
|
||||||
|
${ALTAIRZ80D}/m68kcpu.c ${ALTAIRZ80D}/m68kdasm.c \
|
||||||
|
${ALTAIRZ80D}/m68kopac.c ${ALTAIRZ80D}/m68kopdm.c \
|
||||||
|
${ALTAIRZ80D}/m68kopnz.c ${ALTAIRZ80D}/m68kops.c ${ALTAIRZ80D}/m68ksim.c
|
||||||
ALTAIRZ80_OPT = -I ${ALTAIRZ80D}
|
ALTAIRZ80_OPT = -I ${ALTAIRZ80D}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue