3B2: Interrupt Refactor and DEMON ROM
- This change introduces a full refactor of the interrupt subsystem for the system board (SBD) and the I/O bus (CIO). Interrupt decode should now be significantly faster, and not require an expensive calculation on every step. - The TIMER device has been split into Rev 2 and Rev 3 implementations. - The optional 3B2/400 Debug Monitor ROMs can now be booted by passing the "DEMON" argument to the 3B2/400 simulator BOOT command. Any of the following will cause the Debug Monitor ROM to be booted instead of the standard 3B2/400 ROM: sim> BOOT DEMON sim> BOOT CPU DEMON sim> BOOT DEMON CPU
This commit is contained in:
parent
d1a720debd
commit
9d849283a4
41 changed files with 1786 additions and 765 deletions
288
3B2/3b2_cpu.c
288
3B2/3b2_cpu.c
|
@ -46,34 +46,39 @@
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
|
||||||
#if defined(REV3)
|
#if defined(REV3)
|
||||||
#include "3b2_rev2_mau.h" /* TODO: Replace with Rev 3 MAU when implemented */
|
|
||||||
#include "3b2_rev3_csr.h"
|
|
||||||
#include "3b2_rev3_mmu.h"
|
|
||||||
#include "rom_rev3_bin.h"
|
#include "rom_rev3_bin.h"
|
||||||
|
#include "3b2_if.h"
|
||||||
|
#define ROM_ARRAY BOOT_CODE_ARRAY
|
||||||
|
#define ROM_SIZE BOOT_CODE_SIZE
|
||||||
#else
|
#else
|
||||||
#include "3b2_rev2_csr.h"
|
|
||||||
#include "3b2_rev2_mau.h"
|
|
||||||
#include "3b2_rev2_mmu.h"
|
|
||||||
#include "3b2_id.h"
|
|
||||||
#include "rom_rev2_bin.h"
|
#include "rom_rev2_bin.h"
|
||||||
#endif
|
#include "rom_rev2_demon_bin.h"
|
||||||
|
#include "3b2_id.h"
|
||||||
|
#define ROM_ARRAY BOOT_CODE_ARRAY_1
|
||||||
|
#define ROM_SIZE BOOT_CODE_SIZE_1
|
||||||
|
#define DEMON_ROM_ARRAY BOOT_CODE_ARRAY_2
|
||||||
|
#define DEMON_ROM_SIZE BOOT_CODE_SIZE_2
|
||||||
|
#endif /* defined(REV3) */
|
||||||
|
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_dmac.h"
|
#include "3b2_dmac.h"
|
||||||
#include "3b2_io.h"
|
#include "3b2_io.h"
|
||||||
#include "3b2_iu.h"
|
#include "3b2_iu.h"
|
||||||
|
#include "3b2_mau.h"
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
|
#include "3b2_mmu.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_stddev.h"
|
||||||
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
#define MAX_SUB_RETURN_SKIP 9
|
#define MAX_SUB_RETURN_SKIP 9
|
||||||
|
|
||||||
uint32 rom_size = BOOT_CODE_SIZE;
|
uint32 rom_size = 0;
|
||||||
|
|
||||||
/* Static function declarations */
|
/* Static function declarations */
|
||||||
static uint32 cpu_effective_address(operand * op);
|
static uint32 cpu_effective_address(operand * op);
|
||||||
static uint32 cpu_read_op(operand * op);
|
static uint32 cpu_read_op(operand * op);
|
||||||
static void cpu_write_op(operand * op, t_uint64 val);
|
static void cpu_write_op(operand * op, t_uint64 val);
|
||||||
static void cpu_set_nz_flags(t_uint64 data, operand * op);
|
static void cpu_set_nz_flags(t_uint64 data, operand * op);
|
||||||
static void cpu_calc_ints();
|
|
||||||
static SIM_INLINE void cpu_on_normal_exception(uint8 isc);
|
static SIM_INLINE void cpu_on_normal_exception(uint8 isc);
|
||||||
static SIM_INLINE void cpu_on_stack_exception(uint8 isc);
|
static SIM_INLINE void cpu_on_stack_exception(uint8 isc);
|
||||||
static SIM_INLINE void cpu_on_process_exception(uint8 isc);
|
static SIM_INLINE void cpu_on_process_exception(uint8 isc);
|
||||||
|
@ -136,16 +141,19 @@ volatile uint32 abort_reason;
|
||||||
uint32 R[NUM_REGISTERS];
|
uint32 R[NUM_REGISTERS];
|
||||||
|
|
||||||
/* Other global CPU state */
|
/* Other global CPU state */
|
||||||
uint8 cpu_int_ipl = 0; /* Interrupt IPL level */
|
|
||||||
uint8 cpu_int_vec = 0; /* Interrupt vector */
|
|
||||||
t_bool cpu_nmi = FALSE; /* If set, there has been an NMI */
|
|
||||||
|
|
||||||
int32 pc_incr = 0; /* Length (in bytes) of instruction
|
/* Interrupt request bitfield */
|
||||||
currently being executed */
|
/* Note: Only the lowest 8 bits are used by Rev 2, and only the lowest
|
||||||
t_bool cpu_ex_halt = FALSE; /* Flag to halt on exceptions /
|
12 bits are used by Rev 3 */
|
||||||
traps */
|
uint16 sbd_int_req = 0; /* Currently set interrupt sources */
|
||||||
t_bool cpu_km = FALSE; /* If true, kernel mode has been forced
|
uint8 int_map[INT_MAP_LEN]; /* Map of interrupt sources to highest
|
||||||
for memory access */
|
priority IPL */
|
||||||
|
t_bool cpu_nmi = FALSE; /* If set, there has been an NMI */
|
||||||
|
int32 pc_incr = 0; /* Length (in bytes) of instruction
|
||||||
|
currently being executed */
|
||||||
|
t_bool cpu_ex_halt = FALSE; /* Flag to halt on exceptions / traps */
|
||||||
|
t_bool cpu_km = FALSE; /* If true, kernel mode has been forced
|
||||||
|
for memory access */
|
||||||
CTAB sys_cmd[] = {
|
CTAB sys_cmd[] = {
|
||||||
{ "BOOT", &sys_boot, RU_BOOT,
|
{ "BOOT", &sys_boot, RU_BOOT,
|
||||||
"bo{ot} boot simulator\n", NULL, &run_cmd_message },
|
"bo{ot} boot simulator\n", NULL, &run_cmd_message },
|
||||||
|
@ -182,6 +190,37 @@ BITFIELD psw_bits[] = {
|
||||||
ENDBITS
|
ENDBITS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BITFIELD sbd_int_req_bits[] = {
|
||||||
|
#if defined(REV3)
|
||||||
|
BIT(CLOK), /* UNIX Interval Timer */
|
||||||
|
BIT(PWRD), /* Power Down Request */
|
||||||
|
BIT(BUSO), /* UBUS or BUB Operational Interrupt */
|
||||||
|
BIT(SBER), /* Single Bit Memory Error */
|
||||||
|
BIT(MBER), /* Multiple Bit Memory Error */
|
||||||
|
BIT(BRXF), /* UBUS, BUB, EIO Bus Received Fail */
|
||||||
|
BIT(BTMO), /* UBUS Timer Timeout */
|
||||||
|
BIT(UDMA), /* UART DMA Complete */
|
||||||
|
BIT(UART), /* UART Interrupt */
|
||||||
|
BIT(FDMA), /* Floppy DMA Complete */
|
||||||
|
BIT(FLOP), /* Floppy Interrupt */
|
||||||
|
BIT(PIR9), /* PIR 9 */
|
||||||
|
BIT(PIR8), /* PIR 8 */
|
||||||
|
BITNCF(3), /* Unused */
|
||||||
|
ENDBITS
|
||||||
|
#else
|
||||||
|
BIT(SERR), /* System Error */
|
||||||
|
BIT(CLOK), /* UNIX Interval Timer */
|
||||||
|
BIT(DMAC), /* DMA Complete */
|
||||||
|
BIT(UART), /* UART */
|
||||||
|
BIT(DISK), /* Integrated Disk Drive (Winchester) */
|
||||||
|
BIT(FLOP), /* Integrated Floppy Drive */
|
||||||
|
BIT(PIR9), /* PIR 9 */
|
||||||
|
BIT(PIR8), /* PIR 8 */
|
||||||
|
BITNCF(8), /* Unused */
|
||||||
|
ENDBITS
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/* Registers. */
|
/* Registers. */
|
||||||
REG cpu_reg[] = {
|
REG cpu_reg[] = {
|
||||||
{ HRDATAD (R0, R[0], 32, "General purpose register 0") },
|
{ HRDATAD (R0, R[0], 32, "General purpose register 0") },
|
||||||
|
@ -218,8 +257,7 @@ REG cpu_reg[] = {
|
||||||
{ HRDATAD (R30, R[30], 32, "Privileged register 30")},
|
{ HRDATAD (R30, R[30], 32, "Privileged register 30")},
|
||||||
{ HRDATAD (R31, R[31], 32, "Privileged register 31")},
|
{ HRDATAD (R31, R[31], 32, "Privileged register 31")},
|
||||||
#endif
|
#endif
|
||||||
{ HRDATAD (IPL, cpu_int_ipl, 8, "Current CPU IPL bits")},
|
{ HRDATADF (SBD_INT, sbd_int_req, 16, "Interrupt Requests", sbd_int_req_bits) },
|
||||||
{ HRDATAD (VEC, cpu_int_vec, 8, "Current CPU interrupt vector")},
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -317,9 +355,9 @@ MTAB cpu_mod[] = {
|
||||||
&cpu_set_size, NULL, NULL, "Set Memory to 1M bytes" },
|
&cpu_set_size, NULL, NULL, "Set Memory to 1M bytes" },
|
||||||
{ UNIT_MSIZE, (1u << 21), NULL, "2M",
|
{ UNIT_MSIZE, (1u << 21), NULL, "2M",
|
||||||
&cpu_set_size, NULL, NULL, "Set Memory to 2M bytes" },
|
&cpu_set_size, NULL, NULL, "Set Memory to 2M bytes" },
|
||||||
#endif
|
|
||||||
{ UNIT_MSIZE, (1u << 22), NULL, "4M",
|
{ UNIT_MSIZE, (1u << 22), NULL, "4M",
|
||||||
&cpu_set_size, NULL, NULL, "Set Memory to 4M bytes" },
|
&cpu_set_size, NULL, NULL, "Set Memory to 4M bytes" },
|
||||||
|
#endif
|
||||||
#if defined(REV3)
|
#if defined(REV3)
|
||||||
{ UNIT_MSIZE, (1u << 23), NULL, "8M",
|
{ UNIT_MSIZE, (1u << 23), NULL, "8M",
|
||||||
&cpu_set_size, NULL, NULL, "Set Memory to 8M bytes" },
|
&cpu_set_size, NULL, NULL, "Set Memory to 8M bytes" },
|
||||||
|
@ -756,24 +794,34 @@ t_stat cpu_show_cio(FILE *st, UNIT *uptr, int32 val, CONST void *desc)
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_load_rom()
|
t_stat cpu_load_rom(uint8 *arrayp, uint32 len)
|
||||||
{
|
{
|
||||||
uint32 i, index, sc, mask, val;
|
uint32 i, index, sc, mask, val;
|
||||||
|
|
||||||
|
/* Update global state */
|
||||||
|
rom_size = len;
|
||||||
|
|
||||||
|
if (ROM != NULL) {
|
||||||
|
free(ROM);
|
||||||
|
}
|
||||||
|
ROM = (uint32 *) calloc((size_t)(len >> 2), sizeof(uint32));
|
||||||
if (ROM == NULL) {
|
if (ROM == NULL) {
|
||||||
return;
|
return SCPE_MEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < rom_size; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
val = BOOT_CODE_ARRAY[i];
|
val = arrayp[i];
|
||||||
sc = (~(i & 3) << 3) & 0x1f;
|
sc = (~(i & 3) << 3) & 0x1f;
|
||||||
mask = 0xffu << sc;
|
mask = 0xffu << sc;
|
||||||
index = i >> 2;
|
index = i >> 2;
|
||||||
|
|
||||||
ROM[index] = (ROM[index] & ~mask) | (val << sc);
|
ROM[index] = (ROM[index] & ~mask) | (val << sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(REV3)
|
||||||
t_stat sys_boot(int32 flag, CONST char *ptr)
|
t_stat sys_boot(int32 flag, CONST char *ptr)
|
||||||
{
|
{
|
||||||
char gbuf[CBUFSIZE];
|
char gbuf[CBUFSIZE];
|
||||||
|
@ -789,6 +837,39 @@ t_stat sys_boot(int32 flag, CONST char *ptr)
|
||||||
|
|
||||||
return run_cmd(flag, "CPU");
|
return run_cmd(flag, "CPU");
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
t_stat sys_boot(int32 flag, CONST char *ptr)
|
||||||
|
{
|
||||||
|
char gbuf[CBUFSIZE] = { 0 };
|
||||||
|
int gnum = 0;
|
||||||
|
uint8 *srcp = ROM_ARRAY;
|
||||||
|
uint32 len = ROM_SIZE;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
|
if ((ptr = get_sim_sw(ptr)) == NULL) {
|
||||||
|
return SCPE_INVSW;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
ptr = get_glyph(ptr, gbuf, 0);
|
||||||
|
|
||||||
|
if (gbuf[0] && (strcmp(gbuf, "CPU") && strcmp(gbuf, "DEMON"))) {
|
||||||
|
return SCPE_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(gbuf, "DEMON") == 0) {
|
||||||
|
srcp = DEMON_ROM_ARRAY;
|
||||||
|
len = DEMON_ROM_SIZE;
|
||||||
|
}
|
||||||
|
} while (gbuf[0]);
|
||||||
|
|
||||||
|
if ((r = cpu_load_rom(srcp, len)) != SCPE_OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return run_cmd(flag, "CPU");
|
||||||
|
}
|
||||||
|
#endif /* Rev 2 boot */
|
||||||
|
|
||||||
t_stat cpu_boot(int32 unit_num, DEVICE *dptr)
|
t_stat cpu_boot(int32 unit_num, DEVICE *dptr)
|
||||||
{
|
{
|
||||||
|
@ -872,9 +953,58 @@ t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pre-populate the interrupt->IPL map "int_map"
|
||||||
|
*/
|
||||||
|
static void build_int_map()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
uint8 ipl;
|
||||||
|
|
||||||
|
for (i = 0; i < INT_MAP_LEN; i++) {
|
||||||
|
#if defined(REV3)
|
||||||
|
if (i & (INT_PWRDWN|INT_BUS_OP|INT_SBERR|
|
||||||
|
INT_MBERR|INT_BUS_RXF|INT_BUS_TMO|
|
||||||
|
INT_CLOCK)) {
|
||||||
|
ipl = CPU_IPL_15;
|
||||||
|
} else if (i & (INT_UART|INT_UART_DMA)) {
|
||||||
|
ipl = CPU_IPL_13;
|
||||||
|
} else if (i & (INT_FLOPPY|INT_FLOPPY_DMA)) {
|
||||||
|
ipl = CPU_IPL_11;
|
||||||
|
} else if (i & INT_PIR9) {
|
||||||
|
ipl = CPU_IPL_9;
|
||||||
|
} else if (i & INT_PIR8) {
|
||||||
|
ipl = CPU_IPL_8;
|
||||||
|
} else {
|
||||||
|
ipl = 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (i & (INT_CLOCK|INT_SERR)) {
|
||||||
|
ipl = CPU_IPL_15;
|
||||||
|
} else if (i & (INT_UART|INT_DMA)) {
|
||||||
|
ipl = CPU_IPL_13;
|
||||||
|
} else if (i & (INT_DISK|INT_FLOPPY)) {
|
||||||
|
ipl = CPU_IPL_11;
|
||||||
|
} else if (i & INT_PIR9) {
|
||||||
|
ipl = CPU_IPL_9;
|
||||||
|
} else if (i & INT_PIR8) {
|
||||||
|
ipl = CPU_IPL_8;
|
||||||
|
} else {
|
||||||
|
ipl = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int_map[i] = ipl;
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_debug(EXECUTE_MSG, &cpu_dev,
|
||||||
|
"Built interrupt->IPL map of length %d\n", INT_MAP_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
t_stat cpu_reset(DEVICE *dptr)
|
t_stat cpu_reset(DEVICE *dptr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
t_stat r;
|
||||||
|
|
||||||
/* Link in our special "boot" command so we can boot with both
|
/* Link in our special "boot" command so we can boot with both
|
||||||
* "BO{OT}" and "BO{OT} CPU" */
|
* "BO{OT}" and "BO{OT} CPU" */
|
||||||
|
@ -883,24 +1013,23 @@ t_stat cpu_reset(DEVICE *dptr)
|
||||||
/* Set up the pre-calibration routine */
|
/* Set up the pre-calibration routine */
|
||||||
sim_clock_precalibrate_commands = att3b2_clock_precalibrate_commands;
|
sim_clock_precalibrate_commands = att3b2_clock_precalibrate_commands;
|
||||||
|
|
||||||
|
/* Populate the interrupt->IPL map */
|
||||||
|
build_int_map();
|
||||||
|
|
||||||
if (!sim_is_running) {
|
if (!sim_is_running) {
|
||||||
/* Clear registers */
|
/* Clear registers */
|
||||||
for (i = 0; i < NUM_REGISTERS; i++) {
|
for (i = 0; i < NUM_REGISTERS; i++) {
|
||||||
R[i] = 0;
|
R[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate ROM */
|
/* Allocate ROM if needed */
|
||||||
if (ROM != NULL) {
|
|
||||||
free(ROM);
|
|
||||||
}
|
|
||||||
ROM = (uint32 *) calloc((size_t)(rom_size >> 2), sizeof(uint32));
|
|
||||||
if (ROM == NULL) {
|
if (ROM == NULL) {
|
||||||
return SCPE_MEM;
|
if ((r = cpu_load_rom(ROM_ARRAY, ROM_SIZE)) != SCPE_OK) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_load_rom();
|
/* Always re-allocate RAM */
|
||||||
|
|
||||||
/* Allocate RAM */
|
|
||||||
if (RAM != NULL) {
|
if (RAM != NULL) {
|
||||||
free(RAM);
|
free(RAM);
|
||||||
}
|
}
|
||||||
|
@ -1822,8 +1951,8 @@ void cpu_on_interrupt(uint16 vec)
|
||||||
uint32 new_pcbp, new_pcbp_ptr;
|
uint32 new_pcbp, new_pcbp_ptr;
|
||||||
|
|
||||||
sim_debug(IRQ_MSG, &cpu_dev,
|
sim_debug(IRQ_MSG, &cpu_dev,
|
||||||
"[%08x] [cpu_on_interrupt] vec=%02x (%d) csr_data = %x\n",
|
"[%08x] [cpu_on_interrupt] vec=%02x (%d) sbd_int_req = %x, csr_data = %x\n",
|
||||||
R[NUM_PC], vec, vec, csr_data);
|
R[NUM_PC], vec, vec, sbd_int_req, csr_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "If a nonmaskable interrupt request is received, an auto-vector
|
* "If a nonmaskable interrupt request is received, an auto-vector
|
||||||
|
@ -1886,6 +2015,9 @@ t_stat sim_instr(void)
|
||||||
/* Generic index */
|
/* Generic index */
|
||||||
uint32 i;
|
uint32 i;
|
||||||
|
|
||||||
|
/* Interrupt request IPL */
|
||||||
|
uint8 ipl;
|
||||||
|
|
||||||
/* Used by oprocessor instructions */
|
/* Used by oprocessor instructions */
|
||||||
uint32 coprocessor_word;
|
uint32 coprocessor_word;
|
||||||
|
|
||||||
|
@ -1999,26 +2131,33 @@ t_stat sim_instr(void)
|
||||||
increment_modep_b();
|
increment_modep_b();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the correct IRQ state */
|
/* Interrupt Handling
|
||||||
cpu_calc_ints();
|
*
|
||||||
|
* - NMI is always serviced first.
|
||||||
if (cpu_nmi || (PSW_CUR_IPL < cpu_int_ipl)) {
|
* - SBD interrupts are handled next in priority.
|
||||||
cpu_on_interrupt(cpu_int_vec);
|
* - IO Bus boards are handled last.
|
||||||
for (i = 0; i < CIO_SLOTS; i++) {
|
*/
|
||||||
if (cio[i].intr &&
|
if (cpu_nmi) {
|
||||||
cio[i].ipl == cpu_int_ipl &&
|
|
||||||
cio[i].ivec == cpu_int_vec) {
|
|
||||||
sim_debug(CIO_DBG, &cpu_dev,
|
|
||||||
"[%08x] [IRQ] Handling CIO interrupt for card %d ivec=%02x\n",
|
|
||||||
R[NUM_PC], i, cpu_int_vec);
|
|
||||||
|
|
||||||
cio[i].intr = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cpu_int_ipl = 0;
|
|
||||||
cpu_int_vec = 0;
|
|
||||||
cpu_nmi = FALSE;
|
cpu_nmi = FALSE;
|
||||||
cpu_in_wait = FALSE;
|
cpu_in_wait = FALSE;
|
||||||
|
cpu_on_interrupt(0);
|
||||||
|
} else if (sbd_int_req) {
|
||||||
|
ipl = int_map[sbd_int_req];
|
||||||
|
if (PSW_CUR_IPL < ipl) {
|
||||||
|
/* For the system board, interrupt vector is always
|
||||||
|
equal to IPL */
|
||||||
|
cpu_in_wait = FALSE;
|
||||||
|
cpu_on_interrupt(ipl);
|
||||||
|
}
|
||||||
|
} else if (cio_int_req) {
|
||||||
|
for (i = 0; i < CIO_SLOTS; i++) {
|
||||||
|
if ((cio_int_req & (1 << i)) && (PSW_CUR_IPL < cio[i].ipl)) {
|
||||||
|
cpu_in_wait = FALSE;
|
||||||
|
CIO_CLR_INT(i);
|
||||||
|
cpu_on_interrupt(cio[i].ivec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpu_in_wait) {
|
if (cpu_in_wait) {
|
||||||
|
@ -3693,45 +3832,6 @@ static void cpu_write_op(operand * op, t_uint64 val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate the current state of interrupts.
|
|
||||||
* TODO: This could use a refactor. It's getting code-smelly.
|
|
||||||
*/
|
|
||||||
static void cpu_calc_ints()
|
|
||||||
{
|
|
||||||
uint32 i;
|
|
||||||
|
|
||||||
/* First scan for a CIO interrupt */
|
|
||||||
for (i = 0; i < CIO_SLOTS; i++) {
|
|
||||||
if (cio[i].intr) {
|
|
||||||
cpu_int_ipl = cio[i].ipl;
|
|
||||||
cpu_int_vec = cio[i].ivec;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If none was found, look for system board interrupts */
|
|
||||||
|
|
||||||
#if defined(REV3)
|
|
||||||
// TODO: Rev 3 interrupt support
|
|
||||||
cpu_int_ipl = cpu_int_vec = 0;
|
|
||||||
#else
|
|
||||||
if (csr_data & CSRPIR8) {
|
|
||||||
cpu_int_ipl = cpu_int_vec = CPU_IPL_8;
|
|
||||||
} else if (csr_data & CSRPIR9) {
|
|
||||||
cpu_int_ipl = cpu_int_vec = CPU_IPL_9;
|
|
||||||
} else if (id_int() || (csr_data & CSRDISK)) {
|
|
||||||
cpu_int_ipl = cpu_int_vec = CPU_IPL_11;
|
|
||||||
} else if ((csr_data & CSRUART) || (csr_data & CSRDMA)) {
|
|
||||||
cpu_int_ipl = cpu_int_vec = CPU_IPL_13;
|
|
||||||
} else if ((csr_data & CSRCLK) || (csr_data & CSRTIMO)) {
|
|
||||||
cpu_int_ipl = cpu_int_vec = CPU_IPL_15;
|
|
||||||
} else {
|
|
||||||
cpu_int_ipl = cpu_int_vec = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the correct datatype for an operand -- either extended type
|
* Returns the correct datatype for an operand -- either extended type
|
||||||
* or default type.
|
* or default type.
|
||||||
|
|
|
@ -604,8 +604,6 @@ instr *cpu_next_instruction(void);
|
||||||
uint8 decode_instruction(instr *instr);
|
uint8 decode_instruction(instr *instr);
|
||||||
void cpu_on_interrupt(uint16 vec);
|
void cpu_on_interrupt(uint16 vec);
|
||||||
void cpu_abort(uint8 et, uint8 isc);
|
void cpu_abort(uint8 et, uint8 isc);
|
||||||
void cpu_set_irq(uint8 ipl, uint8 id, uint16 csr_flags);
|
|
||||||
void cpu_clear_irq(uint8 ipl, uint16 csr_flags);
|
|
||||||
|
|
||||||
/* Helper macros */
|
/* Helper macros */
|
||||||
|
|
||||||
|
@ -649,7 +647,11 @@ void cpu_clear_irq(uint8 ipl, uint16 csr_flags);
|
||||||
(d) = (uint8) (a)[(p)++]; \
|
(d) = (uint8) (a)[(p)++]; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CPU_SET_INT(flags) (sbd_int_req |= flags)
|
||||||
|
#define CPU_CLR_INT(flags) (sbd_int_req &= ~(flags))
|
||||||
|
|
||||||
extern volatile int32 stop_reason;
|
extern volatile int32 stop_reason;
|
||||||
|
extern uint16 sbd_int_req;
|
||||||
extern uint32 rom_size;
|
extern uint32 rom_size;
|
||||||
extern instr *cpu_instr;
|
extern instr *cpu_instr;
|
||||||
extern t_bool cpu_nmi;
|
extern t_bool cpu_nmi;
|
||||||
|
|
44
3B2/3b2_csr.h
Normal file
44
3B2/3b2_csr.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/* 3b2_csr.h: Common CSR header
|
||||||
|
|
||||||
|
Copyright (c) 2021, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _3B2_CSR_H_
|
||||||
|
#define _3B2_CSR_H_
|
||||||
|
|
||||||
|
#if defined(REV3)
|
||||||
|
#include "3b2_rev3_csr.h"
|
||||||
|
#else
|
||||||
|
#include "3b2_rev2_csr.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SET_CSR(FLAGS) (csr_data |= (FLAGS))
|
||||||
|
#define CLR_CSR(FLAGS) (csr_data &= ~(FLAGS))
|
||||||
|
#define CSR(FLAGS) ((csr_data & FLAGS) != 0)
|
||||||
|
|
||||||
|
#endif /* _3B2_CSR_H_ */
|
|
@ -32,8 +32,8 @@
|
||||||
|
|
||||||
#include "sim_disk.h"
|
#include "sim_disk.h"
|
||||||
|
|
||||||
#include "3b2_mem.h"
|
|
||||||
#include "3b2_io.h"
|
#include "3b2_io.h"
|
||||||
|
#include "3b2_mem.h"
|
||||||
|
|
||||||
#define CTQRESIZE 20
|
#define CTQRESIZE 20
|
||||||
#define CTQCESIZE 16
|
#define CTQCESIZE 16
|
||||||
|
@ -761,7 +761,7 @@ t_stat ctc_svc(UNIT *uptr)
|
||||||
sim_debug(TRACE_DBG, &ctc_dev,
|
sim_debug(TRACE_DBG, &ctc_dev,
|
||||||
"[cio_svc] IRQ for board %d (VEC=%d)\n",
|
"[cio_svc] IRQ for board %d (VEC=%d)\n",
|
||||||
int_cid, cio[int_cid].ivec);
|
int_cid, cio[int_cid].ivec);
|
||||||
cio[int_cid].intr = TRUE;
|
CIO_SET_INT(int_cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check to see if the completion queue has more work in it. We
|
/* Check to see if the completion queue has more work in it. We
|
||||||
|
|
|
@ -85,6 +85,8 @@ noret __libc_longjmp(jmp_buf buf, int val);
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PCHAR(c) (((char) (c) >= 0x20 && (char) (c) < 0x7f) ? (char) (c) : '.')
|
||||||
|
|
||||||
#define UNIT_V_EXBRK (UNIT_V_UF + 0)
|
#define UNIT_V_EXBRK (UNIT_V_UF + 0)
|
||||||
#define UNIT_V_OPBRK (UNIT_V_UF + 1)
|
#define UNIT_V_OPBRK (UNIT_V_UF + 1)
|
||||||
#define UNIT_EXBRK (1u << UNIT_V_EXBRK)
|
#define UNIT_EXBRK (1u << UNIT_V_EXBRK)
|
||||||
|
@ -135,6 +137,11 @@ noret __libc_longjmp(jmp_buf buf, int val);
|
||||||
#define TIMER_INTERVAL 1
|
#define TIMER_INTERVAL 1
|
||||||
#define TIMER_BUS 2
|
#define TIMER_BUS 2
|
||||||
|
|
||||||
|
/* Timer */
|
||||||
|
#define TMR_CLK 0 /* The clock responsible for IPL 15 interrupts */
|
||||||
|
#define TPS_CLK 100 /* 100 ticks per second */
|
||||||
|
|
||||||
|
|
||||||
/* Global symbols */
|
/* Global symbols */
|
||||||
|
|
||||||
extern DEBTAB sys_deb_tab[];
|
extern DEBTAB sys_deb_tab[];
|
||||||
|
|
61
3B2/3b2_id.c
61
3B2/3b2_id.c
|
@ -186,11 +186,31 @@ DEVICE id_dev = {
|
||||||
|
|
||||||
/* Function implementation */
|
/* Function implementation */
|
||||||
|
|
||||||
t_bool id_int()
|
#define UPDATE_INT { \
|
||||||
|
if ((id_status & (ID_STAT_CEL|ID_STAT_CEH)) || \
|
||||||
|
((id_status & ID_STAT_SRQ) && !id_srqm)) { \
|
||||||
|
CPU_SET_INT(INT_DISK); \
|
||||||
|
} else { \
|
||||||
|
CPU_CLR_INT(INT_DISK); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIM_INLINE void id_set_status(uint8 flags)
|
||||||
{
|
{
|
||||||
return (((id_status & ID_STAT_CEL) ||
|
id_status |= flags;
|
||||||
(id_status & ID_STAT_CEH) ||
|
UPDATE_INT;
|
||||||
((id_status & ID_STAT_SRQ) && !id_srqm)));
|
}
|
||||||
|
|
||||||
|
static SIM_INLINE void id_clr_status(uint8 flags)
|
||||||
|
{
|
||||||
|
id_status &= ~(flags);
|
||||||
|
UPDATE_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SIM_INLINE void id_set_srqm(t_bool state)
|
||||||
|
{
|
||||||
|
id_srqm = state;
|
||||||
|
UPDATE_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIM_INLINE void id_clear_fifo()
|
static SIM_INLINE void id_clear_fifo()
|
||||||
|
@ -217,9 +237,9 @@ t_stat id_ctlr_svc(UNIT *uptr)
|
||||||
|
|
||||||
cmd = uptr->u4; /* The command that caused the activity */
|
cmd = uptr->u4; /* The command that caused the activity */
|
||||||
|
|
||||||
id_srqm = FALSE;
|
id_set_srqm(FALSE);
|
||||||
id_status &= ~(ID_STAT_CB);
|
id_clr_status(ID_STAT_CB);
|
||||||
id_status |= ID_STAT_CEH;
|
id_set_status(ID_STAT_CEH);
|
||||||
uptr->u4 = 0;
|
uptr->u4 = 0;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
@ -259,8 +279,8 @@ t_stat id_unit_svc(UNIT *uptr)
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
id_srqm = FALSE;
|
id_set_srqm(FALSE);
|
||||||
id_status &= ~(ID_STAT_CB);
|
id_clr_status(ID_STAT_CB);
|
||||||
/* Note that we don't set CEH, in case this is a SEEK/RECAL ID_SEEK_1 */
|
/* Note that we don't set CEH, in case this is a SEEK/RECAL ID_SEEK_1 */
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
|
@ -277,7 +297,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
||||||
if (id_polling) {
|
if (id_polling) {
|
||||||
switch (id_seek_state[unit]) {
|
switch (id_seek_state[unit]) {
|
||||||
case ID_SEEK_0:
|
case ID_SEEK_0:
|
||||||
id_status |= ID_STAT_CEH;
|
id_set_status(ID_STAT_CEH);
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tINTR\t\tCOMPLETING Recal/Seek SEEK_0 UNIT %d\n",
|
"[%08x]\tINTR\t\tCOMPLETING Recal/Seek SEEK_0 UNIT %d\n",
|
||||||
R[NUM_PC], unit);
|
R[NUM_PC], unit);
|
||||||
|
@ -289,7 +309,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
||||||
"[%08x]\tINTR\t\tCOMPLETING Recal/Seek SEEK_1 UNIT %d\n",
|
"[%08x]\tINTR\t\tCOMPLETING Recal/Seek SEEK_1 UNIT %d\n",
|
||||||
R[NUM_PC], unit);
|
R[NUM_PC], unit);
|
||||||
id_seek_state[unit] = ID_SEEK_NONE;
|
id_seek_state[unit] = ID_SEEK_NONE;
|
||||||
id_status |= ID_STAT_SRQ;
|
id_set_status(ID_STAT_SRQ);
|
||||||
uptr->u4 = 0; /* Only clear out the command on a SEEK_1, never a SEEK_0 */
|
uptr->u4 = 0; /* Only clear out the command on a SEEK_1, never a SEEK_0 */
|
||||||
if (uptr->flags & UNIT_ATT) {
|
if (uptr->flags & UNIT_ATT) {
|
||||||
id_int_status |= (ID_IST_SEN|unit);
|
id_int_status |= (ID_IST_SEN|unit);
|
||||||
|
@ -307,7 +327,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tINTR\t\tCOMPLETING NON-POLLING Recal/Seek UNIT %d\n",
|
"[%08x]\tINTR\t\tCOMPLETING NON-POLLING Recal/Seek UNIT %d\n",
|
||||||
R[NUM_PC], unit);
|
R[NUM_PC], unit);
|
||||||
id_status |= ID_STAT_CEH;
|
id_set_status(ID_STAT_CEH);
|
||||||
uptr->u4 = 0;
|
uptr->u4 = 0;
|
||||||
if (uptr->flags & UNIT_ATT) {
|
if (uptr->flags & UNIT_ATT) {
|
||||||
id_int_status |= (ID_IST_SEN|unit);
|
id_int_status |= (ID_IST_SEN|unit);
|
||||||
|
@ -321,7 +341,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tINTR\t\tCOMPLETING Sense Unit Status UNIT %d\n",
|
"[%08x]\tINTR\t\tCOMPLETING Sense Unit Status UNIT %d\n",
|
||||||
R[NUM_PC], unit);
|
R[NUM_PC], unit);
|
||||||
id_status |= ID_STAT_CEH;
|
id_set_status(ID_STAT_CEH);
|
||||||
uptr->u4 = 0;
|
uptr->u4 = 0;
|
||||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
/* If no HD is attached, SUS puts 0x00 into the data
|
/* If no HD is attached, SUS puts 0x00 into the data
|
||||||
|
@ -339,7 +359,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
||||||
sim_debug(EXECUTE_MSG, &id_dev,
|
sim_debug(EXECUTE_MSG, &id_dev,
|
||||||
"[%08x]\tINTR\t\tCOMPLETING OTHER COMMAND 0x%x UNIT %d\n",
|
"[%08x]\tINTR\t\tCOMPLETING OTHER COMMAND 0x%x UNIT %d\n",
|
||||||
R[NUM_PC], cmd, unit);
|
R[NUM_PC], cmd, unit);
|
||||||
id_status |= ID_STAT_CEH;
|
id_set_status(ID_STAT_CEH);
|
||||||
uptr->u4 = 0;
|
uptr->u4 = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -673,14 +693,14 @@ void id_handle_command(uint8 val)
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x] \tCOMMAND\t%02x\tAUX:CLCE\n",
|
"[%08x] \tCOMMAND\t%02x\tAUX:CLCE\n",
|
||||||
R[NUM_PC], val);
|
R[NUM_PC], val);
|
||||||
id_status &= ~(ID_STAT_CEH|ID_STAT_CEL);
|
id_clr_status(ID_STAT_CEH|ID_STAT_CEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aux_cmd & ID_AUX_HSRQ) {
|
if (aux_cmd & ID_AUX_HSRQ) {
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x] \tCOMMAND\t%02x\tAUX:HSRQ\n",
|
"[%08x] \tCOMMAND\t%02x\tAUX:HSRQ\n",
|
||||||
R[NUM_PC], val);
|
R[NUM_PC], val);
|
||||||
id_srqm = TRUE;
|
id_set_srqm(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (aux_cmd & ID_AUX_CLB) {
|
if (aux_cmd & ID_AUX_CLB) {
|
||||||
|
@ -699,6 +719,7 @@ void id_handle_command(uint8 val)
|
||||||
sim_cancel(id_ctlr_unit);
|
sim_cancel(id_ctlr_unit);
|
||||||
id_status = 0;
|
id_status = 0;
|
||||||
id_srqm = FALSE;
|
id_srqm = FALSE;
|
||||||
|
UPDATE_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Just return early */
|
/* Just return early */
|
||||||
|
@ -715,7 +736,7 @@ void id_handle_command(uint8 val)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A full command always resets CEH and CEL */
|
/* A full command always resets CEH and CEL */
|
||||||
id_status &= ~(ID_STAT_CEH|ID_STAT_CEL);
|
id_clr_status(ID_STAT_CEH|ID_STAT_CEL);
|
||||||
|
|
||||||
/* Save the full command byte */
|
/* Save the full command byte */
|
||||||
id_cmd = val;
|
id_cmd = val;
|
||||||
|
@ -739,14 +760,14 @@ void id_handle_command(uint8 val)
|
||||||
id_sel_unit->u4 = cmd;
|
id_sel_unit->u4 = cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
id_status |= ID_STAT_CB;
|
id_set_status(ID_STAT_CB);
|
||||||
|
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case ID_CMD_SIS:
|
case ID_CMD_SIS:
|
||||||
sim_debug(WRITE_MSG, &id_dev,
|
sim_debug(WRITE_MSG, &id_dev,
|
||||||
"[%08x]\tCOMMAND\t%02x\tSense Int. Status\n",
|
"[%08x]\tCOMMAND\t%02x\tSense Int. Status\n",
|
||||||
R[NUM_PC], val);
|
R[NUM_PC], val);
|
||||||
id_status &= ~ID_STAT_SRQ; /* SIS immediately de-asserts SRQ */
|
id_clr_status(ID_STAT_SRQ); /* SIS immediately de-asserts SRQ */
|
||||||
id_activate(id_ctlr_unit, ID_SIS_WAIT);
|
id_activate(id_ctlr_unit, ID_SIS_WAIT);
|
||||||
break;
|
break;
|
||||||
case ID_CMD_SPEC:
|
case ID_CMD_SPEC:
|
||||||
|
@ -951,7 +972,7 @@ void id_handle_command(uint8 val)
|
||||||
|
|
||||||
void id_after_dma()
|
void id_after_dma()
|
||||||
{
|
{
|
||||||
id_status &= ~ID_STAT_DRQ;
|
id_clr_status(ID_STAT_DRQ);
|
||||||
id_drq = FALSE;
|
id_drq = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,6 @@
|
||||||
|
|
||||||
/* Function prototypes */
|
/* Function prototypes */
|
||||||
|
|
||||||
t_bool id_int();
|
|
||||||
t_stat id_ctlr_svc(UNIT *uptr);
|
t_stat id_ctlr_svc(UNIT *uptr);
|
||||||
t_stat id_unit_svc(UNIT *uptr);
|
t_stat id_unit_svc(UNIT *uptr);
|
||||||
t_stat id_reset(DEVICE *dptr);
|
t_stat id_reset(DEVICE *dptr);
|
||||||
|
|
60
3B2/3b2_if.c
60
3B2/3b2_if.c
|
@ -32,19 +32,10 @@
|
||||||
|
|
||||||
#include "sim_disk.h"
|
#include "sim_disk.h"
|
||||||
|
|
||||||
|
|
||||||
#if defined(REV3)
|
|
||||||
#include "3b2_rev3_csr.h"
|
|
||||||
#else
|
|
||||||
#include "3b2_rev2_csr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
|
|
||||||
/* Static function declarations */
|
/* Static function declarations */
|
||||||
static SIM_INLINE void if_set_irq();
|
|
||||||
static SIM_INLINE void if_clear_irq();
|
|
||||||
static SIM_INLINE void if_cancel_pending_irq();
|
|
||||||
static SIM_INLINE uint32 if_lba();
|
static SIM_INLINE uint32 if_lba();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -67,13 +58,26 @@ static SIM_INLINE uint32 if_lba();
|
||||||
#define IF_HLD_DELAY 60000 /* us */
|
#define IF_HLD_DELAY 60000 /* us */
|
||||||
#define IF_HSW_DELAY 40000 /* us */
|
#define IF_HSW_DELAY 40000 /* us */
|
||||||
|
|
||||||
|
#if defined(REV3)
|
||||||
|
#define SET_INT CPU_SET_INT(INT_FLOPPY)
|
||||||
|
#define CLR_INT CPU_CLR_INT(INT_FLOPPY)
|
||||||
|
#else
|
||||||
|
#define SET_INT do { \
|
||||||
|
CPU_SET_INT(INT_FLOPPY); \
|
||||||
|
SET_CSR(CSRDISK); \
|
||||||
|
} while(0)
|
||||||
|
#define CLR_INT do { \
|
||||||
|
CPU_CLR_INT(INT_FLOPPY); \
|
||||||
|
CLR_CSR(CSRDISK); \
|
||||||
|
} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
UNIT if_unit = {
|
UNIT if_unit = {
|
||||||
UDATA (&if_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE,
|
UDATA (&if_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE,
|
||||||
IF_DSK_SIZE_SECS)
|
IF_DSK_SIZE_SECS)
|
||||||
};
|
};
|
||||||
|
|
||||||
REG if_reg[] = {
|
REG if_reg[] = {
|
||||||
{ HRDATAD (IRQ, if_irq, 1, "IRQ Set") },
|
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -90,36 +94,14 @@ DEVICE if_dev = {
|
||||||
IF_STATE if_state;
|
IF_STATE if_state;
|
||||||
uint8 if_buf[IF_SEC_SIZE];
|
uint8 if_buf[IF_SEC_SIZE];
|
||||||
uint32 if_sec_ptr = 0;
|
uint32 if_sec_ptr = 0;
|
||||||
t_bool if_irq = FALSE;
|
|
||||||
|
|
||||||
/* Function implementation */
|
/* Function implementation */
|
||||||
|
|
||||||
static SIM_INLINE void if_set_irq()
|
|
||||||
{
|
|
||||||
if_irq = TRUE;
|
|
||||||
#if defined(REV2)
|
|
||||||
csr_data |= CSRDISK;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static SIM_INLINE void if_clear_irq()
|
|
||||||
{
|
|
||||||
if_irq = FALSE;
|
|
||||||
#if defined(REV2)
|
|
||||||
csr_data &= ~CSRDISK;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static SIM_INLINE void if_activate(uint32 delay)
|
static SIM_INLINE void if_activate(uint32 delay)
|
||||||
{
|
{
|
||||||
sim_activate_abs(&if_unit, delay);
|
sim_activate_abs(&if_unit, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SIM_INLINE void if_cancel_pending_irq()
|
|
||||||
{
|
|
||||||
sim_cancel(&if_unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
t_stat if_svc(UNIT *uptr)
|
t_stat if_svc(UNIT *uptr)
|
||||||
{
|
{
|
||||||
uint32 lba; /* Logical block address for write */
|
uint32 lba; /* Logical block address for write */
|
||||||
|
@ -160,7 +142,7 @@ t_stat if_svc(UNIT *uptr)
|
||||||
|
|
||||||
/* Request an interrupt */
|
/* Request an interrupt */
|
||||||
sim_debug(IRQ_MSG, &if_dev, "\tINTR\n");
|
sim_debug(IRQ_MSG, &if_dev, "\tINTR\n");
|
||||||
if_set_irq();
|
SET_INT;
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
@ -200,7 +182,7 @@ uint32 if_read(uint32 pa, size_t size) {
|
||||||
data |= IF_NRDY;
|
data |= IF_NRDY;
|
||||||
}
|
}
|
||||||
/* Reading the status register always de-asserts the IRQ line */
|
/* Reading the status register always de-asserts the IRQ line */
|
||||||
if_clear_irq();
|
CLR_INT;
|
||||||
sim_debug(READ_MSG, &if_dev, "\tSTATUS\t%02x\n", data);
|
sim_debug(READ_MSG, &if_dev, "\tSTATUS\t%02x\n", data);
|
||||||
break;
|
break;
|
||||||
case IF_TRACK_REG:
|
case IF_TRACK_REG:
|
||||||
|
@ -535,13 +517,13 @@ void if_handle_command()
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((if_state.cmd & 0xf) == 0) {
|
if ((if_state.cmd & 0xf) == 0) {
|
||||||
if_cancel_pending_irq();
|
sim_cancel(&if_unit);
|
||||||
#if defined(REV2)
|
#if defined(REV2)
|
||||||
if_clear_irq(); /* TODO: Confirm this is right */
|
CLR_INT; /* TODO: Confirm this is right */
|
||||||
#endif
|
#endif
|
||||||
} else if ((if_state.cmd & 0x8) == 0x8) {
|
} else if ((if_state.cmd & 0x8) == 0x8) {
|
||||||
if_state.status |= IF_DRQ;
|
if_state.status |= IF_DRQ;
|
||||||
if_set_irq();
|
SET_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -563,7 +545,7 @@ void if_write(uint32 pa, uint32 val, size_t size)
|
||||||
case IF_CMD_REG:
|
case IF_CMD_REG:
|
||||||
if_state.cmd = (uint8) val;
|
if_state.cmd = (uint8) val;
|
||||||
/* Writing to the command register always de-asserts the IRQ line */
|
/* Writing to the command register always de-asserts the IRQ line */
|
||||||
if_clear_irq();
|
CLR_INT;
|
||||||
|
|
||||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||||
/* If not attached, do nothing */
|
/* If not attached, do nothing */
|
||||||
|
|
|
@ -127,6 +127,5 @@ CONST char *if_description(DEVICE *dptr);
|
||||||
t_stat if_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
t_stat if_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
|
|
||||||
extern IF_STATE if_state;
|
extern IF_STATE if_state;
|
||||||
extern t_bool if_irq;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
50
3B2/3b2_io.c
50
3B2/3b2_io.c
|
@ -30,24 +30,24 @@
|
||||||
|
|
||||||
#include "3b2_io.h"
|
#include "3b2_io.h"
|
||||||
|
|
||||||
#if defined(REV3)
|
|
||||||
#include "3b2_rev3_csr.h"
|
|
||||||
#include "3b2_rev3_mmu.h"
|
|
||||||
#else
|
|
||||||
#include "3b2_id.h"
|
|
||||||
#include "3b2_rev2_csr.h"
|
|
||||||
#include "3b2_rev2_mmu.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_dmac.h"
|
#include "3b2_dmac.h"
|
||||||
#include "3b2_if.h"
|
#include "3b2_if.h"
|
||||||
#include "3b2_iu.h"
|
#include "3b2_iu.h"
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
|
#include "3b2_mmu.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_stddev.h"
|
||||||
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
|
#if defined(REV2)
|
||||||
|
#include "3b2_id.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
CIO_STATE cio[CIO_SLOTS] = {{0}};
|
CIO_STATE cio[CIO_SLOTS] = {{0}};
|
||||||
|
|
||||||
|
uint16 cio_int_req = 0; /* Bitset of card slots requesting interrupts */
|
||||||
|
|
||||||
#if defined(REV3)
|
#if defined(REV3)
|
||||||
iolink iotable[] = {
|
iolink iotable[] = {
|
||||||
{ MMUBASE, MMUBASE+MMUSIZE, &mmu_read, &mmu_write },
|
{ MMUBASE, MMUBASE+MMUSIZE, &mmu_read, &mmu_write },
|
||||||
|
@ -99,10 +99,10 @@ void cio_clear(uint8 cid)
|
||||||
cio[cid].ivec = 0;
|
cio[cid].ivec = 0;
|
||||||
cio[cid].no_rque = 0;
|
cio[cid].no_rque = 0;
|
||||||
cio[cid].ipl = 0;
|
cio[cid].ipl = 0;
|
||||||
cio[cid].intr = FALSE;
|
|
||||||
cio[cid].sysgen_s = 0;
|
cio[cid].sysgen_s = 0;
|
||||||
cio[cid].seqbit = 0;
|
cio[cid].seqbit = 0;
|
||||||
cio[cid].op = 0;
|
cio[cid].op = 0;
|
||||||
|
CIO_CLR_INT(cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -490,7 +490,7 @@ uint32 io_read(uint32 pa, size_t size)
|
||||||
sim_debug(IO_DBG, &cpu_dev,
|
sim_debug(IO_DBG, &cpu_dev,
|
||||||
"[READ] [%08x] No card at cid=%d reg=%d\n",
|
"[READ] [%08x] No card at cid=%d reg=%d\n",
|
||||||
R[NUM_PC], cid, reg);
|
R[NUM_PC], cid, reg);
|
||||||
csr_data |= CSRTIMO;
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -594,7 +594,7 @@ uint32 io_read(uint32 pa, size_t size)
|
||||||
sim_debug(CIO_DBG, &cpu_dev,
|
sim_debug(CIO_DBG, &cpu_dev,
|
||||||
"[READ] [%08x] No card at cid=%d reg=%d\n",
|
"[READ] [%08x] No card at cid=%d reg=%d\n",
|
||||||
R[NUM_PC], cid, reg);
|
R[NUM_PC], cid, reg);
|
||||||
csr_data |= CSRTIMO;
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -611,7 +611,7 @@ uint32 io_read(uint32 pa, size_t size)
|
||||||
sim_debug(IO_DBG, &cpu_dev,
|
sim_debug(IO_DBG, &cpu_dev,
|
||||||
"[%08x] [io_read] ADDR=%08x: No device found.\n",
|
"[%08x] [io_read] ADDR=%08x: No device found.\n",
|
||||||
R[NUM_PC], pa);
|
R[NUM_PC], pa);
|
||||||
csr_data |= CSRTIMO;
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -621,6 +621,24 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
||||||
iolink *p;
|
iolink *p;
|
||||||
uint8 cid, reg;
|
uint8 cid, reg;
|
||||||
|
|
||||||
|
#if defined(REV3)
|
||||||
|
if (pa >= VCACHE_BOTTOM && pa < VCACHE_TOP) {
|
||||||
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pa >= BUB_BOTTOM && pa < BUB_TOP) {
|
||||||
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
|
/* TODO: I don't remember why we do this! */
|
||||||
|
if ((pa & 0xfff) == 3) {
|
||||||
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
|
}
|
||||||
|
/* TODO: Implement BUB */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Feature Card Area */
|
/* Feature Card Area */
|
||||||
if (pa >= CIO_BOTTOM && pa < CIO_TOP) {
|
if (pa >= CIO_BOTTOM && pa < CIO_TOP) {
|
||||||
cid = CID(pa);
|
cid = CID(pa);
|
||||||
|
@ -631,7 +649,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
||||||
sim_debug(CIO_DBG, &cpu_dev,
|
sim_debug(CIO_DBG, &cpu_dev,
|
||||||
"[WRITE] [%08x] No card at cid=%d reg=%d\n",
|
"[WRITE] [%08x] No card at cid=%d reg=%d\n",
|
||||||
R[NUM_PC], cid, reg);
|
R[NUM_PC], cid, reg);
|
||||||
csr_data |= CSRTIMO;
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -726,7 +744,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
||||||
sim_debug(CIO_DBG, &cpu_dev,
|
sim_debug(CIO_DBG, &cpu_dev,
|
||||||
"[WRITE] [%08x] No card at cid=%d reg=%d\n",
|
"[WRITE] [%08x] No card at cid=%d reg=%d\n",
|
||||||
R[NUM_PC], cid, reg);
|
R[NUM_PC], cid, reg);
|
||||||
csr_data |= CSRTIMO;
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -744,7 +762,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
||||||
sim_debug(IO_DBG, &cpu_dev,
|
sim_debug(IO_DBG, &cpu_dev,
|
||||||
"[%08x] [io_write] ADDR=%08x: No device found.\n",
|
"[%08x] [io_write] ADDR=%08x: No device found.\n",
|
||||||
R[NUM_PC], pa);
|
R[NUM_PC], pa);
|
||||||
csr_data |= CSRTIMO;
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,8 @@
|
||||||
#define CIO_INT1 2
|
#define CIO_INT1 2
|
||||||
#define CIO_SYSGEN 3
|
#define CIO_SYSGEN 3
|
||||||
|
|
||||||
|
#define CIO_SET_INT(slot) (cio_int_req |= (1 << slot))
|
||||||
|
#define CIO_CLR_INT(slot) (cio_int_req &= ~(1 << slot))
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint16 id; /* Card ID */
|
uint16 id; /* Card ID */
|
||||||
|
@ -174,7 +176,6 @@ typedef struct {
|
||||||
uint8 ivec; /* Interrupt Vector */
|
uint8 ivec; /* Interrupt Vector */
|
||||||
uint8 no_rque; /* Number of request queues */
|
uint8 no_rque; /* Number of request queues */
|
||||||
uint8 ipl; /* IPL that this card uses */
|
uint8 ipl; /* IPL that this card uses */
|
||||||
t_bool intr; /* Card needs to interrupt */
|
|
||||||
uint8 sysgen_s; /* Sysgen state */
|
uint8 sysgen_s; /* Sysgen state */
|
||||||
uint8 seqbit; /* Squence Bit */
|
uint8 seqbit; /* Squence Bit */
|
||||||
uint8 op; /* Last received opcode */
|
uint8 op; /* Last received opcode */
|
||||||
|
@ -245,6 +246,7 @@ void io_write(uint32 pa, uint32 val, size_t size);
|
||||||
void dump_entry(uint32 dbits, DEVICE *dev, CONST char *type,
|
void dump_entry(uint32 dbits, DEVICE *dev, CONST char *type,
|
||||||
uint32 esize, cio_entry *entry, uint8 *app_data);
|
uint32 esize, cio_entry *entry, uint8 *app_data);
|
||||||
|
|
||||||
|
extern uint16 cio_int_req;
|
||||||
extern CIO_STATE cio[CIO_SLOTS];
|
extern CIO_STATE cio[CIO_SLOTS];
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
88
3B2/3b2_iu.c
88
3B2/3b2_iu.c
|
@ -32,15 +32,44 @@
|
||||||
|
|
||||||
#include "sim_tmxr.h"
|
#include "sim_tmxr.h"
|
||||||
|
|
||||||
#if defined(REV3)
|
|
||||||
#include "3b2_rev3_csr.h"
|
|
||||||
#else
|
|
||||||
#include "3b2_rev2_csr.h"
|
|
||||||
#endif
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_dmac.h"
|
#include "3b2_dmac.h"
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_stddev.h"
|
||||||
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
|
#define SET_INT do { \
|
||||||
|
CPU_SET_INT(INT_UART); \
|
||||||
|
SET_CSR(CSRUART); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CLR_INT do { \
|
||||||
|
CPU_CLR_INT(INT_UART); \
|
||||||
|
CLR_CSR(CSRUART); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#if defined(REV3)
|
||||||
|
#define SET_DMA_INT do { \
|
||||||
|
CPU_SET_INT(INT_UART_DMA); \
|
||||||
|
SET_CSR(CSRDMA); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CLR_DMA_INT do { \
|
||||||
|
CPU_CLR_INT(INT_UART_DMA); \
|
||||||
|
CLR_CSR(CSRDMA); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define SET_DMA_INT do { \
|
||||||
|
CPU_SET_INT(INT_DMA); \
|
||||||
|
SET_CSR(CSRDMA); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CLR_DMA_INT do { \
|
||||||
|
CPU_CLR_INT(INT_DMA); \
|
||||||
|
CLR_CSR(CSRDMA); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Static function declarations */
|
/* Static function declarations */
|
||||||
static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 val);
|
static SIM_INLINE void iu_w_cmd(uint8 portno, uint8 val);
|
||||||
|
@ -310,8 +339,8 @@ void iu_txrdy_a_irq() {
|
||||||
(iu_console.stat & STS_TXR)) {
|
(iu_console.stat & STS_TXR)) {
|
||||||
sim_debug(EXECUTE_MSG, &tto_dev,
|
sim_debug(EXECUTE_MSG, &tto_dev,
|
||||||
"[iu_txrdy_a_irq()] Firing IRQ after transmit of %02x (%c)\n",
|
"[iu_txrdy_a_irq()] Firing IRQ after transmit of %02x (%c)\n",
|
||||||
(uint8) iu_console.txbuf, (char) iu_console.txbuf);
|
(uint8) iu_console.txbuf, PCHAR(iu_console.txbuf));
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,8 +350,8 @@ void iu_txrdy_b_irq() {
|
||||||
(iu_contty.stat & STS_TXR)) {
|
(iu_contty.stat & STS_TXR)) {
|
||||||
sim_debug(EXECUTE_MSG, &contty_dev,
|
sim_debug(EXECUTE_MSG, &contty_dev,
|
||||||
"[iu_txrdy_b_irq()] Firing IRQ after transmit of %02x (%c)\n",
|
"[iu_txrdy_b_irq()] Firing IRQ after transmit of %02x (%c)\n",
|
||||||
(uint8) iu_contty.txbuf, (char) iu_contty.txbuf);
|
(uint8) iu_contty.txbuf, PCHAR(iu_contty.txbuf));
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,7 +425,7 @@ t_stat iu_svc_tti(UNIT *uptr)
|
||||||
{
|
{
|
||||||
int32 temp;
|
int32 temp;
|
||||||
|
|
||||||
sim_clock_coschedule(uptr, tmxr_poll);
|
tmxr_clock_coschedule(uptr, tmxr_poll);
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
|
|
||||||
|
@ -423,7 +452,7 @@ t_stat iu_svc_tti(UNIT *uptr)
|
||||||
iu_console.stat |= STS_RXR;
|
iu_console.stat |= STS_RXR;
|
||||||
iu_state.istat |= ISTS_RAI;
|
iu_state.istat |= ISTS_RAI;
|
||||||
if (iu_state.imr & IMR_RXRA) {
|
if (iu_state.imr & IMR_RXRA) {
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -459,7 +488,7 @@ t_stat iu_svc_contty_rcv(UNIT *uptr)
|
||||||
contty_ldsc[ln].rcve = 1;
|
contty_ldsc[ln].rcve = 1;
|
||||||
iu_state.inprt &= ~(IU_DCDB);
|
iu_state.inprt &= ~(IU_DCDB);
|
||||||
iu_state.ipcr |= IU_DCDB;
|
iu_state.ipcr |= IU_DCDB;
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check for disconnect */
|
/* Check for disconnect */
|
||||||
|
@ -467,7 +496,7 @@ t_stat iu_svc_contty_rcv(UNIT *uptr)
|
||||||
contty_ldsc[0].rcve = 0;
|
contty_ldsc[0].rcve = 0;
|
||||||
iu_state.inprt |= IU_DCDB;
|
iu_state.inprt |= IU_DCDB;
|
||||||
iu_state.ipcr |= IU_DCDB;
|
iu_state.ipcr |= IU_DCDB;
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
} else if (iu_contty.conf & RX_EN) {
|
} else if (iu_contty.conf & RX_EN) {
|
||||||
tmxr_poll_rx(&contty_desc);
|
tmxr_poll_rx(&contty_desc);
|
||||||
|
|
||||||
|
@ -484,7 +513,7 @@ t_stat iu_svc_contty_rcv(UNIT *uptr)
|
||||||
iu_contty.stat |= STS_RXR;
|
iu_contty.stat |= STS_RXR;
|
||||||
iu_state.istat |= ISTS_RBI;
|
iu_state.istat |= ISTS_RBI;
|
||||||
if (iu_state.imr & IMR_RXRB) {
|
if (iu_state.imr & IMR_RXRB) {
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,7 +548,7 @@ t_stat iu_svc_timer(UNIT *uptr)
|
||||||
iu_state.istat |= ISTS_CRI;
|
iu_state.istat |= ISTS_CRI;
|
||||||
|
|
||||||
if (iu_state.imr & IMR_CTR) {
|
if (iu_state.imr & IMR_CTR) {
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -573,7 +602,7 @@ uint32 iu_read(uint32 pa, size_t size)
|
||||||
iu_console.stat &= ~(STS_RXR|STS_FFL);
|
iu_console.stat &= ~(STS_RXR|STS_FFL);
|
||||||
iu_state.istat &= ~ISTS_RAI;
|
iu_state.istat &= ~ISTS_RAI;
|
||||||
} else if (iu_state.imr & IMR_RXRA) {
|
} else if (iu_state.imr & IMR_RXRA) {
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -581,7 +610,7 @@ uint32 iu_read(uint32 pa, size_t size)
|
||||||
data = iu_state.ipcr;
|
data = iu_state.ipcr;
|
||||||
/* Reading the port resets it */
|
/* Reading the port resets it */
|
||||||
iu_state.ipcr = 0;
|
iu_state.ipcr = 0;
|
||||||
csr_data &= ~CSRUART;
|
CLR_INT;
|
||||||
break;
|
break;
|
||||||
case ISR:
|
case ISR:
|
||||||
data = iu_state.istat;
|
data = iu_state.istat;
|
||||||
|
@ -610,7 +639,7 @@ uint32 iu_read(uint32 pa, size_t size)
|
||||||
iu_contty.stat &= ~(STS_RXR|STS_FFL);
|
iu_contty.stat &= ~(STS_RXR|STS_FFL);
|
||||||
iu_state.istat &= ~ISTS_RBI;
|
iu_state.istat &= ~ISTS_RBI;
|
||||||
} else if (iu_state.imr & IMR_RXRB) {
|
} else if (iu_state.imr & IMR_RXRB) {
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -625,12 +654,12 @@ uint32 iu_read(uint32 pa, size_t size)
|
||||||
case STOP_CTR:
|
case STOP_CTR:
|
||||||
data = 0;
|
data = 0;
|
||||||
iu_state.istat &= ~ISTS_CRI;
|
iu_state.istat &= ~ISTS_CRI;
|
||||||
csr_data &= ~CSRUART;
|
CLR_INT;
|
||||||
sim_cancel(&iu_timer_unit);
|
sim_cancel(&iu_timer_unit);
|
||||||
break;
|
break;
|
||||||
case 17: /* Clear DMAC interrupt */
|
case 17: /* Clear DMAC interrupt */
|
||||||
data = 0;
|
data = 0;
|
||||||
csr_data &= ~CSRDMA;
|
CLR_DMA_INT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -681,7 +710,10 @@ void iu_write(uint32 pa, uint32 val, size_t size)
|
||||||
break;
|
break;
|
||||||
case IMR:
|
case IMR:
|
||||||
iu_state.imr = bval;
|
iu_state.imr = bval;
|
||||||
csr_data &= ~CSRUART;
|
sim_debug(EXECUTE_MSG, &tto_dev,
|
||||||
|
"[%08x] Write IMR = %x\n",
|
||||||
|
R[NUM_PC], bval);
|
||||||
|
CLR_INT;
|
||||||
/* Possibly cause an interrupt */
|
/* Possibly cause an interrupt */
|
||||||
iu_txrdy_a_irq();
|
iu_txrdy_a_irq();
|
||||||
iu_txrdy_b_irq();
|
iu_txrdy_b_irq();
|
||||||
|
@ -784,7 +816,7 @@ t_stat iu_tx(uint8 portno, uint8 val)
|
||||||
p->stat |= STS_RXR;
|
p->stat |= STS_RXR;
|
||||||
if (iu_state.imr & imr_mask) {
|
if (iu_state.imr & imr_mask) {
|
||||||
iu_state.istat |= ists;
|
iu_state.istat |= ists;
|
||||||
csr_data |= CSRUART;
|
SET_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -800,12 +832,12 @@ t_stat iu_tx(uint8 portno, uint8 val)
|
||||||
/* Write the character to the SIMH console */
|
/* Write the character to the SIMH console */
|
||||||
sim_debug(EXECUTE_MSG, &tto_dev,
|
sim_debug(EXECUTE_MSG, &tto_dev,
|
||||||
"[iu_tx] CONSOLE transmit %02x (%c)\n",
|
"[iu_tx] CONSOLE transmit %02x (%c)\n",
|
||||||
(uint8) c, (char) c);
|
(uint8) c, PCHAR(c));
|
||||||
status = sim_putchar_s(c);
|
status = sim_putchar_s(c);
|
||||||
} else {
|
} else {
|
||||||
sim_debug(EXECUTE_MSG, &contty_dev,
|
sim_debug(EXECUTE_MSG, &contty_dev,
|
||||||
"[iu_tx] CONTTY transmit %02x (%c)\n",
|
"[iu_tx] CONTTY transmit %02x (%c)\n",
|
||||||
(uint8) c, (char) c);
|
(uint8) c, PCHAR(c));
|
||||||
status = tmxr_putc_ln(&contty_ldsc[0], c);
|
status = tmxr_putc_ln(&contty_ldsc[0], c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -955,12 +987,16 @@ void iu_dma_console(uint8 channel, uint32 service_address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cancel any pending interrupts, we're done. */
|
||||||
|
/* TODO: I THINK THIS BREAKS EVERYTHING!!!! */
|
||||||
|
/* sim_cancel(uptr); */
|
||||||
|
|
||||||
/* Done with DMA */
|
/* Done with DMA */
|
||||||
port->dma = DMA_NONE;
|
port->dma = DMA_NONE;
|
||||||
|
|
||||||
dma_state.mask |= (1 << channel);
|
dma_state.mask |= (1 << channel);
|
||||||
dma_state.status |= (1 << channel);
|
dma_state.status |= (1 << channel);
|
||||||
csr_data |= CSRDMA;
|
SET_DMA_INT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iu_dma_contty(uint8 channel, uint32 service_address)
|
void iu_dma_contty(uint8 channel, uint32 service_address)
|
||||||
|
@ -1005,5 +1041,5 @@ void iu_dma_contty(uint8 channel, uint32 service_address)
|
||||||
|
|
||||||
dma_state.mask |= (1 << channel);
|
dma_state.mask |= (1 << channel);
|
||||||
dma_state.status |= (1 << channel);
|
dma_state.status |= (1 << channel);
|
||||||
csr_data |= CSRDMA;
|
SET_DMA_INT;
|
||||||
}
|
}
|
||||||
|
|
37
3B2/3b2_mau.h
Normal file
37
3B2/3b2_mau.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/* 3b2_mau.h: Common CSR header
|
||||||
|
|
||||||
|
Copyright (c) 2021, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _3B2_MAU_H_
|
||||||
|
#define _3B2_MAU_H_
|
||||||
|
|
||||||
|
/* TODO: Update when rev3 mau is implemented */
|
||||||
|
#include "3b2_rev2_mau.h"
|
||||||
|
|
||||||
|
#endif /* _3B2_MAU_H */
|
|
@ -30,16 +30,10 @@
|
||||||
|
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
|
|
||||||
#if defined(REV3)
|
|
||||||
#include "3b2_rev3_csr.h"
|
|
||||||
#include "3b2_rev3_mmu.h"
|
|
||||||
#else
|
|
||||||
#include "3b2_rev2_csr.h"
|
|
||||||
#include "3b2_rev2_mmu.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_io.h"
|
#include "3b2_io.h"
|
||||||
|
#include "3b2_mmu.h"
|
||||||
|
|
||||||
t_bool addr_is_rom(uint32 pa)
|
t_bool addr_is_rom(uint32 pa)
|
||||||
{
|
{
|
||||||
|
|
40
3B2/3b2_mmu.h
Normal file
40
3B2/3b2_mmu.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* 3b2_mmu.h: Common MMU header
|
||||||
|
|
||||||
|
Copyright (c) 2021, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _3B2_MMU_H_
|
||||||
|
#define _3B2_MMU_H_
|
||||||
|
|
||||||
|
#if defined(REV3)
|
||||||
|
#include "3b2_rev3_mmu.h"
|
||||||
|
#else
|
||||||
|
#include "3b2_rev2_mmu.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _3B2_MMU_H_ */
|
10
3B2/3b2_ni.c
10
3B2/3b2_ni.c
|
@ -97,7 +97,7 @@
|
||||||
|
|
||||||
#include "3b2_io.h"
|
#include "3b2_io.h"
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
/* State container for the card */
|
/* State container for the card */
|
||||||
NI_STATE ni;
|
NI_STATE ni;
|
||||||
|
@ -286,12 +286,12 @@ static void ni_disable()
|
||||||
sim_debug(DBG_TRACE, &ni_dev,
|
sim_debug(DBG_TRACE, &ni_dev,
|
||||||
"[ni_disable] Disabling the interface.\n");
|
"[ni_disable] Disabling the interface.\n");
|
||||||
ni.enabled = FALSE;
|
ni.enabled = FALSE;
|
||||||
cio[ni.cid].intr = FALSE;
|
|
||||||
sim_cancel(ni_unit);
|
sim_cancel(ni_unit);
|
||||||
sim_cancel(rcv_unit);
|
sim_cancel(rcv_unit);
|
||||||
sim_cancel(rq_unit);
|
sim_cancel(rq_unit);
|
||||||
sim_cancel(cio_unit);
|
sim_cancel(cio_unit);
|
||||||
sim_cancel(sanity_unit);
|
sim_cancel(sanity_unit);
|
||||||
|
CIO_CLR_INT(ni.cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ni_cmd(uint8 cid, cio_entry *rentry, uint8 *rapp_data, t_bool is_exp)
|
static void ni_cmd(uint8 cid, cio_entry *rentry, uint8 *rapp_data, t_bool is_exp)
|
||||||
|
@ -870,7 +870,7 @@ t_stat ni_sanity_svc(UNIT *uptr)
|
||||||
cio_cqueue(ni.cid, CIO_STAT, NIQESIZE, &cqe, app_data);
|
cio_cqueue(ni.cid, CIO_STAT, NIQESIZE, &cqe, app_data);
|
||||||
|
|
||||||
if (cio[ni.cid].ivec > 0) {
|
if (cio[ni.cid].ivec > 0) {
|
||||||
cio[ni.cid].intr = TRUE;
|
CIO_SET_INT(ni.cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
sim_activate_after(sanity_unit, NI_SANITY_INTERVAL_US);
|
sim_activate_after(sanity_unit, NI_SANITY_INTERVAL_US);
|
||||||
|
@ -885,7 +885,7 @@ t_stat ni_cio_svc(UNIT *uptr)
|
||||||
if (cio[ni.cid].ivec > 0) {
|
if (cio[ni.cid].ivec > 0) {
|
||||||
sim_debug(DBG_TRACE, &ni_dev,
|
sim_debug(DBG_TRACE, &ni_dev,
|
||||||
"[ni_cio_svc] Handling a CIO service (Setting Interrupt) for board %d\n", ni.cid);
|
"[ni_cio_svc] Handling a CIO service (Setting Interrupt) for board %d\n", ni.cid);
|
||||||
cio[ni.cid].intr = TRUE;
|
CIO_SET_INT(ni.cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
@ -952,7 +952,7 @@ void ni_process_packet()
|
||||||
|
|
||||||
/* Trigger an interrupt */
|
/* Trigger an interrupt */
|
||||||
if (cio[ni.cid].ivec > 0) {
|
if (cio[ni.cid].ivec > 0) {
|
||||||
cio[ni.cid].intr = TRUE;
|
CIO_SET_INT(ni.cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
#include "3b2_io.h"
|
#include "3b2_io.h"
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
/* Static function declarations */
|
/* Static function declarations */
|
||||||
static t_stat ports_show_queue_common(FILE *st, UNIT *uptr, int32 val,
|
static t_stat ports_show_queue_common(FILE *st, UNIT *uptr, int32 val,
|
||||||
|
@ -511,7 +511,7 @@ static void ports_update_conn(uint32 ln)
|
||||||
|
|
||||||
/* Interrupt */
|
/* Interrupt */
|
||||||
if (cio[cid].ivec > 0) {
|
if (cio[cid].ivec > 0) {
|
||||||
cio[cid].intr = TRUE;
|
CIO_SET_INT(cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,7 +677,7 @@ t_stat ports_cio_svc(UNIT *uptr)
|
||||||
ports_int_cid, ports_int_subdev);
|
ports_int_cid, ports_int_subdev);
|
||||||
|
|
||||||
if (cio[ports_int_cid].ivec > 0) {
|
if (cio[ports_int_cid].ivec > 0) {
|
||||||
cio[ports_int_cid].intr = TRUE;
|
CIO_SET_INT(ports_int_cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cio[ports_int_cid].op) {
|
switch (cio[ports_int_cid].op) {
|
||||||
|
@ -740,7 +740,7 @@ t_stat ports_rcv_svc(UNIT *uptr)
|
||||||
if (cio[cid].ivec > 0 &&
|
if (cio[cid].ivec > 0 &&
|
||||||
cio_rqueue(cid, PORTS_RCV_QUEUE,
|
cio_rqueue(cid, PORTS_RCV_QUEUE,
|
||||||
PPQESIZE, &rentry, rapp_data) == SCPE_OK) {
|
PPQESIZE, &rentry, rapp_data) == SCPE_OK) {
|
||||||
cio[cid].intr = TRUE;
|
CIO_SET_INT(cid);
|
||||||
|
|
||||||
/* Write the character to the memory address */
|
/* Write the character to the memory address */
|
||||||
pwrite_b(rentry.address, c);
|
pwrite_b(rentry.address, c);
|
||||||
|
@ -814,7 +814,7 @@ t_stat ports_xmt_svc(UNIT *uptr)
|
||||||
centry.address = ports_state[ln].tx_req_addr;
|
centry.address = ports_state[ln].tx_req_addr;
|
||||||
app_data[0] = RC_FLU;
|
app_data[0] = RC_FLU;
|
||||||
cio_cqueue(cid, CIO_STAT, PPQESIZE, ¢ry, app_data);
|
cio_cqueue(cid, CIO_STAT, PPQESIZE, ¢ry, app_data);
|
||||||
cio[cid].intr = TRUE;
|
CIO_SET_INT(cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
#include "3b2_sys.h"
|
#include "3b2_sys.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
uint16 csr_data;
|
uint16 csr_data;
|
||||||
|
|
||||||
|
@ -166,15 +166,19 @@ void csr_write(uint32 pa, uint32 val, size_t size)
|
||||||
break;
|
break;
|
||||||
case 0x33: /* Set PIR9 */
|
case 0x33: /* Set PIR9 */
|
||||||
csr_data |= CSRPIR9;
|
csr_data |= CSRPIR9;
|
||||||
|
CPU_SET_INT(INT_PIR9);
|
||||||
break;
|
break;
|
||||||
case 0x37: /* Clear PIR9 */
|
case 0x37: /* Clear PIR9 */
|
||||||
csr_data &= ~CSRPIR9;
|
csr_data &= ~CSRPIR9;
|
||||||
|
CPU_CLR_INT(INT_PIR9);
|
||||||
break;
|
break;
|
||||||
case 0x3b: /* Set PIR8 */
|
case 0x3b: /* Set PIR8 */
|
||||||
csr_data |= CSRPIR8;
|
csr_data |= CSRPIR8;
|
||||||
|
CPU_SET_INT(INT_PIR8);
|
||||||
break;
|
break;
|
||||||
case 0x3f: /* Clear PIR8 */
|
case 0x3f: /* Clear PIR8 */
|
||||||
csr_data &= ~CSRPIR8;
|
csr_data &= ~CSRPIR8;
|
||||||
|
CPU_CLR_INT(INT_PIR8);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -79,6 +79,18 @@
|
||||||
#define CSRDMA 0x0002 /* DMA Interrupt */
|
#define CSRDMA 0x0002 /* DMA Interrupt */
|
||||||
#define CSRIOF 0x0001 /* I/O Board Fail */
|
#define CSRIOF 0x0001 /* I/O Board Fail */
|
||||||
|
|
||||||
|
/* Interrupt Sources */
|
||||||
|
#define INT_SERR 0x01 /* IPL 15 */
|
||||||
|
#define INT_CLOCK 0x02 /* IPL 15 */
|
||||||
|
#define INT_DMA 0x04 /* IPL 13 */
|
||||||
|
#define INT_UART 0x04 /* IPL 13 */
|
||||||
|
#define INT_DISK 0x10 /* IPL 11 */
|
||||||
|
#define INT_FLOPPY 0x20 /* IPL 11 */
|
||||||
|
#define INT_PIR9 0x40 /* IPL 9 */
|
||||||
|
#define INT_PIR8 0x80 /* IPL 8 */
|
||||||
|
|
||||||
|
#define INT_MAP_LEN 0x100
|
||||||
|
|
||||||
/* Memory */
|
/* Memory */
|
||||||
#define MEMSIZE_REG 0x4C003
|
#define MEMSIZE_REG 0x4C003
|
||||||
#define MEMID_512K 0
|
#define MEMID_512K 0
|
||||||
|
|
|
@ -85,15 +85,9 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
/* TODO: Simplify after 3b2_rev3_mau is implemented */
|
|
||||||
#if defined(REV3)
|
|
||||||
#include "3b2_rev3_mmu.h"
|
|
||||||
#else
|
|
||||||
#include "3b2_rev2_mmu.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
|
#include "3b2_mmu.h"
|
||||||
|
|
||||||
#define MAU_ID 0 /* Coprocessor ID of MAU */
|
#define MAU_ID 0 /* Coprocessor ID of MAU */
|
||||||
|
|
||||||
|
@ -282,7 +276,11 @@ DEVICE mau_dev = {
|
||||||
NULL, /* attach routine */
|
NULL, /* attach routine */
|
||||||
NULL, /* detach routine */
|
NULL, /* detach routine */
|
||||||
NULL, /* context */
|
NULL, /* context */
|
||||||
DEV_DISABLE|DEV_DIS|DEV_DEBUG, /* flags */
|
#ifdef REV3
|
||||||
|
DEV_DEBUG, /* Rev 3 flags: Always required */
|
||||||
|
#else
|
||||||
|
DEV_DISABLE|DEV_DIS|DEV_DEBUG, /* Rev 2 flags */
|
||||||
|
#endif
|
||||||
0, /* debug control flags */
|
0, /* debug control flags */
|
||||||
mau_debug, /* debug flag names */
|
mau_debug, /* debug flag names */
|
||||||
NULL, /* memory size change */
|
NULL, /* memory size change */
|
||||||
|
|
|
@ -28,10 +28,10 @@
|
||||||
from the author.
|
from the author.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "3b2_rev2_mmu.h"
|
|
||||||
|
|
||||||
#include "3b2_sys.h"
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_mmu.h"
|
||||||
|
#include "3b2_sys.h"
|
||||||
|
|
||||||
UNIT mmu_unit = { UDATA(NULL, 0, 0) };
|
UNIT mmu_unit = { UDATA(NULL, 0, 0) };
|
||||||
|
|
||||||
|
|
|
@ -187,9 +187,6 @@
|
||||||
/* Shift and mask the flag bits for the current CPU mode */
|
/* Shift and mask the flag bits for the current CPU mode */
|
||||||
#define MMU_PERM(f) ((f >> ((3 - CPU_CM) * 2)) & 3)
|
#define MMU_PERM(f) ((f >> ((3 - CPU_CM) * 2)) & 3)
|
||||||
|
|
||||||
#define ROM_SIZE 0x10000
|
|
||||||
#define BOOT_CODE_SIZE 0x8000
|
|
||||||
|
|
||||||
/* Codes set in the MMU Fault register */
|
/* Codes set in the MMU Fault register */
|
||||||
#define MMU_F_SDTLEN 0x03
|
#define MMU_F_SDTLEN 0x03
|
||||||
#define MMU_F_PW 0x04
|
#define MMU_F_PW 0x04
|
||||||
|
|
|
@ -31,14 +31,16 @@
|
||||||
#include "3b2_defs.h"
|
#include "3b2_defs.h"
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_ctc.h"
|
#include "3b2_ctc.h"
|
||||||
#include "3b2_id.h"
|
#include "3b2_id.h"
|
||||||
#include "3b2_if.h"
|
#include "3b2_if.h"
|
||||||
#include "3b2_iu.h"
|
#include "3b2_iu.h"
|
||||||
#include "3b2_ni.h"
|
#include "3b2_ni.h"
|
||||||
#include "3b2_ports.h"
|
#include "3b2_ports.h"
|
||||||
#include "3b2_rev2_mau.h"
|
#include "3b2_mau.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_stddev.h"
|
||||||
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
char sim_name[] = "AT&T 3B2/400";
|
char sim_name[] = "AT&T 3B2/400";
|
||||||
|
|
||||||
|
|
401
3B2/3b2_rev2_timer.c
Normal file
401
3B2/3b2_rev2_timer.c
Normal file
|
@ -0,0 +1,401 @@
|
||||||
|
/* 3b2_rev2_timer.c: 8253 Interval Timer
|
||||||
|
|
||||||
|
Copyright (c) 2017, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8253 Timer.
|
||||||
|
*
|
||||||
|
* The 8253 Timer IC has three interval timers, which we treat here as
|
||||||
|
* three units.
|
||||||
|
*
|
||||||
|
* Note that this simulation is very specific to the 3B2, and not
|
||||||
|
* usable as a general purpose 8253 simulator.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
|
#include "3b2_defs.h"
|
||||||
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
|
#define SET_INT do { \
|
||||||
|
CPU_SET_INT(INT_CLOCK); \
|
||||||
|
SET_CSR(CSRCLK); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define CLR_INT do { \
|
||||||
|
CPU_CLR_INT(INT_CLOCK); \
|
||||||
|
CLR_CSR(CSRCLK); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
struct timer_ctr TIMERS[3];
|
||||||
|
|
||||||
|
int32 tmxr_poll = 16667;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The three timers, (A, B, C) run at different
|
||||||
|
* programmatially controlled frequencies, so each must be
|
||||||
|
* handled through a different service routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
UNIT timer_unit[] = {
|
||||||
|
{ UDATA(&timer0_svc, 0, 0) },
|
||||||
|
{ UDATA(&timer1_svc, UNIT_IDLE, 0) },
|
||||||
|
{ UDATA(&timer2_svc, 0, 0) },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
UNIT *timer_clk_unit = &timer_unit[1];
|
||||||
|
|
||||||
|
REG timer_reg[] = {
|
||||||
|
{ HRDATAD(DIVA, TIMERS[0].divider, 16, "Divider A") },
|
||||||
|
{ HRDATAD(STA, TIMERS[0].mode, 8, "Mode A") },
|
||||||
|
{ HRDATAD(DIVB, TIMERS[1].divider, 16, "Divider B") },
|
||||||
|
{ HRDATAD(STB, TIMERS[1].mode, 8, "Mode B") },
|
||||||
|
{ HRDATAD(DIVC, TIMERS[2].divider, 16, "Divider C") },
|
||||||
|
{ HRDATAD(STC, TIMERS[2].mode, 8, "Mode C") },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
MTAB timer_mod[] = {
|
||||||
|
{ MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, NULL, "SHUTDOWN",
|
||||||
|
&timer_set_shutdown, NULL, NULL, "Soft Power Shutdown" },
|
||||||
|
{ 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE timer_dev = {
|
||||||
|
"TIMER", timer_unit, timer_reg, timer_mod,
|
||||||
|
1, 16, 8, 4, 16, 32,
|
||||||
|
NULL, NULL, &timer_reset,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
DEV_DEBUG, 0, sys_deb_tab
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat timer_reset(DEVICE *dptr) {
|
||||||
|
int32 i, t;
|
||||||
|
|
||||||
|
memset(&TIMERS, 0, sizeof(struct timer_ctr) * 3);
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
timer_unit[i].tmrnum = i;
|
||||||
|
timer_unit[i].tmr = (void *)&TIMERS[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Timer 1 gate is always active */
|
||||||
|
TIMERS[1].gate = 1;
|
||||||
|
|
||||||
|
if (!sim_is_running) {
|
||||||
|
t = sim_rtcn_init_unit(timer_clk_unit, TPS_CLK, TMR_CLK);
|
||||||
|
sim_activate_after(timer_clk_unit, 1000000 / t);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_activate(uint8 ctrnum)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
|
||||||
|
switch (ctrnum) {
|
||||||
|
case TIMER_SANITY:
|
||||||
|
break;
|
||||||
|
case TIMER_INTERVAL:
|
||||||
|
if ((csr_data & CSRITIM) == 0) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] INTERVAL TIMER: Activating after %d ms\n",
|
||||||
|
R[NUM_PC], ctr->val);
|
||||||
|
sim_activate_after_abs(&timer_unit[ctrnum], ctr->val);
|
||||||
|
ctr->val--;
|
||||||
|
} else {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] INTERVAL TIMER: Currently disabled, not starting\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIMER_BUS:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_stat timer_set_shutdown(UNIT *uptr, int32 val, CONST char* cptr, void* desc)
|
||||||
|
{
|
||||||
|
struct timer_ctr *sanity = (struct timer_ctr *)timer_unit[0].tmr;
|
||||||
|
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] Setting sanity timer to 0 for shutdown.\n", R[NUM_PC]);
|
||||||
|
|
||||||
|
sanity->val = 0;
|
||||||
|
|
||||||
|
CLR_INT;
|
||||||
|
|
||||||
|
CPU_SET_INT(INT_SERR);
|
||||||
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_enable(uint8 ctrnum) {
|
||||||
|
timer_activate(ctrnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_disable(uint8 ctrnum)
|
||||||
|
{
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] Disabling timer %d\n",
|
||||||
|
R[NUM_PC], ctrnum);
|
||||||
|
sim_cancel(&timer_unit[ctrnum]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity Timer
|
||||||
|
*/
|
||||||
|
t_stat timer0_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
int32 time;
|
||||||
|
|
||||||
|
ctr = (struct timer_ctr *)uptr->tmr;
|
||||||
|
|
||||||
|
time = ctr->divider * TIMER_STP_US;
|
||||||
|
|
||||||
|
if (time == 0) {
|
||||||
|
time = TIMER_STP_US;
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_activate_after_abs(uptr, time);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interval Timer
|
||||||
|
*/
|
||||||
|
t_stat timer1_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
int32 t;
|
||||||
|
|
||||||
|
ctr = (struct timer_ctr *)uptr->tmr;
|
||||||
|
|
||||||
|
if (ctr->enabled && !(csr_data & CSRITIM)) {
|
||||||
|
/* Fire the IPL 15 clock interrupt */
|
||||||
|
SET_INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = sim_rtcn_calb(TPS_CLK, TMR_CLK);
|
||||||
|
sim_activate_after_abs(uptr, 1000000/TPS_CLK);
|
||||||
|
tmxr_poll = t;
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bus Timeout Timer
|
||||||
|
*/
|
||||||
|
t_stat timer2_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
int32 time;
|
||||||
|
|
||||||
|
ctr = (struct timer_ctr *)uptr->tmr;
|
||||||
|
|
||||||
|
time = ctr->divider * TIMER_STP_US;
|
||||||
|
|
||||||
|
if (time == 0) {
|
||||||
|
time = TIMER_STP_US;
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_activate_after_abs(uptr, time);
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 timer_read(uint32 pa, size_t size)
|
||||||
|
{
|
||||||
|
uint32 reg;
|
||||||
|
uint16 ctr_val;
|
||||||
|
uint8 ctrnum;
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
reg = pa - TIMERBASE;
|
||||||
|
ctrnum = (reg >> 2) & 0x3;
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case TIMER_REG_DIVA:
|
||||||
|
case TIMER_REG_DIVB:
|
||||||
|
case TIMER_REG_DIVC:
|
||||||
|
ctr_val = ctr->val;
|
||||||
|
|
||||||
|
if (ctr_val != ctr->divider) {
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] >>> ctr_val = %04x, ctr->divider = %04x\n",
|
||||||
|
R[NUM_PC], ctr_val, ctr->divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ctr->mode & CLK_RW) {
|
||||||
|
case CLK_LSB:
|
||||||
|
return ctr_val & 0xff;
|
||||||
|
case CLK_MSB:
|
||||||
|
return (ctr_val & 0xff00) >> 8;
|
||||||
|
case CLK_LMB:
|
||||||
|
if (ctr->lmb) {
|
||||||
|
ctr->lmb = FALSE;
|
||||||
|
return (ctr_val & 0xff00) >> 8;
|
||||||
|
} else {
|
||||||
|
ctr->lmb = TRUE;
|
||||||
|
return ctr_val & 0xff;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIMER_REG_CTRL:
|
||||||
|
return ctr->mode;
|
||||||
|
case TIMER_CLR_LATCH:
|
||||||
|
/* Clearing the timer latch has a side-effect
|
||||||
|
of also clearing pending interrupts */
|
||||||
|
CLR_INT;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* Unhandled */
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] UNHANDLED TIMER READ. ADDR=%08x\n",
|
||||||
|
R[NUM_PC], pa);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_timer_write(uint8 ctrnum, uint32 val)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
switch(ctr->mode & 0x30) {
|
||||||
|
case 0x10:
|
||||||
|
ctr->divider &= 0xff00;
|
||||||
|
ctr->divider |= val & 0xff;
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
ctr->enabled = TRUE;
|
||||||
|
ctr->stime = sim_gtime();
|
||||||
|
sim_cancel(timer_clk_unit);
|
||||||
|
sim_activate_after_abs(timer_clk_unit, ctr->divider * TIMER_STP_US);
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
ctr->divider &= 0x00ff;
|
||||||
|
ctr->divider |= (val & 0xff) << 8;
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
ctr->enabled = TRUE;
|
||||||
|
ctr->stime = sim_gtime();
|
||||||
|
/* Kick the timer to get the new divider value */
|
||||||
|
sim_cancel(timer_clk_unit);
|
||||||
|
sim_activate_after_abs(timer_clk_unit, ctr->divider * TIMER_STP_US);
|
||||||
|
break;
|
||||||
|
case 0x30:
|
||||||
|
if (ctr->lmb) {
|
||||||
|
ctr->lmb = FALSE;
|
||||||
|
ctr->divider = (uint16) ((ctr->divider & 0x00ff) | ((val & 0xff) << 8));
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
ctr->enabled = TRUE;
|
||||||
|
ctr->stime = sim_gtime();
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] Write timer %d val LMB (MSB): %02x\n",
|
||||||
|
R[NUM_PC], ctrnum, val & 0xff);
|
||||||
|
/* Kick the timer to get the new divider value */
|
||||||
|
sim_cancel(timer_clk_unit);
|
||||||
|
sim_activate_after_abs(timer_clk_unit, ctr->divider * TIMER_STP_US);
|
||||||
|
} else {
|
||||||
|
ctr->lmb = TRUE;
|
||||||
|
ctr->divider = (ctr->divider & 0xff00) | (val & 0xff);
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_write(uint32 pa, uint32 val, size_t size)
|
||||||
|
{
|
||||||
|
uint8 reg, ctrnum;
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
reg = (uint8) (pa - TIMERBASE);
|
||||||
|
|
||||||
|
switch(reg) {
|
||||||
|
case TIMER_REG_DIVA:
|
||||||
|
handle_timer_write(0, val);
|
||||||
|
break;
|
||||||
|
case TIMER_REG_DIVB:
|
||||||
|
handle_timer_write(1, val);
|
||||||
|
break;
|
||||||
|
case TIMER_REG_DIVC:
|
||||||
|
handle_timer_write(2, val);
|
||||||
|
break;
|
||||||
|
case TIMER_REG_CTRL:
|
||||||
|
/* The counter number is in bits 6 and 7 */
|
||||||
|
ctrnum = (val >> 6) & 3;
|
||||||
|
if (ctrnum > 2) {
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] WARNING: Write to invalid counter: %d\n",
|
||||||
|
R[NUM_PC], ctrnum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
ctr->mode = (uint8) val;
|
||||||
|
ctr->enabled = FALSE;
|
||||||
|
ctr->lmb = FALSE;
|
||||||
|
break;
|
||||||
|
case TIMER_CLR_LATCH:
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] unexpected write to clear timer latch\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_tick()
|
||||||
|
{
|
||||||
|
if (TIMERS[0].gate && TIMERS[0].enabled) {
|
||||||
|
TIMERS[0].val = TIMERS[0].divider - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TIMERS[1].gate && TIMERS[1].enabled) {
|
||||||
|
TIMERS[1].val = TIMERS[1].divider - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TIMERS[2].gate && TIMERS[2].enabled) {
|
||||||
|
TIMERS[2].val = TIMERS[2].divider - 1;
|
||||||
|
}
|
||||||
|
}
|
72
3B2/3b2_rev2_timer.h
Normal file
72
3B2/3b2_rev2_timer.h
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
/* 3b2_rev2_timer.h: 8253 Interval Timer
|
||||||
|
|
||||||
|
Copyright (c) 2017, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _3B2_REV2_TIMER_H_
|
||||||
|
#define _3B2_REV2_TIMER_H_
|
||||||
|
|
||||||
|
#include "sim_defs.h"
|
||||||
|
|
||||||
|
#define TIMER_STP_US 1
|
||||||
|
#define tmrnum u3
|
||||||
|
#define tmr up7
|
||||||
|
|
||||||
|
#define TIMER_REG_DIVA 0x03
|
||||||
|
#define TIMER_REG_DIVB 0x07
|
||||||
|
#define TIMER_REG_DIVC 0x0b
|
||||||
|
#define TIMER_REG_CTRL 0x0f
|
||||||
|
#define TIMER_CLR_LATCH 0x13
|
||||||
|
|
||||||
|
#define CLK_RW 0x30
|
||||||
|
#define CLK_LSB 0x10
|
||||||
|
#define CLK_MSB 0x20
|
||||||
|
#define CLK_LMB 0x30
|
||||||
|
|
||||||
|
struct timer_ctr {
|
||||||
|
uint16 divider;
|
||||||
|
uint16 val;
|
||||||
|
uint8 mode;
|
||||||
|
t_bool lmb;
|
||||||
|
t_bool enabled;
|
||||||
|
t_bool gate;
|
||||||
|
double stime; /* Most recent start time of counter */
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat timer_reset(DEVICE *dptr);
|
||||||
|
uint32 timer_read(uint32 pa, size_t size);
|
||||||
|
void timer_write(uint32 pa, uint32 val, size_t size);
|
||||||
|
void timer_tick();
|
||||||
|
t_stat timer0_svc(UNIT *uptr);
|
||||||
|
t_stat timer1_svc(UNIT *uptr);
|
||||||
|
t_stat timer2_svc(UNIT *uptr);
|
||||||
|
t_stat timer_set_shutdown(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
||||||
|
void timer_disable(uint8 ctrnum);
|
||||||
|
void timer_enable(uint8 ctrnum);
|
||||||
|
|
||||||
|
#endif /* _3B2_REV2_TIMER_H_ */
|
|
@ -28,11 +28,10 @@
|
||||||
from the author.
|
from the author.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "3b2_rev3_csr.h"
|
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_if.h"
|
#include "3b2_if.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
uint32 csr_data;
|
uint32 csr_data;
|
||||||
|
|
||||||
|
@ -131,6 +130,14 @@ uint32 csr_read(uint32 pa, size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define SET_INT(flag, val) { \
|
||||||
|
if (val) { \
|
||||||
|
CPU_SET_INT(flag); \
|
||||||
|
} else { \
|
||||||
|
CPU_CLR_INT(flag); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
void csr_write(uint32 pa, uint32 val, size_t size)
|
void csr_write(uint32 pa, uint32 val, size_t size)
|
||||||
{
|
{
|
||||||
uint32 reg = pa - CSRBASE;
|
uint32 reg = pa - CSRBASE;
|
||||||
|
@ -139,24 +146,31 @@ void csr_write(uint32 pa, uint32 val, size_t size)
|
||||||
|
|
||||||
case 0x00:
|
case 0x00:
|
||||||
CSRBIT(CSRCLK, val);
|
CSRBIT(CSRCLK, val);
|
||||||
|
SET_INT(INT_CLOCK, val);
|
||||||
break;
|
break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
CSRBIT(CSRPWRDN, val);
|
CSRBIT(CSRPWRDN, val);
|
||||||
|
SET_INT(INT_PWRDWN, val);
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
CSRBIT(CSROPINT15, val);
|
CSRBIT(CSROPINT15, val);
|
||||||
|
SET_INT(INT_BUS_OP, val);
|
||||||
break;
|
break;
|
||||||
case 0x0c:
|
case 0x0c:
|
||||||
CSRBIT(CSRUART, val);
|
CSRBIT(CSRUART, val);
|
||||||
|
SET_INT(INT_UART, val);
|
||||||
break;
|
break;
|
||||||
case 0x10:
|
case 0x10:
|
||||||
CSRBIT(CSRDMA, val);
|
CSRBIT(CSRDMA, val);
|
||||||
|
SET_INT(INT_UART_DMA, val);
|
||||||
break;
|
break;
|
||||||
case 0x14:
|
case 0x14:
|
||||||
CSRBIT(CSRPIR9, val);
|
CSRBIT(CSRPIR9, val);
|
||||||
|
SET_INT(INT_PIR9, val);
|
||||||
break;
|
break;
|
||||||
case 0x18:
|
case 0x18:
|
||||||
CSRBIT(CSRPIR8, val);
|
CSRBIT(CSRPIR8, val);
|
||||||
|
SET_INT(INT_PIR8, val);
|
||||||
break;
|
break;
|
||||||
case 0x1c:
|
case 0x1c:
|
||||||
CSRBIT(CSRITIM, val);
|
CSRBIT(CSRITIM, val);
|
||||||
|
@ -234,15 +248,31 @@ void csr_write(uint32 pa, uint32 val, size_t size)
|
||||||
break;
|
break;
|
||||||
case 0x5c:
|
case 0x5c:
|
||||||
CSRBIT(CSRSBERR, val);
|
CSRBIT(CSRSBERR, val);
|
||||||
|
if (val) {
|
||||||
|
if (!(csr_data & CSRISBERR)) {
|
||||||
|
SET_INT(INT_SBERR, TRUE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SET_INT(INT_SBERR, FALSE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x60:
|
case 0x60:
|
||||||
CSRBIT(CSRMBERR, val);
|
CSRBIT(CSRMBERR, val);
|
||||||
|
SET_INT(INT_MBERR, val);
|
||||||
break;
|
break;
|
||||||
case 0x64:
|
case 0x64:
|
||||||
CSRBIT(CSRUBUBF, val);
|
CSRBIT(CSRUBUBF, val);
|
||||||
|
SET_INT(INT_BUS_RXF, val);
|
||||||
break;
|
break;
|
||||||
case 0x68:
|
case 0x68:
|
||||||
CSRBIT(CSRTIMO, val);
|
CSRBIT(CSRTIMO, val);
|
||||||
|
if (val) {
|
||||||
|
if (!(csr_data & CSRITIMO)) {
|
||||||
|
SET_INT(INT_BUS_TMO, TRUE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SET_INT(INT_BUS_TMO, FALSE);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x6c:
|
case 0x6c:
|
||||||
CSRBIT(CSRFRF, val);
|
CSRBIT(CSRFRF, val);
|
||||||
|
|
|
@ -33,12 +33,63 @@
|
||||||
|
|
||||||
#define NUM_REGISTERS 32
|
#define NUM_REGISTERS 32
|
||||||
|
|
||||||
#define DEFMEMSIZE MSIZ_4M
|
#define DEFMEMSIZE MSIZ_16M
|
||||||
#define MAXMEMSIZE MSIZ_64M
|
#define MAXMEMSIZE MSIZ_64M
|
||||||
|
|
||||||
#define HWORD_OP_COUNT 12
|
#define HWORD_OP_COUNT 12
|
||||||
#define CPU_VERSION 0x1F /* Version encoded in WE32200 */
|
#define CPU_VERSION 0x1F /* Version encoded in WE32200 */
|
||||||
|
|
||||||
|
/* CSR Flags */
|
||||||
|
#define CSRCLK 1u /* UNIX Interval Timer Timeout */
|
||||||
|
#define CSRPWRDN (1u << 1) /* Power Down Request */
|
||||||
|
#define CSROPINT15 (1u << 2) /* Oper. Interrupt Level 15 */
|
||||||
|
#define CSRUART (1u << 3) /* DUART Interrupt */
|
||||||
|
#define CSRDMA (1u << 4) /* DUART DMA Complete Interrupt */
|
||||||
|
#define CSRPIR9 (1u << 5) /* Programmed Interrupt 9 */
|
||||||
|
#define CSRPIR8 (1u << 6) /* Programmed Interrupt 8 */
|
||||||
|
#define CSRITIM (1u << 7) /* Inhibit UNIX Interval Timer */
|
||||||
|
#define CSRISTIM (1u << 8) /* Inhibit System Sanity Timer */
|
||||||
|
#define CSRITIMO (1u << 9) /* Inhibit Bus Timer */
|
||||||
|
#define CSRICPUFLT (1u << 10) /* Inhibit Faults to CPU */
|
||||||
|
#define CSRISBERR (1u << 11) /* Inhibit Single Bit Error Rpt */
|
||||||
|
#define CSRIIOBUS (1u << 12) /* Inhibit Integral 3B2 I/O Bus */
|
||||||
|
#define CSRIBUB (1u << 13) /* Inhibit 4 BUB Slots */
|
||||||
|
#define CSRFECC (1u << 14) /* Force ECC Syndrome */
|
||||||
|
#define CSRTHERM (1u << 15) /* Thermal Shutdown Request */
|
||||||
|
#define CSRLED (1u << 16) /* Failure LED */
|
||||||
|
#define CSRPWRSPDN (1u << 17) /* Power Down -- Power Supply */
|
||||||
|
#define CSRFLPFST (1u << 18) /* Floppy Speed Fast */
|
||||||
|
#define CSRFLPS1 (1u << 19) /* Floppy Side 1 */
|
||||||
|
#define CSRFLPMO (1u << 20) /* Floppy Motor On */
|
||||||
|
#define CSRFLPDEN (1u << 21) /* Floppy Density */
|
||||||
|
#define CSRFLPSZ (1u << 22) /* Floppy Size */
|
||||||
|
#define CSRSBERR (1u << 23) /* Single Bit Error */
|
||||||
|
#define CSRMBERR (1u << 24) /* Multiple Bit Error */
|
||||||
|
#define CSRUBUBF (1u << 25) /* Ubus/BUB Received Fail */
|
||||||
|
#define CSRTIMO (1u << 26) /* Bus Timer Timeout */
|
||||||
|
#define CSRFRF (1u << 27) /* Fault Registers Frozen */
|
||||||
|
#define CSRALGN (1u << 28) /* Data Alignment Error */
|
||||||
|
#define CSRSTIMO (1u << 29) /* Sanity Timer Timeout */
|
||||||
|
#define CSRABRT (1u << 30) /* Abort Switch Activated */
|
||||||
|
#define CSRRRST (1u << 31) /* System Reset Request */
|
||||||
|
|
||||||
|
/* Interrupt Sources */
|
||||||
|
#define INT_CLOCK 0x0001 /* UNIX Interval Timer Timeout - IPL 15 */
|
||||||
|
#define INT_PWRDWN 0x0002 /* Power Down Request - IPL 15 */
|
||||||
|
#define INT_BUS_OP 0x0004 /* UBUS or BUB Operational Interrupt - IPL 15 */
|
||||||
|
#define INT_SBERR 0x0008 /* Single Bit Memory Error - IPL 15 */
|
||||||
|
#define INT_MBERR 0x0010 /* Multiple Bit Memory Error - IPL 15 */
|
||||||
|
#define INT_BUS_RXF 0x0020 /* UBUS, BUB, EIO Bus Received Fail - IPL 15 */
|
||||||
|
#define INT_BUS_TMO 0x0040 /* UBUS Timer Timeout - IPL 15 */
|
||||||
|
#define INT_UART_DMA 0x0080 /* UART DMA Complete - IPL 13 */
|
||||||
|
#define INT_UART 0x0100 /* UART Interrupt - IPL 13 */
|
||||||
|
#define INT_FLOPPY_DMA 0x0200 /* Floppy DMA Complete - IPL 11 */
|
||||||
|
#define INT_FLOPPY 0x0400 /* Floppy Interrupt - IPL 11 */
|
||||||
|
#define INT_PIR9 0x0800 /* PIR-9 (from CSER) - IPL 9 */
|
||||||
|
#define INT_PIR8 0x1000 /* PIR-8 (from CSER) - IPL 8 */
|
||||||
|
|
||||||
|
#define INT_MAP_LEN 0x2000
|
||||||
|
|
||||||
/* Memory */
|
/* Memory */
|
||||||
#define MEMID_4M 6
|
#define MEMID_4M 6
|
||||||
#define MEMID_16M 7
|
#define MEMID_16M 7
|
||||||
|
@ -95,38 +146,4 @@
|
||||||
#define DMA_IUB 0x47
|
#define DMA_IUB 0x47
|
||||||
#define DMA_C 0x48
|
#define DMA_C 0x48
|
||||||
|
|
||||||
/* CSR Flags */
|
|
||||||
#define CSRCLK 1u /* UNIX Interval Timer Timeout */
|
|
||||||
#define CSRPWRDN (1u << 1) /* Power Down Request */
|
|
||||||
#define CSROPINT15 (1u << 2) /* Oper. Interrupt Level 15 */
|
|
||||||
#define CSRUART (1u << 3) /* DUART Interrupt */
|
|
||||||
#define CSRDMA (1u << 4) /* DUART DMA Complete Interrupt */
|
|
||||||
#define CSRPIR9 (1u << 5) /* Programmed Interrupt 9 */
|
|
||||||
#define CSRPIR8 (1u << 6) /* Programmed Interrupt 8 */
|
|
||||||
#define CSRITIM (1u << 7) /* Inhibit UNIX Interval Timer */
|
|
||||||
#define CSRISTIM (1u << 8) /* Inhibit System Sanity Timer */
|
|
||||||
#define CSRITIMO (1u << 9) /* Inhibit Bus Timer */
|
|
||||||
#define CSRICPUFLT (1u << 10) /* Inhibit Faults to CPU */
|
|
||||||
#define CSRISBERR (1u << 11) /* Inhibit Single Bit Error Rpt */
|
|
||||||
#define CSRIIOBUS (1u << 12) /* Inhibit Integral 3B2 I/O Bus */
|
|
||||||
#define CSRIBUB (1u << 13) /* Inhibit 4 BUB Slots */
|
|
||||||
#define CSRFECC (1u << 14) /* Force ECC Syndrome */
|
|
||||||
#define CSRTHERM (1u << 15) /* Thermal Shutdown Request */
|
|
||||||
#define CSRLED (1u << 16) /* Failure LED */
|
|
||||||
#define CSRPWRSPDN (1u << 17) /* Power Down -- Power Supply */
|
|
||||||
#define CSRFLPFST (1u << 18) /* Floppy Speed Fast */
|
|
||||||
#define CSRFLPS1 (1u << 19) /* Floppy Side 1 */
|
|
||||||
#define CSRFLPMO (1u << 20) /* Floppy Motor On */
|
|
||||||
#define CSRFLPDEN (1u << 21) /* Floppy Density */
|
|
||||||
#define CSRFLPSZ (1u << 22) /* Floppy Size */
|
|
||||||
#define CSRSBERR (1u << 23) /* Single Bit Error */
|
|
||||||
#define CSRMBERR (1u << 24) /* Multiple Bit Error */
|
|
||||||
#define CSRUBUBF (1u << 25) /* Ubus/BUB Received Fail */
|
|
||||||
#define CSRTIMO (1u << 26) /* Bus Timer Timeout */
|
|
||||||
#define CSRFRF (1u << 27) /* Fault Registers Frozen */
|
|
||||||
#define CSRALGN (1u << 28) /* Data Alignment Error */
|
|
||||||
#define CSRSTIMO (1u << 29) /* Sanity Timer Timeout */
|
|
||||||
#define CSRABRT (1u << 30) /* Abort Switch Activated */
|
|
||||||
#define CSRRRST (1u << 31) /* System Reset Request */
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,11 +28,11 @@
|
||||||
from the author.
|
from the author.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "3b2_rev3_mmu.h"
|
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_mem.h"
|
#include "3b2_mem.h"
|
||||||
#include "3b2_rev3_csr.h"
|
#include "3b2_mmu.h"
|
||||||
|
|
||||||
UNIT mmu_unit = { UDATA(NULL, 0, 0) };
|
UNIT mmu_unit = { UDATA(NULL, 0, 0) };
|
||||||
|
|
||||||
|
|
|
@ -167,14 +167,14 @@
|
||||||
#define SDC_IDX(va) ((uint8)((va) >> 17) & 7)
|
#define SDC_IDX(va) ((uint8)((va) >> 17) & 7)
|
||||||
|
|
||||||
/* Convert from sd to sd cache entry */
|
/* Convert from sd to sd cache entry */
|
||||||
#define SD_TO_SDCH(hi,lo) ((hi) & SD_ADDR_MASK | \
|
#define SD_TO_SDCH(hi,lo) (((hi) & SD_ADDR_MASK) | \
|
||||||
((lo) & SD_C_MASK) >> 1 | \
|
((lo) & SD_C_MASK) >> 1 | \
|
||||||
((lo) & SD_CACHE_MASK) >> 1 | \
|
((lo) & SD_CACHE_MASK) >> 1 | \
|
||||||
(SDC_G_MASK))
|
(SDC_G_MASK))
|
||||||
#define SD_TO_SDCL(lo,va) (((lo) & SD_ACC_MASK) | \
|
#define SD_TO_SDCL(lo,va) (((lo) & SD_ACC_MASK) | \
|
||||||
((lo) & SD_MAX_OFF_MASK) >> 3 | \
|
((lo) & SD_MAX_OFF_MASK) >> 3 | \
|
||||||
((lo) & SD_R_MASK) << 18 | \
|
((lo) & SD_R_MASK) << 18 | \
|
||||||
((lo) & SD_M_MASK) << 21 | \
|
((lo) & SD_M_MASK) << 21 | \
|
||||||
((va) & SD_VADDR_MASK) >> 20)
|
((va) & SD_VADDR_MASK) >> 20)
|
||||||
|
|
||||||
/* Convert from sd cache entry to sd */
|
/* Convert from sd cache entry to sd */
|
||||||
|
@ -188,18 +188,18 @@
|
||||||
SD_V_MASK | SD_P_MASK)
|
SD_V_MASK | SD_P_MASK)
|
||||||
|
|
||||||
/* Convert from pd cache entry to pd */
|
/* Convert from pd cache entry to pd */
|
||||||
#define PDCE_TO_PD(pdcl) (((pdcl & PDC_PADDR_MASK) << 11) | \
|
#define PDCE_TO_PD(pdcl) ((((pdcl) & PDC_PADDR_MASK) << 11) | \
|
||||||
((pdcl & PDC_W_MASK) >> 17) | \
|
(((pdcl) & PDC_W_MASK) >> 17) | \
|
||||||
((pdcl & PDC_M_MASK) >> 21) | \
|
(((pdcl) & PDC_M_MASK) >> 21) | \
|
||||||
((pdcl & PDC_R_MASK) >> 18) | \
|
(((pdcl) & PDC_R_MASK) >> 18) | \
|
||||||
PD_P_MASK)
|
PD_P_MASK)
|
||||||
|
|
||||||
/* Convert from pd to pd cache entry (low word) */
|
/* Convert from pd to pd cache entry (low word) */
|
||||||
#define PD_TO_PDCL(pd, sd_lo) (((pd & PD_PADDR_MASK) >> 11) | \
|
#define PD_TO_PDCL(pd, sd_lo) ((((pd) & PD_PADDR_MASK) >> 11) | \
|
||||||
((pd & PD_W_MASK) << 17) | \
|
(((pd) & PD_W_MASK) << 17) | \
|
||||||
((pd & PD_M_MASK) << 21) | \
|
(((pd) & PD_M_MASK) << 21) | \
|
||||||
((pd & PD_R_MASK) << 18) | \
|
(((pd) & PD_R_MASK) << 18) | \
|
||||||
(sd_lo & SD_ACC_MASK))
|
((sd_lo) & SD_ACC_MASK))
|
||||||
|
|
||||||
/* Convert from va to pd cache entry (high word / tag) */
|
/* Convert from va to pd cache entry (high word / tag) */
|
||||||
#define VA_TO_PDCH(va, sd_lo) ((1 << 30) | \
|
#define VA_TO_PDCH(va, sd_lo) ((1 << 30) | \
|
||||||
|
|
|
@ -31,13 +31,15 @@
|
||||||
#include "3b2_defs.h"
|
#include "3b2_defs.h"
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
#include "3b2_if.h"
|
#include "3b2_if.h"
|
||||||
#include "3b2_iu.h"
|
#include "3b2_iu.h"
|
||||||
|
#include "3b2_mau.h"
|
||||||
#include "3b2_ni.h"
|
#include "3b2_ni.h"
|
||||||
#include "3b2_ports.h"
|
#include "3b2_ports.h"
|
||||||
#include "3b2_rev2_mau.h" /* TODO: Replace with Rev 3 MAU when implemented */
|
|
||||||
#include "3b2_scsi.h"
|
#include "3b2_scsi.h"
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_stddev.h"
|
||||||
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
char sim_name[] = "AT&T 3B2/600G";
|
char sim_name[] = "AT&T 3B2/600G";
|
||||||
|
|
||||||
|
|
506
3B2/3b2_rev3_timer.c
Normal file
506
3B2/3b2_rev3_timer.c
Normal file
|
@ -0,0 +1,506 @@
|
||||||
|
/* 3b2_rev3_timer.c: 82C54 Interval Timer.
|
||||||
|
|
||||||
|
Copyright (c) 2021, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 82C54 Timer.
|
||||||
|
*
|
||||||
|
* 82C54 (Rev3) Timer IC has three interval timers, which we treat
|
||||||
|
* here as three units.
|
||||||
|
*
|
||||||
|
* In the 3B2, the three timers are assigned specific purposes:
|
||||||
|
*
|
||||||
|
* - Timer 0: SYSTEM SANITY TIMER. This timer is normally loaded with
|
||||||
|
* a short timeout and allowed to run. If it times out, it
|
||||||
|
* will generate an interrupt and cause a system
|
||||||
|
* error. Software resets the timer regularly to ensure
|
||||||
|
* that it does not time out. It is fed by a 10 kHz
|
||||||
|
* clock, so each single counting step of this timer is
|
||||||
|
* 100 microseconds.
|
||||||
|
*
|
||||||
|
* - Timer 1: UNIX INTERVAL TIMER. This is the main timer that drives
|
||||||
|
* process switching in Unix. It operates at a fixed rate,
|
||||||
|
* and the counter is set up by Unix to generate an
|
||||||
|
* interrupt once every 10 milliseconds. The timer is fed
|
||||||
|
* by a 100 kHz clock, so each single counting step of
|
||||||
|
* this timer is 10 microseconds.
|
||||||
|
*
|
||||||
|
* - Timer 2: BUS TIMEOUT TIMER. This timer is reset every time the
|
||||||
|
* IO bus is accessed, and then stopped when the IO bus
|
||||||
|
* responds. It is mainly used to determine when the IO
|
||||||
|
* bus is hung (e.g., no card is installed in a given
|
||||||
|
* slot, so nothing can respond). When it times out, it
|
||||||
|
* generates an interrupt. It is fed by a 500 kHz clock,
|
||||||
|
* so each single counting step of this timer is 2
|
||||||
|
* microseconds.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Implementaiton Notes
|
||||||
|
* ====================
|
||||||
|
*
|
||||||
|
* In general, no attempt has been made to create an accurate
|
||||||
|
* emulation of the 82C54 timer. This implementation is truly built
|
||||||
|
* for the 3B2, and even more specifically for System V Unix, which is
|
||||||
|
* the only operating system ever to have been ported to the 3B2.
|
||||||
|
*
|
||||||
|
* - The Bus Timeout Timer is not implemented other than a stub that
|
||||||
|
* is designed to pass hardware diagnostics. The simulator IO
|
||||||
|
* subsystem always sets the correct interrupt directly if the bus
|
||||||
|
* will not respond.
|
||||||
|
*
|
||||||
|
* - The System Sanity Timer is also not implemented other than a
|
||||||
|
* stub to pass diagnostics.
|
||||||
|
*
|
||||||
|
* - The main Unix Interval Timer is implemented as a true SIMH clock
|
||||||
|
* when set up for the correct mode. In other modes, it likewise
|
||||||
|
* implements a stub designed to pass diagnostics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
|
#include "3b2_defs.h"
|
||||||
|
#include "3b2_timer.h"
|
||||||
|
|
||||||
|
struct timer_ctr TIMERS[3];
|
||||||
|
|
||||||
|
int32 tmxr_poll = 16667;
|
||||||
|
|
||||||
|
UNIT timer_unit[] = {
|
||||||
|
{ UDATA(&timer0_svc, 0, 0) },
|
||||||
|
{ UDATA(&timer1_svc, UNIT_IDLE, 0) },
|
||||||
|
{ UDATA(&timer2_svc, 0, 0) },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
UNIT *timer_clk_unit = &timer_unit[1];
|
||||||
|
|
||||||
|
REG timer_reg[] = {
|
||||||
|
{ HRDATAD(DIV0, TIMERS[0].divider, 16, "Divider (0)") },
|
||||||
|
{ HRDATAD(COUNT0, TIMERS[0].val, 16, "Count (0)") },
|
||||||
|
{ HRDATAD(CTRL0, TIMERS[0].ctrl, 8, "Control (0)") },
|
||||||
|
{ HRDATAD(DIV1, TIMERS[1].divider, 16, "Divider (1)") },
|
||||||
|
{ HRDATAD(COUNT1, TIMERS[1].val, 16, "Count (1)") },
|
||||||
|
{ HRDATAD(CTRL1, TIMERS[1].ctrl, 8, "Control (1)") },
|
||||||
|
{ HRDATAD(DIV2, TIMERS[2].divider, 16, "Divider (2)") },
|
||||||
|
{ HRDATAD(COUNT2, TIMERS[2].val, 16, "Count (2)") },
|
||||||
|
{ HRDATAD(CTRL2, TIMERS[2].ctrl, 8, "Control (2)") },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
DEVICE timer_dev = {
|
||||||
|
"TIMER", timer_unit, timer_reg, NULL,
|
||||||
|
1, 16, 8, 4, 16, 32,
|
||||||
|
NULL, NULL, &timer_reset,
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
DEV_DEBUG, 0, sys_deb_tab
|
||||||
|
};
|
||||||
|
|
||||||
|
t_stat timer_reset(DEVICE *dptr) {
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
memset(&TIMERS, 0, sizeof(struct timer_ctr) * 3);
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) {
|
||||||
|
timer_unit[i].tmrnum = i;
|
||||||
|
timer_unit[i].tmr = (void *)&TIMERS[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: I don't think this is right. Verify. */
|
||||||
|
/*
|
||||||
|
if (!sim_is_running) {
|
||||||
|
t = sim_rtcn_init_unit(timer_clk_unit, TPS_CLK, TMR_CLK);
|
||||||
|
sim_activate_after_abs(timer_clk_unit, 1000000 / t);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void timer_activate(uint8 ctrnum)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
|
||||||
|
switch (ctrnum) {
|
||||||
|
case TIMER_SANITY:
|
||||||
|
if ((csr_data & CSRISTIM) == 0) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] SANITY TIMER: Activating after %d steps\n",
|
||||||
|
R[NUM_PC], ctr->val);
|
||||||
|
sim_activate_abs(&timer_unit[ctrnum], ctr->val);
|
||||||
|
ctr->val--;
|
||||||
|
} else {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] SANITY TIMER: Currently disabled, not starting\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIMER_INTERVAL:
|
||||||
|
if ((csr_data & CSRITIM) == 0) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] INTERVAL TIMER: Activating after %d ms\n",
|
||||||
|
R[NUM_PC], ctr->val);
|
||||||
|
sim_activate_after_abs(&timer_unit[ctrnum], ctr->val);
|
||||||
|
ctr->val--;
|
||||||
|
} else {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] INTERVAL TIMER: Currently disabled, not starting\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIMER_BUS:
|
||||||
|
if ((csr_data & CSRITIMO) == 0) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] BUS TIMER: Activating after %d steps\n",
|
||||||
|
R[NUM_PC], ctr->val);
|
||||||
|
sim_activate_abs(&timer_unit[ctrnum], (ctr->val - 2));
|
||||||
|
ctr->val -= 2;
|
||||||
|
} else {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] BUS TIMER: Currently disabled, not starting\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_enable(uint8 ctrnum)
|
||||||
|
{
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] Enabling timer %d\n",
|
||||||
|
R[NUM_PC], ctrnum);
|
||||||
|
timer_activate(ctrnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_disable(uint8 ctrnum)
|
||||||
|
{
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] Disabling timer %d\n",
|
||||||
|
R[NUM_PC], ctrnum);
|
||||||
|
sim_cancel(&timer_unit[ctrnum]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity Timer
|
||||||
|
*/
|
||||||
|
t_stat timer0_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
ctr = (struct timer_ctr *)uptr->tmr;
|
||||||
|
|
||||||
|
if (ctr->enabled) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] TIMER 0 COMPLETION.\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
if (!(csr_data & CSRISTIM)) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] TIMER 0 NMI IRQ.\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
ctr->val = 0xffff;
|
||||||
|
cpu_nmi = TRUE;
|
||||||
|
CSRBIT(CSRSTIMO, TRUE);
|
||||||
|
CPU_SET_INT(INT_BUS_TMO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interval Timer
|
||||||
|
*/
|
||||||
|
t_stat timer1_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
int32 t;
|
||||||
|
|
||||||
|
ctr = (struct timer_ctr *)uptr->tmr;
|
||||||
|
|
||||||
|
if (ctr->enabled && !(csr_data & CSRITIM)) {
|
||||||
|
/* Fire the IPL 15 clock interrupt */
|
||||||
|
CSRBIT(CSRCLK, TRUE);
|
||||||
|
CPU_SET_INT(INT_CLOCK);
|
||||||
|
}
|
||||||
|
|
||||||
|
t = sim_rtcn_calb(TPS_CLK, TMR_CLK);
|
||||||
|
sim_activate_after_abs(uptr, 1000000/TPS_CLK);
|
||||||
|
tmxr_poll = t;
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bus Timeout Timer
|
||||||
|
*/
|
||||||
|
t_stat timer2_svc(UNIT *uptr)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
ctr = (struct timer_ctr *)uptr->tmr;
|
||||||
|
|
||||||
|
if (ctr->enabled && TIMER_RW(ctr) == CLK_LSB) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] TIMER 2 COMPLETION.\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
if (!(csr_data & CSRITIMO)) {
|
||||||
|
sim_debug(EXECUTE_MSG, &timer_dev,
|
||||||
|
"[%08x] TIMER 2 IRQ.\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
ctr->val = 0xffff;
|
||||||
|
CSRBIT(CSRTIMO, TRUE);
|
||||||
|
CPU_SET_INT(INT_BUS_TMO);
|
||||||
|
/* Also trigger a bus abort */
|
||||||
|
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCPE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 timer_read(uint32 pa, size_t size)
|
||||||
|
{
|
||||||
|
uint32 reg;
|
||||||
|
uint16 ctr_val;
|
||||||
|
uint8 ctrnum, retval;
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
reg = pa - TIMERBASE;
|
||||||
|
ctrnum = (reg >> 2) & 0x3;
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case TIMER_REG_DIVA:
|
||||||
|
case TIMER_REG_DIVB:
|
||||||
|
case TIMER_REG_DIVC:
|
||||||
|
ctr_val = ctr->val;
|
||||||
|
|
||||||
|
switch (TIMER_RW(ctr)) {
|
||||||
|
case CLK_LSB:
|
||||||
|
retval = ctr_val & 0xff;
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, retval, retval);
|
||||||
|
break;
|
||||||
|
case CLK_MSB:
|
||||||
|
retval = (ctr_val & 0xff00) >> 8;
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [MSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, retval, retval);
|
||||||
|
break;
|
||||||
|
case CLK_LMB:
|
||||||
|
if (ctr->r_ctrl_latch) {
|
||||||
|
ctr->r_ctrl_latch = FALSE;
|
||||||
|
retval = ctr->ctrl_latch;
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LATCH CTRL] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, retval, retval);
|
||||||
|
} else if (ctr->r_cnt_latch) {
|
||||||
|
if (ctr->r_lmb) {
|
||||||
|
ctr->r_lmb = FALSE;
|
||||||
|
retval = (ctr->cnt_latch & 0xff00) >> 8;
|
||||||
|
ctr->r_cnt_latch = FALSE;
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LATCH DATA MSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, retval, retval);
|
||||||
|
} else {
|
||||||
|
ctr->r_lmb = TRUE;
|
||||||
|
retval = ctr->cnt_latch & 0xff;
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LATCH DATA LSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, retval, retval);
|
||||||
|
}
|
||||||
|
} else if (ctr->r_lmb) {
|
||||||
|
ctr->r_lmb = FALSE;
|
||||||
|
retval = (ctr_val & 0xff00) >> 8;
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LMB - MSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, retval, retval);
|
||||||
|
} else {
|
||||||
|
ctr->r_lmb = TRUE;
|
||||||
|
retval = ctr_val & 0xff;
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LMB - LSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, retval, retval);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
case TIMER_REG_CTRL:
|
||||||
|
return ctr->ctrl;
|
||||||
|
case TIMER_CLR_LATCH:
|
||||||
|
/* Clearing the timer latch has a side-effect
|
||||||
|
of also clearing pending interrupts */
|
||||||
|
CSRBIT(CSRCLK, FALSE);
|
||||||
|
CPU_CLR_INT(INT_CLOCK);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
/* Unhandled */
|
||||||
|
sim_debug(READ_MSG, &timer_dev,
|
||||||
|
"[%08x] UNHANDLED TIMER READ. ADDR=%08x\n",
|
||||||
|
R[NUM_PC], pa);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_timer_write(uint8 ctrnum, uint32 val)
|
||||||
|
{
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
UNIT *unit = &timer_unit[ctrnum];
|
||||||
|
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
ctr->enabled = TRUE;
|
||||||
|
|
||||||
|
switch(TIMER_RW(ctr)) {
|
||||||
|
case CLK_LSB:
|
||||||
|
ctr->divider = val & 0xff;
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, val & 0xff, val & 0xff);
|
||||||
|
timer_activate(ctrnum);
|
||||||
|
break;
|
||||||
|
case CLK_MSB:
|
||||||
|
ctr->divider = (val & 0xff) << 8;
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [MSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, val & 0xff, val & 0xff);
|
||||||
|
timer_activate(ctrnum);
|
||||||
|
break;
|
||||||
|
case CLK_LMB:
|
||||||
|
if (ctr->w_lmb) {
|
||||||
|
ctr->w_lmb = FALSE;
|
||||||
|
ctr->divider = (uint16) ((ctr->divider & 0x00ff) | ((val & 0xff) << 8));
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LMB - MSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, val & 0xff, val & 0xff);
|
||||||
|
timer_activate(ctrnum);
|
||||||
|
} else {
|
||||||
|
ctr->w_lmb = TRUE;
|
||||||
|
ctr->divider = (ctr->divider & 0xff00) | (val & 0xff);
|
||||||
|
ctr->val = ctr->divider;
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] [%d] [LMB - LSB] val=%d (0x%x)\n",
|
||||||
|
R[NUM_PC], ctrnum, val & 0xff, val & 0xff);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_write(uint32 pa, uint32 val, size_t size)
|
||||||
|
{
|
||||||
|
uint8 reg, ctrnum;
|
||||||
|
struct timer_ctr *ctr;
|
||||||
|
|
||||||
|
reg = (uint8) (pa - TIMERBASE);
|
||||||
|
|
||||||
|
switch(reg) {
|
||||||
|
case TIMER_REG_DIVA:
|
||||||
|
handle_timer_write(0, val);
|
||||||
|
break;
|
||||||
|
case TIMER_REG_DIVB:
|
||||||
|
handle_timer_write(1, val);
|
||||||
|
break;
|
||||||
|
case TIMER_REG_DIVC:
|
||||||
|
handle_timer_write(2, val);
|
||||||
|
break;
|
||||||
|
case TIMER_REG_CTRL:
|
||||||
|
ctrnum = (val >> 6) & 3;
|
||||||
|
if (ctrnum == 3) {
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] READ BACK COMMAND. DATA=%02x\n",
|
||||||
|
R[NUM_PC], val);
|
||||||
|
if (val & 2) {
|
||||||
|
ctr = &TIMERS[0];
|
||||||
|
if ((val & 0x20) == 0) {
|
||||||
|
ctr->ctrl_latch = (uint16) TIMERS[2].ctrl;
|
||||||
|
ctr->r_ctrl_latch = TRUE;
|
||||||
|
}
|
||||||
|
if ((val & 0x20) == 0) {
|
||||||
|
ctr->cnt_latch = ctr->val;
|
||||||
|
ctr->r_cnt_latch = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val & 4) {
|
||||||
|
ctr = &TIMERS[1];
|
||||||
|
if ((val & 0x10) == 0) {
|
||||||
|
ctr->ctrl_latch = (uint16) TIMERS[2].ctrl;
|
||||||
|
ctr->r_ctrl_latch = TRUE;
|
||||||
|
}
|
||||||
|
if ((val & 0x20) == 0) {
|
||||||
|
ctr->cnt_latch = ctr->val;
|
||||||
|
ctr->r_cnt_latch = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (val & 8) {
|
||||||
|
ctr = &TIMERS[2];
|
||||||
|
if ((val & 0x10) == 0) {
|
||||||
|
ctr->ctrl_latch = (uint16) TIMERS[2].ctrl;
|
||||||
|
ctr->r_ctrl_latch = TRUE;
|
||||||
|
}
|
||||||
|
if ((val & 0x20) == 0) {
|
||||||
|
ctr->cnt_latch = ctr->val;
|
||||||
|
ctr->r_cnt_latch = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] Timer Control Write: timer %d => %02x\n",
|
||||||
|
R[NUM_PC], ctrnum, val & 0xff);
|
||||||
|
ctr = &TIMERS[ctrnum];
|
||||||
|
ctr->ctrl = (uint8) val;
|
||||||
|
ctr->enabled = FALSE;
|
||||||
|
ctr->w_lmb = FALSE;
|
||||||
|
ctr->r_lmb = FALSE;
|
||||||
|
ctr->val = 0xffff;
|
||||||
|
ctr->divider = 0xffff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TIMER_CLR_LATCH:
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] unexpected write to clear timer latch\n",
|
||||||
|
R[NUM_PC]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sim_debug(WRITE_MSG, &timer_dev,
|
||||||
|
"[%08x] unknown timer register: %d\n",
|
||||||
|
R[NUM_PC], reg);
|
||||||
|
}
|
||||||
|
}
|
79
3B2/3b2_rev3_timer.h
Normal file
79
3B2/3b2_rev3_timer.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/* 3b2_rev2_stddev.h: 82C54 Interval Timer.
|
||||||
|
|
||||||
|
Copyright (c) 2021, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _3B2_REV3_TIMER_H_
|
||||||
|
#define _3B2_REV3_TIMER_H_
|
||||||
|
|
||||||
|
#include "3b2_defs.h"
|
||||||
|
|
||||||
|
/* Timer definitions */
|
||||||
|
#define TIMER_STP_US 1
|
||||||
|
#define tmrnum u3
|
||||||
|
#define tmr up7
|
||||||
|
|
||||||
|
#define TIMER_REG_DIVA 0x03
|
||||||
|
#define TIMER_REG_DIVB 0x07
|
||||||
|
#define TIMER_REG_DIVC 0x0b
|
||||||
|
#define TIMER_REG_CTRL 0x0f
|
||||||
|
#define TIMER_CLR_LATCH 0x13
|
||||||
|
|
||||||
|
#define TIMER_MODE(ctr) (((ctr->ctrl) >> 1) & 7)
|
||||||
|
#define TIMER_RW(ctr) (((ctr->ctrl) >> 4) & 3)
|
||||||
|
|
||||||
|
#define CLK_LATCH 0
|
||||||
|
#define CLK_LSB 1
|
||||||
|
#define CLK_MSB 2
|
||||||
|
#define CLK_LMB 3
|
||||||
|
|
||||||
|
struct timer_ctr {
|
||||||
|
uint16 divider;
|
||||||
|
uint16 val;
|
||||||
|
uint8 ctrl_latch;
|
||||||
|
uint16 cnt_latch;
|
||||||
|
uint8 ctrl;
|
||||||
|
t_bool r_lmb;
|
||||||
|
t_bool w_lmb;
|
||||||
|
t_bool enabled;
|
||||||
|
t_bool r_ctrl_latch;
|
||||||
|
t_bool r_cnt_latch;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 82C54 Timer */
|
||||||
|
t_stat timer_reset(DEVICE *dptr);
|
||||||
|
uint32 timer_read(uint32 pa, size_t size);
|
||||||
|
void timer_write(uint32 pa, uint32 val, size_t size);
|
||||||
|
t_stat timer0_svc(UNIT *uptr);
|
||||||
|
t_stat timer1_svc(UNIT *uptr);
|
||||||
|
t_stat timer2_svc(UNIT *uptr);
|
||||||
|
/* void timer_tick(uint8 ctrnum); */
|
||||||
|
void timer_disable(uint8 ctrnum);
|
||||||
|
void timer_enable(uint8 ctrnum);
|
||||||
|
|
||||||
|
#endif /* _3B2_REV3_TIMER_H_ */
|
|
@ -70,7 +70,7 @@ static struct scsi_dev_t ha_tab[] = {
|
||||||
HA_TAPE(ST120)
|
HA_TAPE(ST120)
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SCSI_U_FLAGS (UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_DIS+ \
|
#define SCSI_U_FLAGS (UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ \
|
||||||
UNIT_ROABLE+(SD327_DTYPE << UNIT_V_DTYPE))
|
UNIT_ROABLE+(SD327_DTYPE << UNIT_V_DTYPE))
|
||||||
|
|
||||||
UNIT ha_unit[] = {
|
UNIT ha_unit[] = {
|
||||||
|
@ -335,7 +335,7 @@ t_stat ha_svc(UNIT *uptr)
|
||||||
sim_debug(HA_TRACE, &ha_dev,
|
sim_debug(HA_TRACE, &ha_dev,
|
||||||
"[%08x] [ha_svc] IRQ for board %d (VEC=%d).\n",
|
"[%08x] [ha_svc] IRQ for board %d (VEC=%d).\n",
|
||||||
R[NUM_PC], ha_state.cid, cio[ha_state.cid].ivec);
|
R[NUM_PC], ha_state.cid, cio[ha_state.cid].ivec);
|
||||||
cio[ha_state.cid].intr = TRUE;
|
CIO_SET_INT(ha_state.cid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
|
399
3B2/3b2_stddev.c
399
3B2/3b2_stddev.c
|
@ -1,4 +1,4 @@
|
||||||
/* 3b2_rev2_stddev.h: AT&T 3B2 Rev 2 (Model 400) System Devices Implementation
|
/* 3b2_stddev.c: AT&T 3B2 miscellaneous system board devices.
|
||||||
|
|
||||||
Copyright (c) 2017, Seth J. Morabito
|
Copyright (c) 2017, Seth J. Morabito
|
||||||
|
|
||||||
|
@ -32,21 +32,15 @@
|
||||||
This file contains system-specific registers and devices for the
|
This file contains system-specific registers and devices for the
|
||||||
following 3B2 devices:
|
following 3B2 devices:
|
||||||
|
|
||||||
- timer 8253 interval timer
|
|
||||||
- nvram Non-Volatile RAM
|
- nvram Non-Volatile RAM
|
||||||
- csr Control Status Registers
|
|
||||||
- tod MM58174A Real-Time-Clock
|
- tod MM58174A Real-Time-Clock
|
||||||
|
- flt Fault Register
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "3b2_stddev.h"
|
#include "3b2_stddev.h"
|
||||||
|
|
||||||
#if defined(REV3)
|
|
||||||
#include "3b2_rev3_csr.h"
|
|
||||||
#else
|
|
||||||
#include "3b2_rev2_csr.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "3b2_cpu.h"
|
#include "3b2_cpu.h"
|
||||||
|
#include "3b2_csr.h"
|
||||||
|
|
||||||
DEBTAB sys_deb_tab[] = {
|
DEBTAB sys_deb_tab[] = {
|
||||||
{ "INIT", INIT_MSG, "Init" },
|
{ "INIT", INIT_MSG, "Init" },
|
||||||
|
@ -58,14 +52,9 @@ DEBTAB sys_deb_tab[] = {
|
||||||
{ NULL, 0 }
|
{ NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct timer_ctr TIMERS[3];
|
|
||||||
|
|
||||||
uint32 *NVRAM = NULL;
|
uint32 *NVRAM = NULL;
|
||||||
|
|
||||||
int32 tmxr_poll = 16667;
|
|
||||||
|
|
||||||
/* NVRAM */
|
/* NVRAM */
|
||||||
|
|
||||||
UNIT nvram_unit = {
|
UNIT nvram_unit = {
|
||||||
UDATA(NULL, UNIT_FIX+UNIT_BINK, NVRSIZE)
|
UDATA(NULL, UNIT_FIX+UNIT_BINK, NVRSIZE)
|
||||||
};
|
};
|
||||||
|
@ -239,390 +228,8 @@ void nvram_write(uint32 pa, uint32 val, size_t size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 8253 Timer.
|
|
||||||
*
|
|
||||||
* The 8253 Timer IC has three interval timers, which we treat here as
|
|
||||||
* three units.
|
|
||||||
*
|
|
||||||
* Note that this simulation is very specific to the 3B2, and not
|
|
||||||
* usable as a general purpose 8253 simulator.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The three timers, (A, B, C) run at different
|
|
||||||
* programmatially controlled frequencies, so each must be
|
|
||||||
* handled through a different service routine.
|
|
||||||
*/
|
|
||||||
|
|
||||||
UNIT timer_unit[] = {
|
|
||||||
{ UDATA(&timer0_svc, 0, 0) },
|
|
||||||
{ UDATA(&timer1_svc, UNIT_IDLE, 0) },
|
|
||||||
{ UDATA(&timer2_svc, 0, 0) },
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
UNIT *timer_clk_unit = &timer_unit[1];
|
|
||||||
|
|
||||||
REG timer_reg[] = {
|
|
||||||
{ HRDATAD(DIVA, TIMERS[0].divider, 16, "Divider A") },
|
|
||||||
{ HRDATAD(STA, TIMERS[0].mode, 8, "Mode A") },
|
|
||||||
{ HRDATAD(DIVB, TIMERS[1].divider, 16, "Divider B") },
|
|
||||||
{ HRDATAD(STB, TIMERS[1].mode, 8, "Mode B") },
|
|
||||||
{ HRDATAD(DIVC, TIMERS[2].divider, 16, "Divider C") },
|
|
||||||
{ HRDATAD(STC, TIMERS[2].mode, 8, "Mode C") },
|
|
||||||
{ NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
MTAB timer_mod[] = {
|
|
||||||
{ MTAB_XTD|MTAB_VDV|MTAB_VALR|MTAB_NC, 0, NULL, "SHUTDOWN",
|
|
||||||
&timer_set_shutdown, NULL, NULL, "Soft Power Shutdown" },
|
|
||||||
{ 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
DEVICE timer_dev = {
|
|
||||||
"TIMER", timer_unit, timer_reg, timer_mod,
|
|
||||||
1, 16, 8, 4, 16, 32,
|
|
||||||
NULL, NULL, &timer_reset,
|
|
||||||
NULL, NULL, NULL, NULL,
|
|
||||||
DEV_DEBUG, 0, sys_deb_tab
|
|
||||||
};
|
|
||||||
|
|
||||||
t_stat timer_reset(DEVICE *dptr) {
|
|
||||||
int32 i, t;
|
|
||||||
|
|
||||||
memset(&TIMERS, 0, sizeof(struct timer_ctr) * 3);
|
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
|
||||||
timer_unit[i].tmrnum = i;
|
|
||||||
timer_unit[i].tmr = (void *)&TIMERS[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Timer 1 gate is always active */
|
|
||||||
TIMERS[1].gate = 1;
|
|
||||||
|
|
||||||
if (!sim_is_running) {
|
|
||||||
t = sim_rtcn_init_unit(timer_clk_unit, TPS_CLK, TMR_CLK);
|
|
||||||
sim_activate_after(timer_clk_unit, 1000000 / t);
|
|
||||||
}
|
|
||||||
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void timer_activate(uint8 ctrnum)
|
|
||||||
{
|
|
||||||
struct timer_ctr *ctr;
|
|
||||||
|
|
||||||
ctr = &TIMERS[ctrnum];
|
|
||||||
|
|
||||||
switch (ctrnum) {
|
|
||||||
case TIMER_SANITY:
|
|
||||||
#ifdef REV3
|
|
||||||
if ((csr_data & CSRISTIM) == 0) {
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] SANITY TIMER: Activating after %d steps\n",
|
|
||||||
R[NUM_PC], ctr->val);
|
|
||||||
sim_activate_abs(&timer_unit[ctrnum], ctr->val);
|
|
||||||
ctr->val--;
|
|
||||||
} else {
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] SANITY TIMER: Currently disabled, not starting\n",
|
|
||||||
R[NUM_PC]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case TIMER_INTERVAL:
|
|
||||||
if ((csr_data & CSRITIM) == 0) {
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] INTERVAL TIMER: Activating after %d ms\n",
|
|
||||||
R[NUM_PC], ctr->val);
|
|
||||||
sim_activate_after_abs(&timer_unit[ctrnum], ctr->val);
|
|
||||||
ctr->val--;
|
|
||||||
} else {
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] INTERVAL TIMER: Currently disabled, not starting\n",
|
|
||||||
R[NUM_PC]);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TIMER_BUS:
|
|
||||||
#ifdef REV3
|
|
||||||
if ((csr_data & CSRITIMO) == 0) {
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] BUS TIMER: Activating after %d steps\n",
|
|
||||||
R[NUM_PC], ctr->val);
|
|
||||||
sim_activate_abs(&timer_unit[ctrnum], (ctr->val - 2));
|
|
||||||
ctr->val -= 2;
|
|
||||||
} else {
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] BUS TIMER: Currently disabled, not starting\n",
|
|
||||||
R[NUM_PC]);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t_stat timer_set_shutdown(UNIT *uptr, int32 val, CONST char* cptr, void* desc)
|
|
||||||
{
|
|
||||||
struct timer_ctr *sanity = (struct timer_ctr *)timer_unit[0].tmr;
|
|
||||||
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] Setting sanity timer to 0 for shutdown.\n", R[NUM_PC]);
|
|
||||||
|
|
||||||
sanity->val = 0;
|
|
||||||
csr_data &= ~CSRCLK;
|
|
||||||
csr_data |= CSRTIMO;
|
|
||||||
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void timer_enable(uint8 ctrnum) {
|
|
||||||
timer_activate(ctrnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
void timer_disable(uint8 ctrnum)
|
|
||||||
{
|
|
||||||
sim_debug(EXECUTE_MSG, &timer_dev,
|
|
||||||
"[%08x] Disabling timer %d\n",
|
|
||||||
R[NUM_PC], ctrnum);
|
|
||||||
sim_cancel(&timer_unit[ctrnum]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sanity Timer
|
|
||||||
*/
|
|
||||||
t_stat timer0_svc(UNIT *uptr)
|
|
||||||
{
|
|
||||||
struct timer_ctr *ctr;
|
|
||||||
int32 time;
|
|
||||||
|
|
||||||
ctr = (struct timer_ctr *)uptr->tmr;
|
|
||||||
|
|
||||||
time = ctr->divider * TIMER_STP_US;
|
|
||||||
|
|
||||||
if (time == 0) {
|
|
||||||
time = TIMER_STP_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
sim_activate_after_abs(uptr, time);
|
|
||||||
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Interval Timer
|
|
||||||
*/
|
|
||||||
t_stat timer1_svc(UNIT *uptr)
|
|
||||||
{
|
|
||||||
struct timer_ctr *ctr;
|
|
||||||
int32 t;
|
|
||||||
|
|
||||||
ctr = (struct timer_ctr *)uptr->tmr;
|
|
||||||
|
|
||||||
if (ctr->enabled && !(csr_data & CSRITIM)) {
|
|
||||||
/* Fire the IPL 15 clock interrupt */
|
|
||||||
csr_data |= CSRCLK;
|
|
||||||
}
|
|
||||||
|
|
||||||
t = sim_rtcn_calb(TPS_CLK, TMR_CLK);
|
|
||||||
sim_activate_after_abs(uptr, 1000000/TPS_CLK);
|
|
||||||
tmxr_poll = t;
|
|
||||||
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bus Timeout Timer
|
|
||||||
*/
|
|
||||||
t_stat timer2_svc(UNIT *uptr)
|
|
||||||
{
|
|
||||||
struct timer_ctr *ctr;
|
|
||||||
int32 time;
|
|
||||||
|
|
||||||
ctr = (struct timer_ctr *)uptr->tmr;
|
|
||||||
|
|
||||||
time = ctr->divider * TIMER_STP_US;
|
|
||||||
|
|
||||||
if (time == 0) {
|
|
||||||
time = TIMER_STP_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
sim_activate_after_abs(uptr, time);
|
|
||||||
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 timer_read(uint32 pa, size_t size)
|
|
||||||
{
|
|
||||||
uint32 reg;
|
|
||||||
uint16 ctr_val;
|
|
||||||
uint8 ctrnum;
|
|
||||||
struct timer_ctr *ctr;
|
|
||||||
|
|
||||||
reg = pa - TIMERBASE;
|
|
||||||
ctrnum = (reg >> 2) & 0x3;
|
|
||||||
ctr = &TIMERS[ctrnum];
|
|
||||||
|
|
||||||
switch (reg) {
|
|
||||||
case TIMER_REG_DIVA:
|
|
||||||
case TIMER_REG_DIVB:
|
|
||||||
case TIMER_REG_DIVC:
|
|
||||||
ctr_val = ctr->val;
|
|
||||||
|
|
||||||
if (ctr_val != ctr->divider) {
|
|
||||||
sim_debug(READ_MSG, &timer_dev,
|
|
||||||
"[%08x] >>> ctr_val = %04x, ctr->divider = %04x\n",
|
|
||||||
R[NUM_PC], ctr_val, ctr->divider);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ctr->mode & CLK_RW) {
|
|
||||||
case CLK_LSB:
|
|
||||||
return ctr_val & 0xff;
|
|
||||||
case CLK_MSB:
|
|
||||||
return (ctr_val & 0xff00) >> 8;
|
|
||||||
case CLK_LMB:
|
|
||||||
if (ctr->lmb) {
|
|
||||||
ctr->lmb = FALSE;
|
|
||||||
return (ctr_val & 0xff00) >> 8;
|
|
||||||
} else {
|
|
||||||
ctr->lmb = TRUE;
|
|
||||||
return ctr_val & 0xff;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TIMER_REG_CTRL:
|
|
||||||
return ctr->mode;
|
|
||||||
case TIMER_CLR_LATCH:
|
|
||||||
/* Clearing the timer latch has a side-effect
|
|
||||||
of also clearing pending interrupts */
|
|
||||||
csr_data &= ~CSRCLK;
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
/* Unhandled */
|
|
||||||
sim_debug(READ_MSG, &timer_dev,
|
|
||||||
"[%08x] UNHANDLED TIMER READ. ADDR=%08x\n",
|
|
||||||
R[NUM_PC], pa);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_timer_write(uint8 ctrnum, uint32 val)
|
|
||||||
{
|
|
||||||
struct timer_ctr *ctr;
|
|
||||||
|
|
||||||
ctr = &TIMERS[ctrnum];
|
|
||||||
switch(ctr->mode & 0x30) {
|
|
||||||
case 0x10:
|
|
||||||
ctr->divider &= 0xff00;
|
|
||||||
ctr->divider |= val & 0xff;
|
|
||||||
ctr->val = ctr->divider;
|
|
||||||
ctr->enabled = TRUE;
|
|
||||||
ctr->stime = sim_gtime();
|
|
||||||
sim_cancel(timer_clk_unit);
|
|
||||||
sim_activate_after_abs(timer_clk_unit, ctr->divider * TIMER_STP_US);
|
|
||||||
break;
|
|
||||||
case 0x20:
|
|
||||||
ctr->divider &= 0x00ff;
|
|
||||||
ctr->divider |= (val & 0xff) << 8;
|
|
||||||
ctr->val = ctr->divider;
|
|
||||||
ctr->enabled = TRUE;
|
|
||||||
ctr->stime = sim_gtime();
|
|
||||||
/* Kick the timer to get the new divider value */
|
|
||||||
sim_cancel(timer_clk_unit);
|
|
||||||
sim_activate_after_abs(timer_clk_unit, ctr->divider * TIMER_STP_US);
|
|
||||||
break;
|
|
||||||
case 0x30:
|
|
||||||
if (ctr->lmb) {
|
|
||||||
ctr->lmb = FALSE;
|
|
||||||
ctr->divider = (uint16) ((ctr->divider & 0x00ff) | ((val & 0xff) << 8));
|
|
||||||
ctr->val = ctr->divider;
|
|
||||||
ctr->enabled = TRUE;
|
|
||||||
ctr->stime = sim_gtime();
|
|
||||||
sim_debug(READ_MSG, &timer_dev,
|
|
||||||
"[%08x] Write timer %d val LMB (MSB): %02x\n",
|
|
||||||
R[NUM_PC], ctrnum, val & 0xff);
|
|
||||||
/* Kick the timer to get the new divider value */
|
|
||||||
sim_cancel(timer_clk_unit);
|
|
||||||
sim_activate_after_abs(timer_clk_unit, ctr->divider * TIMER_STP_US);
|
|
||||||
} else {
|
|
||||||
ctr->lmb = TRUE;
|
|
||||||
ctr->divider = (ctr->divider & 0xff00) | (val & 0xff);
|
|
||||||
ctr->val = ctr->divider;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void timer_write(uint32 pa, uint32 val, size_t size)
|
|
||||||
{
|
|
||||||
uint8 reg, ctrnum;
|
|
||||||
struct timer_ctr *ctr;
|
|
||||||
|
|
||||||
reg = (uint8) (pa - TIMERBASE);
|
|
||||||
|
|
||||||
switch(reg) {
|
|
||||||
case TIMER_REG_DIVA:
|
|
||||||
handle_timer_write(0, val);
|
|
||||||
break;
|
|
||||||
case TIMER_REG_DIVB:
|
|
||||||
handle_timer_write(1, val);
|
|
||||||
break;
|
|
||||||
case TIMER_REG_DIVC:
|
|
||||||
handle_timer_write(2, val);
|
|
||||||
break;
|
|
||||||
case TIMER_REG_CTRL:
|
|
||||||
/* The counter number is in bits 6 and 7 */
|
|
||||||
ctrnum = (val >> 6) & 3;
|
|
||||||
if (ctrnum > 2) {
|
|
||||||
sim_debug(WRITE_MSG, &timer_dev,
|
|
||||||
"[%08x] WARNING: Write to invalid counter: %d\n",
|
|
||||||
R[NUM_PC], ctrnum);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctr = &TIMERS[ctrnum];
|
|
||||||
ctr->mode = (uint8) val;
|
|
||||||
ctr->enabled = FALSE;
|
|
||||||
ctr->lmb = FALSE;
|
|
||||||
break;
|
|
||||||
case TIMER_CLR_LATCH:
|
|
||||||
sim_debug(WRITE_MSG, &timer_dev,
|
|
||||||
"[%08x] unexpected write to clear timer latch\n",
|
|
||||||
R[NUM_PC]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void timer_tick()
|
|
||||||
{
|
|
||||||
if (TIMERS[0].gate && TIMERS[0].enabled) {
|
|
||||||
TIMERS[0].val = TIMERS[0].divider - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TIMERS[1].gate && TIMERS[1].enabled) {
|
|
||||||
TIMERS[1].val = TIMERS[1].divider - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TIMERS[2].gate && TIMERS[2].enabled) {
|
|
||||||
TIMERS[2].val = TIMERS[2].divider - 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MM58174A Time Of Day Clock
|
* MM58174A Time Of Day Clock
|
||||||
*
|
|
||||||
* Despite its name, this device is not used by the 3B2 as a clock. It
|
|
||||||
* is only used to store the current date and time between boots. It
|
|
||||||
* is set when an operator changes the date and time. Is is read at
|
|
||||||
* boot time. Therefore, we do not need to treat it as a clock or
|
|
||||||
* timer device here.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
UNIT tod_unit = {
|
UNIT tod_unit = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* 3b2_rev2_stddev.h: AT&T 3B2 Rev 2 (Model 400) System Devices Header
|
/* 3b2_stddev.h: AT&T 3B2 miscellaneous system board devices.
|
||||||
|
|
||||||
Copyright (c) 2017, Seth J. Morabito
|
Copyright (c) 2017, Seth J. Morabito
|
||||||
|
|
||||||
|
@ -28,40 +28,11 @@
|
||||||
from the author.
|
from the author.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _3B2_REV2_SYSDEV_H_
|
#ifndef _3B2_STDDEV_H_
|
||||||
#define _3B2_REV2_SYSDEV_H_
|
#define _3B2_STDDEV_H_
|
||||||
|
|
||||||
#include "3b2_defs.h"
|
#include "3b2_defs.h"
|
||||||
|
|
||||||
/* Timer definitions */
|
|
||||||
#define TMR_CLK 0 /* The clock responsible for IPL 15 interrupts */
|
|
||||||
#define TPS_CLK 100 /* 100 ticks per second */
|
|
||||||
|
|
||||||
#define TIMER_STP_US 1
|
|
||||||
#define tmrnum u3
|
|
||||||
#define tmr up7
|
|
||||||
|
|
||||||
#define TIMER_REG_DIVA 0x03
|
|
||||||
#define TIMER_REG_DIVB 0x07
|
|
||||||
#define TIMER_REG_DIVC 0x0b
|
|
||||||
#define TIMER_REG_CTRL 0x0f
|
|
||||||
#define TIMER_CLR_LATCH 0x13
|
|
||||||
|
|
||||||
#define CLK_RW 0x30
|
|
||||||
#define CLK_LSB 0x10
|
|
||||||
#define CLK_MSB 0x20
|
|
||||||
#define CLK_LMB 0x30
|
|
||||||
|
|
||||||
struct timer_ctr {
|
|
||||||
uint16 divider;
|
|
||||||
uint16 val;
|
|
||||||
uint8 mode;
|
|
||||||
t_bool lmb;
|
|
||||||
t_bool enabled;
|
|
||||||
t_bool gate;
|
|
||||||
double stime; /* Most recent start time of counter */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* NVRAM */
|
/* NVRAM */
|
||||||
t_stat nvram_ex(t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
|
t_stat nvram_ex(t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
|
||||||
t_stat nvram_dep(t_value val, t_addr exta, UNIT *uptr, int32 sw);
|
t_stat nvram_dep(t_value val, t_addr exta, UNIT *uptr, int32 sw);
|
||||||
|
@ -73,28 +44,7 @@ const char *nvram_description(DEVICE *dptr);
|
||||||
t_stat nvram_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
t_stat nvram_help(FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr);
|
||||||
void nvram_write(uint32 pa, uint32 val, size_t size);
|
void nvram_write(uint32 pa, uint32 val, size_t size);
|
||||||
|
|
||||||
/* 8253 Timer */
|
|
||||||
t_stat timer_reset(DEVICE *dptr);
|
|
||||||
uint32 timer_read(uint32 pa, size_t size);
|
|
||||||
void timer_write(uint32 pa, uint32 val, size_t size);
|
|
||||||
void timer_tick();
|
|
||||||
t_stat timer0_svc(UNIT *uptr);
|
|
||||||
t_stat timer1_svc(UNIT *uptr);
|
|
||||||
t_stat timer2_svc(UNIT *uptr);
|
|
||||||
t_stat timer_set_shutdown(UNIT *uptr, int32 val, CONST char *cptr, void *desc);
|
|
||||||
void timer_disable(uint8 ctrnum);
|
|
||||||
void timer_enable(uint8 ctrnum);
|
|
||||||
|
|
||||||
/* CSR */
|
|
||||||
t_stat csr_svc(UNIT *uptr);
|
|
||||||
t_stat csr_ex(t_value *vptr, t_addr exta, UNIT *uptr, int32 sw);
|
|
||||||
t_stat csr_dep(t_value val, t_addr exta, UNIT *uptr, int32 sw);
|
|
||||||
t_stat csr_reset(DEVICE *dptr);
|
|
||||||
uint32 csr_read(uint32 pa, size_t size);
|
|
||||||
void csr_write(uint32 pa, uint32 val, size_t size);
|
|
||||||
|
|
||||||
/* TOD */
|
/* TOD */
|
||||||
|
|
||||||
typedef struct tod_data {
|
typedef struct tod_data {
|
||||||
int32 delta; /* Delta between simulated time and real time (sec.) */
|
int32 delta; /* Delta between simulated time and real time (sec.) */
|
||||||
uint8 tsec; /* 1/10 seconds */
|
uint8 tsec; /* 1/10 seconds */
|
||||||
|
@ -125,11 +75,8 @@ void tod_write(uint32, uint32 val, size_t size);
|
||||||
|
|
||||||
#if defined(REV3)
|
#if defined(REV3)
|
||||||
/* Fault Register */
|
/* Fault Register */
|
||||||
|
|
||||||
uint32 flt_read(uint32 pa, size_t size);
|
uint32 flt_read(uint32 pa, size_t size);
|
||||||
void flt_write(uint32 pa, uint32 val, size_t size);
|
void flt_write(uint32 pa, uint32 val, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int32 tmxr_poll;
|
#endif /* _3B2_STDDEV_H_ */
|
||||||
|
|
||||||
#endif /* _3B2_REV2_SYSDEV_H_ */
|
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
from the author.
|
from the author.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _3B2_REV2_SYS_H_
|
#ifndef _3B2_SYS_H_
|
||||||
#define _3B2_REV2_SYS_H_
|
#define _3B2_SYS_H_
|
||||||
|
|
||||||
#include "3b2_defs.h"
|
#include "3b2_defs.h"
|
||||||
|
|
||||||
|
@ -43,4 +43,4 @@ extern char sim_name[];
|
||||||
extern REG *sim_PC;
|
extern REG *sim_PC;
|
||||||
extern int32 sim_emax;
|
extern int32 sim_emax;
|
||||||
|
|
||||||
#endif /* _3B2_REV2_SYS_H_ */
|
#endif /* _3B2_SYS_H_ */
|
||||||
|
|
42
3B2/3b2_timer.h
Normal file
42
3B2/3b2_timer.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/* 3b2_timer.h: Common TIMER header
|
||||||
|
|
||||||
|
Copyright (c) 2021, Seth J. Morabito
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person
|
||||||
|
obtaining a copy of this software and associated documentation
|
||||||
|
files (the "Software"), to deal in the Software without
|
||||||
|
restriction, including without limitation the rights to use, copy,
|
||||||
|
modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||||
|
of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
||||||
|
Except as contained in this notice, the name of the author shall
|
||||||
|
not be used in advertising or otherwise to promote the sale, use or
|
||||||
|
other dealings in this Software without prior written authorization
|
||||||
|
from the author.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _3B2_TIMER_H_
|
||||||
|
#define _3B2_TIMER_H_
|
||||||
|
|
||||||
|
#if defined(REV3)
|
||||||
|
#include "3b2_rev3_timer.h"
|
||||||
|
#else
|
||||||
|
#include "3b2_rev2_timer.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int32 tmxr_poll;
|
||||||
|
|
||||||
|
#endif /* _3B2_TIMER_H_ */
|
|
@ -1,7 +1,13 @@
|
||||||
AT&T 3B2 Simulator
|
AT&T 3B2 Simulator
|
||||||
==================
|
==================
|
||||||
|
|
||||||
This module contains a simulator for the AT&T 3B2 Model 400 microcomputer.
|
This module contains the source for two simulators:
|
||||||
|
|
||||||
|
1. A simulator for the AT&T 3B2 Model 400 computer (Rev. 2)
|
||||||
|
2. A simulator for the AT&T 3B2 Model 600 computer (Rev. 3)
|
||||||
|
|
||||||
|
The 3B2/400 simulator is complete, usable, and robust. The 3B2/600 simulator
|
||||||
|
is not yet usable, however. It is under active development.
|
||||||
|
|
||||||
Full documentation for the 3B2 simulator is available here:
|
Full documentation for the 3B2 simulator is available here:
|
||||||
|
|
||||||
|
@ -23,6 +29,7 @@ devices are given in parentheses:
|
||||||
- uPD7261A Integrated MFM Fixed Disk Controller (IDISK)
|
- uPD7261A Integrated MFM Fixed Disk Controller (IDISK)
|
||||||
- Non-Volatile Memory (NVRAM)
|
- Non-Volatile Memory (NVRAM)
|
||||||
- MM58174A Time Of Day Clock (TOD)
|
- MM58174A Time Of Day Clock (TOD)
|
||||||
|
- CM195A Ethernet Network Interface (NI)
|
||||||
- CM195B 4-port Serial MUX (PORTS)
|
- CM195B 4-port Serial MUX (PORTS)
|
||||||
- CM195H Cartridge Tape Controller (CTC)
|
- CM195H Cartridge Tape Controller (CTC)
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,10 @@
|
||||||
RelativePath="..\3B2\3b2_rev3_sys.c"
|
RelativePath="..\3B2\3b2_rev3_sys.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\3B2\3b2_rev3_timer.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\3B2\3b2_scsi.c"
|
RelativePath="..\3B2\3b2_scsi.c"
|
||||||
>
|
>
|
||||||
|
@ -536,11 +540,11 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\3B2\3b2_rev2_csr.h"
|
RelativePath="..\3B2\3b2_rev3_csr.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\3B2\3b2_rev2_defs.h"
|
RelativePath="..\3B2\3b2_rev3_defs.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
@ -548,11 +552,15 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\3B2\3b2_rev2_mmu.h"
|
RelativePath="..\3B2\3b2_rev3_mmu.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\3B2\3b2_rev2_sys.h"
|
RelativePath="..\3B2\3b2_rev3_sys.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\3B2\3b2_rev3_timer.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
|
|
@ -251,6 +251,10 @@
|
||||||
RelativePath="..\3B2\3b2_rev2_csr.c"
|
RelativePath="..\3B2\3b2_rev2_csr.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\3B2\3b2_rev2_timer.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\3B2\3b2_stddev.c"
|
RelativePath="..\3B2\3b2_stddev.c"
|
||||||
>
|
>
|
||||||
|
@ -559,6 +563,10 @@
|
||||||
RelativePath="..\3B2\3b2_rev2_csr.h"
|
RelativePath="..\3B2\3b2_rev2_csr.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\3B2\3b2_rev2_timer.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\3B2\3b2_stddev.h"
|
RelativePath="..\3B2\3b2_stddev.h"
|
||||||
>
|
>
|
||||||
|
|
21
makefile
21
makefile
|
@ -2035,21 +2035,22 @@ ATT3B2D = ${SIMHD}/3B2
|
||||||
ATT3B2M400 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \
|
ATT3B2M400 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \
|
||||||
${ATT3B2D}/3b2_rev2_sys.c ${ATT3B2D}/3b2_rev2_mmu.c \
|
${ATT3B2D}/3b2_rev2_sys.c ${ATT3B2D}/3b2_rev2_mmu.c \
|
||||||
${ATT3B2D}/3b2_rev2_mau.c ${ATT3B2D}/3b2_rev2_csr.c \
|
${ATT3B2D}/3b2_rev2_mau.c ${ATT3B2D}/3b2_rev2_csr.c \
|
||||||
${ATT3B2D}/3b2_stddev.c ${ATT3B2D}/3b2_mem.c \
|
${ATT3B2D}/3b2_rev2_timer.c ${ATT3B2D}/3b2_stddev.c \
|
||||||
${ATT3B2D}/3b2_iu.c ${ATT3B2D}/3b2_if.c \
|
${ATT3B2D}/3b2_mem.c ${ATT3B2D}/3b2_iu.c \
|
||||||
${ATT3B2D}/3b2_id.c ${ATT3B2D}/3b2_dmac.c \
|
${ATT3B2D}/3b2_if.c ${ATT3B2D}/3b2_id.c \
|
||||||
${ATT3B2D}/3b2_io.c ${ATT3B2D}/3b2_ports.c \
|
${ATT3B2D}/3b2_dmac.c ${ATT3B2D}/3b2_io.c \
|
||||||
${ATT3B2D}/3b2_ctc.c ${ATT3B2D}/3b2_ni.c
|
${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_ctc.c \
|
||||||
|
${ATT3B2D}/3b2_ni.c
|
||||||
ATT3B2M400_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV2 -I ${ATT3B2D} ${NETWORK_OPT}
|
ATT3B2M400_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV2 -I ${ATT3B2D} ${NETWORK_OPT}
|
||||||
|
|
||||||
ATT3B2M600 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \
|
ATT3B2M600 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \
|
||||||
${ATT3B2D}/3b2_rev3_sys.c ${ATT3B2D}/3b2_rev3_mmu.c \
|
${ATT3B2D}/3b2_rev3_sys.c ${ATT3B2D}/3b2_rev3_mmu.c \
|
||||||
${ATT3B2D}/3b2_rev2_mau.c ${ATT3B2D}/3b2_rev3_csr.c \
|
${ATT3B2D}/3b2_rev2_mau.c ${ATT3B2D}/3b2_rev3_csr.c \
|
||||||
${ATT3B2D}/3b2_stddev.c ${ATT3B2D}/3b2_mem.c \
|
${ATT3B2D}/3b2_rev3_timer.c ${ATT3B2D}/3b2_stddev.c \
|
||||||
${ATT3B2D}/3b2_iu.c ${ATT3B2D}/3b2_if.c \
|
${ATT3B2D}/3b2_mem.c ${ATT3B2D}/3b2_iu.c \
|
||||||
${ATT3B2D}/3b2_dmac.c ${ATT3B2D}/3b2_io.c \
|
${ATT3B2D}/3b2_if.c ${ATT3B2D}/3b2_dmac.c \
|
||||||
${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_scsi.c \
|
${ATT3B2D}/3b2_io.c ${ATT3B2D}/3b2_ports.c \
|
||||||
${ATT3B2D}/3b2_ni.c
|
${ATT3B2D}/3b2_scsi.c ${ATT3B2D}/3b2_ni.c
|
||||||
ATT3B2M600_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV3 -I ${ATT3B2D} ${NETWORK_OPT}
|
ATT3B2M600_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV3 -I ${ATT3B2D} ${NETWORK_OPT}
|
||||||
|
|
||||||
SIGMAD = ${SIMHD}/sigma
|
SIGMAD = ${SIMHD}/sigma
|
||||||
|
|
Loading…
Add table
Reference in a new issue