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"
|
||||
|
||||
#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 "3b2_if.h"
|
||||
#define ROM_ARRAY BOOT_CODE_ARRAY
|
||||
#define ROM_SIZE BOOT_CODE_SIZE
|
||||
#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"
|
||||
#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_io.h"
|
||||
#include "3b2_iu.h"
|
||||
#include "3b2_mau.h"
|
||||
#include "3b2_mem.h"
|
||||
#include "3b2_mmu.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
#define MAX_SUB_RETURN_SKIP 9
|
||||
|
||||
uint32 rom_size = BOOT_CODE_SIZE;
|
||||
uint32 rom_size = 0;
|
||||
|
||||
/* Static function declarations */
|
||||
static uint32 cpu_effective_address(operand * op);
|
||||
static uint32 cpu_read_op(operand * op);
|
||||
static void cpu_write_op(operand * op, t_uint64 val);
|
||||
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_stack_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];
|
||||
|
||||
/* 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
|
||||
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 */
|
||||
/* Interrupt request bitfield */
|
||||
/* Note: Only the lowest 8 bits are used by Rev 2, and only the lowest
|
||||
12 bits are used by Rev 3 */
|
||||
uint16 sbd_int_req = 0; /* Currently set interrupt sources */
|
||||
uint8 int_map[INT_MAP_LEN]; /* Map of interrupt sources to highest
|
||||
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[] = {
|
||||
{ "BOOT", &sys_boot, RU_BOOT,
|
||||
"bo{ot} boot simulator\n", NULL, &run_cmd_message },
|
||||
|
@ -182,6 +190,37 @@ BITFIELD psw_bits[] = {
|
|||
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. */
|
||||
REG cpu_reg[] = {
|
||||
{ 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 (R31, R[31], 32, "Privileged register 31")},
|
||||
#endif
|
||||
{ HRDATAD (IPL, cpu_int_ipl, 8, "Current CPU IPL bits")},
|
||||
{ HRDATAD (VEC, cpu_int_vec, 8, "Current CPU interrupt vector")},
|
||||
{ HRDATADF (SBD_INT, sbd_int_req, 16, "Interrupt Requests", sbd_int_req_bits) },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -317,9 +355,9 @@ MTAB cpu_mod[] = {
|
|||
&cpu_set_size, NULL, NULL, "Set Memory to 1M bytes" },
|
||||
{ UNIT_MSIZE, (1u << 21), NULL, "2M",
|
||||
&cpu_set_size, NULL, NULL, "Set Memory to 2M bytes" },
|
||||
#endif
|
||||
{ UNIT_MSIZE, (1u << 22), NULL, "4M",
|
||||
&cpu_set_size, NULL, NULL, "Set Memory to 4M bytes" },
|
||||
#endif
|
||||
#if defined(REV3)
|
||||
{ UNIT_MSIZE, (1u << 23), NULL, "8M",
|
||||
&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;
|
||||
}
|
||||
|
||||
void cpu_load_rom()
|
||||
t_stat cpu_load_rom(uint8 *arrayp, uint32 len)
|
||||
{
|
||||
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) {
|
||||
return;
|
||||
return SCPE_MEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < rom_size; i++) {
|
||||
val = BOOT_CODE_ARRAY[i];
|
||||
for (i = 0; i < len; i++) {
|
||||
val = arrayp[i];
|
||||
sc = (~(i & 3) << 3) & 0x1f;
|
||||
mask = 0xffu << sc;
|
||||
index = i >> 2;
|
||||
|
||||
ROM[index] = (ROM[index] & ~mask) | (val << sc);
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
#if defined(REV3)
|
||||
t_stat sys_boot(int32 flag, CONST char *ptr)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
|
@ -789,6 +837,39 @@ t_stat sys_boot(int32 flag, CONST char *ptr)
|
|||
|
||||
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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
int i;
|
||||
t_stat r;
|
||||
|
||||
/* Link in our special "boot" command so we can boot with both
|
||||
* "BO{OT}" and "BO{OT} CPU" */
|
||||
|
@ -883,24 +1013,23 @@ t_stat cpu_reset(DEVICE *dptr)
|
|||
/* Set up the pre-calibration routine */
|
||||
sim_clock_precalibrate_commands = att3b2_clock_precalibrate_commands;
|
||||
|
||||
/* Populate the interrupt->IPL map */
|
||||
build_int_map();
|
||||
|
||||
if (!sim_is_running) {
|
||||
/* Clear registers */
|
||||
for (i = 0; i < NUM_REGISTERS; i++) {
|
||||
R[i] = 0;
|
||||
}
|
||||
|
||||
/* Allocate ROM */
|
||||
if (ROM != NULL) {
|
||||
free(ROM);
|
||||
}
|
||||
ROM = (uint32 *) calloc((size_t)(rom_size >> 2), sizeof(uint32));
|
||||
/* Allocate ROM if needed */
|
||||
if (ROM == NULL) {
|
||||
return SCPE_MEM;
|
||||
if ((r = cpu_load_rom(ROM_ARRAY, ROM_SIZE)) != SCPE_OK) {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
cpu_load_rom();
|
||||
|
||||
/* Allocate RAM */
|
||||
/* Always re-allocate RAM */
|
||||
if (RAM != NULL) {
|
||||
free(RAM);
|
||||
}
|
||||
|
@ -1822,8 +1951,8 @@ void cpu_on_interrupt(uint16 vec)
|
|||
uint32 new_pcbp, new_pcbp_ptr;
|
||||
|
||||
sim_debug(IRQ_MSG, &cpu_dev,
|
||||
"[%08x] [cpu_on_interrupt] vec=%02x (%d) csr_data = %x\n",
|
||||
R[NUM_PC], vec, vec, csr_data);
|
||||
"[%08x] [cpu_on_interrupt] vec=%02x (%d) sbd_int_req = %x, csr_data = %x\n",
|
||||
R[NUM_PC], vec, vec, sbd_int_req, csr_data);
|
||||
|
||||
/*
|
||||
* "If a nonmaskable interrupt request is received, an auto-vector
|
||||
|
@ -1886,6 +2015,9 @@ t_stat sim_instr(void)
|
|||
/* Generic index */
|
||||
uint32 i;
|
||||
|
||||
/* Interrupt request IPL */
|
||||
uint8 ipl;
|
||||
|
||||
/* Used by oprocessor instructions */
|
||||
uint32 coprocessor_word;
|
||||
|
||||
|
@ -1999,26 +2131,33 @@ t_stat sim_instr(void)
|
|||
increment_modep_b();
|
||||
}
|
||||
|
||||
/* Set the correct IRQ state */
|
||||
cpu_calc_ints();
|
||||
|
||||
if (cpu_nmi || (PSW_CUR_IPL < cpu_int_ipl)) {
|
||||
cpu_on_interrupt(cpu_int_vec);
|
||||
for (i = 0; i < CIO_SLOTS; i++) {
|
||||
if (cio[i].intr &&
|
||||
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;
|
||||
/* Interrupt Handling
|
||||
*
|
||||
* - NMI is always serviced first.
|
||||
* - SBD interrupts are handled next in priority.
|
||||
* - IO Bus boards are handled last.
|
||||
*/
|
||||
if (cpu_nmi) {
|
||||
cpu_nmi = 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) {
|
||||
|
@ -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
|
||||
* or default type.
|
||||
|
|
|
@ -604,8 +604,6 @@ instr *cpu_next_instruction(void);
|
|||
uint8 decode_instruction(instr *instr);
|
||||
void cpu_on_interrupt(uint16 vec);
|
||||
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 */
|
||||
|
||||
|
@ -649,7 +647,11 @@ void cpu_clear_irq(uint8 ipl, uint16 csr_flags);
|
|||
(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 uint16 sbd_int_req;
|
||||
extern uint32 rom_size;
|
||||
extern instr *cpu_instr;
|
||||
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 "3b2_mem.h"
|
||||
#include "3b2_io.h"
|
||||
#include "3b2_mem.h"
|
||||
|
||||
#define CTQRESIZE 20
|
||||
#define CTQCESIZE 16
|
||||
|
@ -761,7 +761,7 @@ t_stat ctc_svc(UNIT *uptr)
|
|||
sim_debug(TRACE_DBG, &ctc_dev,
|
||||
"[cio_svc] IRQ for board %d (VEC=%d)\n",
|
||||
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
|
||||
|
|
|
@ -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_OPBRK (UNIT_V_UF + 1)
|
||||
#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_BUS 2
|
||||
|
||||
/* Timer */
|
||||
#define TMR_CLK 0 /* The clock responsible for IPL 15 interrupts */
|
||||
#define TPS_CLK 100 /* 100 ticks per second */
|
||||
|
||||
|
||||
/* Global symbols */
|
||||
|
||||
extern DEBTAB sys_deb_tab[];
|
||||
|
|
61
3B2/3b2_id.c
61
3B2/3b2_id.c
|
@ -186,11 +186,31 @@ DEVICE id_dev = {
|
|||
|
||||
/* 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 & ID_STAT_CEH) ||
|
||||
((id_status & ID_STAT_SRQ) && !id_srqm)));
|
||||
id_status |= flags;
|
||||
UPDATE_INT;
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -217,9 +237,9 @@ t_stat id_ctlr_svc(UNIT *uptr)
|
|||
|
||||
cmd = uptr->u4; /* The command that caused the activity */
|
||||
|
||||
id_srqm = FALSE;
|
||||
id_status &= ~(ID_STAT_CB);
|
||||
id_status |= ID_STAT_CEH;
|
||||
id_set_srqm(FALSE);
|
||||
id_clr_status(ID_STAT_CB);
|
||||
id_set_status(ID_STAT_CEH);
|
||||
uptr->u4 = 0;
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -259,8 +279,8 @@ t_stat id_unit_svc(UNIT *uptr)
|
|||
return SCPE_OK;
|
||||
}
|
||||
|
||||
id_srqm = FALSE;
|
||||
id_status &= ~(ID_STAT_CB);
|
||||
id_set_srqm(FALSE);
|
||||
id_clr_status(ID_STAT_CB);
|
||||
/* Note that we don't set CEH, in case this is a SEEK/RECAL ID_SEEK_1 */
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -277,7 +297,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
|||
if (id_polling) {
|
||||
switch (id_seek_state[unit]) {
|
||||
case ID_SEEK_0:
|
||||
id_status |= ID_STAT_CEH;
|
||||
id_set_status(ID_STAT_CEH);
|
||||
sim_debug(EXECUTE_MSG, &id_dev,
|
||||
"[%08x]\tINTR\t\tCOMPLETING Recal/Seek SEEK_0 UNIT %d\n",
|
||||
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",
|
||||
R[NUM_PC], unit);
|
||||
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 */
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
id_int_status |= (ID_IST_SEN|unit);
|
||||
|
@ -307,7 +327,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
|||
sim_debug(EXECUTE_MSG, &id_dev,
|
||||
"[%08x]\tINTR\t\tCOMPLETING NON-POLLING Recal/Seek UNIT %d\n",
|
||||
R[NUM_PC], unit);
|
||||
id_status |= ID_STAT_CEH;
|
||||
id_set_status(ID_STAT_CEH);
|
||||
uptr->u4 = 0;
|
||||
if (uptr->flags & UNIT_ATT) {
|
||||
id_int_status |= (ID_IST_SEN|unit);
|
||||
|
@ -321,7 +341,7 @@ t_stat id_unit_svc(UNIT *uptr)
|
|||
sim_debug(EXECUTE_MSG, &id_dev,
|
||||
"[%08x]\tINTR\t\tCOMPLETING Sense Unit Status UNIT %d\n",
|
||||
R[NUM_PC], unit);
|
||||
id_status |= ID_STAT_CEH;
|
||||
id_set_status(ID_STAT_CEH);
|
||||
uptr->u4 = 0;
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
/* 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,
|
||||
"[%08x]\tINTR\t\tCOMPLETING OTHER COMMAND 0x%x UNIT %d\n",
|
||||
R[NUM_PC], cmd, unit);
|
||||
id_status |= ID_STAT_CEH;
|
||||
id_set_status(ID_STAT_CEH);
|
||||
uptr->u4 = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -673,14 +693,14 @@ void id_handle_command(uint8 val)
|
|||
sim_debug(WRITE_MSG, &id_dev,
|
||||
"[%08x] \tCOMMAND\t%02x\tAUX:CLCE\n",
|
||||
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) {
|
||||
sim_debug(WRITE_MSG, &id_dev,
|
||||
"[%08x] \tCOMMAND\t%02x\tAUX:HSRQ\n",
|
||||
R[NUM_PC], val);
|
||||
id_srqm = TRUE;
|
||||
id_set_srqm(TRUE);
|
||||
}
|
||||
|
||||
if (aux_cmd & ID_AUX_CLB) {
|
||||
|
@ -699,6 +719,7 @@ void id_handle_command(uint8 val)
|
|||
sim_cancel(id_ctlr_unit);
|
||||
id_status = 0;
|
||||
id_srqm = FALSE;
|
||||
UPDATE_INT;
|
||||
}
|
||||
|
||||
/* Just return early */
|
||||
|
@ -715,7 +736,7 @@ void id_handle_command(uint8 val)
|
|||
}
|
||||
|
||||
/* 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 */
|
||||
id_cmd = val;
|
||||
|
@ -739,14 +760,14 @@ void id_handle_command(uint8 val)
|
|||
id_sel_unit->u4 = cmd;
|
||||
}
|
||||
|
||||
id_status |= ID_STAT_CB;
|
||||
id_set_status(ID_STAT_CB);
|
||||
|
||||
switch(cmd) {
|
||||
case ID_CMD_SIS:
|
||||
sim_debug(WRITE_MSG, &id_dev,
|
||||
"[%08x]\tCOMMAND\t%02x\tSense Int. Status\n",
|
||||
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);
|
||||
break;
|
||||
case ID_CMD_SPEC:
|
||||
|
@ -951,7 +972,7 @@ void id_handle_command(uint8 val)
|
|||
|
||||
void id_after_dma()
|
||||
{
|
||||
id_status &= ~ID_STAT_DRQ;
|
||||
id_clr_status(ID_STAT_DRQ);
|
||||
id_drq = FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -158,7 +158,6 @@
|
|||
|
||||
/* Function prototypes */
|
||||
|
||||
t_bool id_int();
|
||||
t_stat id_ctlr_svc(UNIT *uptr);
|
||||
t_stat id_unit_svc(UNIT *uptr);
|
||||
t_stat id_reset(DEVICE *dptr);
|
||||
|
|
60
3B2/3b2_if.c
60
3B2/3b2_if.c
|
@ -32,19 +32,10 @@
|
|||
|
||||
#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_csr.h"
|
||||
|
||||
/* 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();
|
||||
|
||||
/*
|
||||
|
@ -67,13 +58,26 @@ static SIM_INLINE uint32 if_lba();
|
|||
#define IF_HLD_DELAY 60000 /* 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 = {
|
||||
UDATA (&if_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BINK+UNIT_ROABLE,
|
||||
IF_DSK_SIZE_SECS)
|
||||
};
|
||||
|
||||
REG if_reg[] = {
|
||||
{ HRDATAD (IRQ, if_irq, 1, "IRQ Set") },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
@ -90,36 +94,14 @@ DEVICE if_dev = {
|
|||
IF_STATE if_state;
|
||||
uint8 if_buf[IF_SEC_SIZE];
|
||||
uint32 if_sec_ptr = 0;
|
||||
t_bool if_irq = FALSE;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
sim_activate_abs(&if_unit, delay);
|
||||
}
|
||||
|
||||
static SIM_INLINE void if_cancel_pending_irq()
|
||||
{
|
||||
sim_cancel(&if_unit);
|
||||
}
|
||||
|
||||
t_stat if_svc(UNIT *uptr)
|
||||
{
|
||||
uint32 lba; /* Logical block address for write */
|
||||
|
@ -160,7 +142,7 @@ t_stat if_svc(UNIT *uptr)
|
|||
|
||||
/* Request an interrupt */
|
||||
sim_debug(IRQ_MSG, &if_dev, "\tINTR\n");
|
||||
if_set_irq();
|
||||
SET_INT;
|
||||
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
@ -200,7 +182,7 @@ uint32 if_read(uint32 pa, size_t size) {
|
|||
data |= IF_NRDY;
|
||||
}
|
||||
/* 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);
|
||||
break;
|
||||
case IF_TRACK_REG:
|
||||
|
@ -535,13 +517,13 @@ void if_handle_command()
|
|||
}
|
||||
|
||||
if ((if_state.cmd & 0xf) == 0) {
|
||||
if_cancel_pending_irq();
|
||||
sim_cancel(&if_unit);
|
||||
#if defined(REV2)
|
||||
if_clear_irq(); /* TODO: Confirm this is right */
|
||||
CLR_INT; /* TODO: Confirm this is right */
|
||||
#endif
|
||||
} else if ((if_state.cmd & 0x8) == 0x8) {
|
||||
if_state.status |= IF_DRQ;
|
||||
if_set_irq();
|
||||
SET_INT;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -563,7 +545,7 @@ void if_write(uint32 pa, uint32 val, size_t size)
|
|||
case IF_CMD_REG:
|
||||
if_state.cmd = (uint8) val;
|
||||
/* Writing to the command register always de-asserts the IRQ line */
|
||||
if_clear_irq();
|
||||
CLR_INT;
|
||||
|
||||
if ((uptr->flags & UNIT_ATT) == 0) {
|
||||
/* 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);
|
||||
|
||||
extern IF_STATE if_state;
|
||||
extern t_bool if_irq;
|
||||
|
||||
#endif
|
||||
|
|
50
3B2/3b2_io.c
50
3B2/3b2_io.c
|
@ -30,24 +30,24 @@
|
|||
|
||||
#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_csr.h"
|
||||
#include "3b2_dmac.h"
|
||||
#include "3b2_if.h"
|
||||
#include "3b2_iu.h"
|
||||
#include "3b2_mem.h"
|
||||
#include "3b2_mmu.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
#if defined(REV2)
|
||||
#include "3b2_id.h"
|
||||
#endif
|
||||
|
||||
CIO_STATE cio[CIO_SLOTS] = {{0}};
|
||||
|
||||
uint16 cio_int_req = 0; /* Bitset of card slots requesting interrupts */
|
||||
|
||||
#if defined(REV3)
|
||||
iolink iotable[] = {
|
||||
{ MMUBASE, MMUBASE+MMUSIZE, &mmu_read, &mmu_write },
|
||||
|
@ -99,10 +99,10 @@ void cio_clear(uint8 cid)
|
|||
cio[cid].ivec = 0;
|
||||
cio[cid].no_rque = 0;
|
||||
cio[cid].ipl = 0;
|
||||
cio[cid].intr = FALSE;
|
||||
cio[cid].sysgen_s = 0;
|
||||
cio[cid].seqbit = 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,
|
||||
"[READ] [%08x] No card at cid=%d reg=%d\n",
|
||||
R[NUM_PC], cid, reg);
|
||||
csr_data |= CSRTIMO;
|
||||
CSRBIT(CSRTIMO, TRUE);
|
||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||
return 0;
|
||||
}
|
||||
|
@ -594,7 +594,7 @@ uint32 io_read(uint32 pa, size_t size)
|
|||
sim_debug(CIO_DBG, &cpu_dev,
|
||||
"[READ] [%08x] No card at cid=%d reg=%d\n",
|
||||
R[NUM_PC], cid, reg);
|
||||
csr_data |= CSRTIMO;
|
||||
CSRBIT(CSRTIMO, TRUE);
|
||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||
return 0;
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ uint32 io_read(uint32 pa, size_t size)
|
|||
sim_debug(IO_DBG, &cpu_dev,
|
||||
"[%08x] [io_read] ADDR=%08x: No device found.\n",
|
||||
R[NUM_PC], pa);
|
||||
csr_data |= CSRTIMO;
|
||||
CSRBIT(CSRTIMO, TRUE);
|
||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||
return 0;
|
||||
}
|
||||
|
@ -621,6 +621,24 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
|||
iolink *p;
|
||||
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 */
|
||||
if (pa >= CIO_BOTTOM && pa < CIO_TOP) {
|
||||
cid = CID(pa);
|
||||
|
@ -631,7 +649,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
|||
sim_debug(CIO_DBG, &cpu_dev,
|
||||
"[WRITE] [%08x] No card at cid=%d reg=%d\n",
|
||||
R[NUM_PC], cid, reg);
|
||||
csr_data |= CSRTIMO;
|
||||
CSRBIT(CSRTIMO, TRUE);
|
||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||
return;
|
||||
}
|
||||
|
@ -726,7 +744,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
|||
sim_debug(CIO_DBG, &cpu_dev,
|
||||
"[WRITE] [%08x] No card at cid=%d reg=%d\n",
|
||||
R[NUM_PC], cid, reg);
|
||||
csr_data |= CSRTIMO;
|
||||
CSRBIT(CSRTIMO, TRUE);
|
||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||
return;
|
||||
}
|
||||
|
@ -744,7 +762,7 @@ void io_write(uint32 pa, uint32 val, size_t size)
|
|||
sim_debug(IO_DBG, &cpu_dev,
|
||||
"[%08x] [io_write] ADDR=%08x: No device found.\n",
|
||||
R[NUM_PC], pa);
|
||||
csr_data |= CSRTIMO;
|
||||
CSRBIT(CSRTIMO, TRUE);
|
||||
cpu_abort(NORMAL_EXCEPTION, EXTERNAL_MEMORY_FAULT);
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,8 @@
|
|||
#define CIO_INT1 2
|
||||
#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 {
|
||||
uint16 id; /* Card ID */
|
||||
|
@ -174,7 +176,6 @@ typedef struct {
|
|||
uint8 ivec; /* Interrupt Vector */
|
||||
uint8 no_rque; /* Number of request queues */
|
||||
uint8 ipl; /* IPL that this card uses */
|
||||
t_bool intr; /* Card needs to interrupt */
|
||||
uint8 sysgen_s; /* Sysgen state */
|
||||
uint8 seqbit; /* Squence Bit */
|
||||
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,
|
||||
uint32 esize, cio_entry *entry, uint8 *app_data);
|
||||
|
||||
extern uint16 cio_int_req;
|
||||
extern CIO_STATE cio[CIO_SLOTS];
|
||||
|
||||
#endif
|
||||
|
|
88
3B2/3b2_iu.c
88
3B2/3b2_iu.c
|
@ -32,15 +32,44 @@
|
|||
|
||||
#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_csr.h"
|
||||
#include "3b2_dmac.h"
|
||||
#include "3b2_mem.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 SIM_INLINE void iu_w_cmd(uint8 portno, uint8 val);
|
||||
|
@ -310,8 +339,8 @@ void iu_txrdy_a_irq() {
|
|||
(iu_console.stat & STS_TXR)) {
|
||||
sim_debug(EXECUTE_MSG, &tto_dev,
|
||||
"[iu_txrdy_a_irq()] Firing IRQ after transmit of %02x (%c)\n",
|
||||
(uint8) iu_console.txbuf, (char) iu_console.txbuf);
|
||||
csr_data |= CSRUART;
|
||||
(uint8) iu_console.txbuf, PCHAR(iu_console.txbuf));
|
||||
SET_INT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -321,8 +350,8 @@ void iu_txrdy_b_irq() {
|
|||
(iu_contty.stat & STS_TXR)) {
|
||||
sim_debug(EXECUTE_MSG, &contty_dev,
|
||||
"[iu_txrdy_b_irq()] Firing IRQ after transmit of %02x (%c)\n",
|
||||
(uint8) iu_contty.txbuf, (char) iu_contty.txbuf);
|
||||
csr_data |= CSRUART;
|
||||
(uint8) iu_contty.txbuf, PCHAR(iu_contty.txbuf));
|
||||
SET_INT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,7 +425,7 @@ t_stat iu_svc_tti(UNIT *uptr)
|
|||
{
|
||||
int32 temp;
|
||||
|
||||
sim_clock_coschedule(uptr, tmxr_poll);
|
||||
tmxr_clock_coschedule(uptr, tmxr_poll);
|
||||
|
||||
/* TODO:
|
||||
|
||||
|
@ -423,7 +452,7 @@ t_stat iu_svc_tti(UNIT *uptr)
|
|||
iu_console.stat |= STS_RXR;
|
||||
iu_state.istat |= ISTS_RAI;
|
||||
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;
|
||||
iu_state.inprt &= ~(IU_DCDB);
|
||||
iu_state.ipcr |= IU_DCDB;
|
||||
csr_data |= CSRUART;
|
||||
SET_INT;
|
||||
}
|
||||
|
||||
/* Check for disconnect */
|
||||
|
@ -467,7 +496,7 @@ t_stat iu_svc_contty_rcv(UNIT *uptr)
|
|||
contty_ldsc[0].rcve = 0;
|
||||
iu_state.inprt |= IU_DCDB;
|
||||
iu_state.ipcr |= IU_DCDB;
|
||||
csr_data |= CSRUART;
|
||||
SET_INT;
|
||||
} else if (iu_contty.conf & RX_EN) {
|
||||
tmxr_poll_rx(&contty_desc);
|
||||
|
||||
|
@ -484,7 +513,7 @@ t_stat iu_svc_contty_rcv(UNIT *uptr)
|
|||
iu_contty.stat |= STS_RXR;
|
||||
iu_state.istat |= ISTS_RBI;
|
||||
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;
|
||||
|
||||
if (iu_state.imr & IMR_CTR) {
|
||||
csr_data |= CSRUART;
|
||||
SET_INT;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
|
@ -573,7 +602,7 @@ uint32 iu_read(uint32 pa, size_t size)
|
|||
iu_console.stat &= ~(STS_RXR|STS_FFL);
|
||||
iu_state.istat &= ~ISTS_RAI;
|
||||
} else if (iu_state.imr & IMR_RXRA) {
|
||||
csr_data |= CSRUART;
|
||||
SET_INT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -581,7 +610,7 @@ uint32 iu_read(uint32 pa, size_t size)
|
|||
data = iu_state.ipcr;
|
||||
/* Reading the port resets it */
|
||||
iu_state.ipcr = 0;
|
||||
csr_data &= ~CSRUART;
|
||||
CLR_INT;
|
||||
break;
|
||||
case ISR:
|
||||
data = iu_state.istat;
|
||||
|
@ -610,7 +639,7 @@ uint32 iu_read(uint32 pa, size_t size)
|
|||
iu_contty.stat &= ~(STS_RXR|STS_FFL);
|
||||
iu_state.istat &= ~ISTS_RBI;
|
||||
} else if (iu_state.imr & IMR_RXRB) {
|
||||
csr_data |= CSRUART;
|
||||
SET_INT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -625,12 +654,12 @@ uint32 iu_read(uint32 pa, size_t size)
|
|||
case STOP_CTR:
|
||||
data = 0;
|
||||
iu_state.istat &= ~ISTS_CRI;
|
||||
csr_data &= ~CSRUART;
|
||||
CLR_INT;
|
||||
sim_cancel(&iu_timer_unit);
|
||||
break;
|
||||
case 17: /* Clear DMAC interrupt */
|
||||
data = 0;
|
||||
csr_data &= ~CSRDMA;
|
||||
CLR_DMA_INT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -681,7 +710,10 @@ void iu_write(uint32 pa, uint32 val, size_t size)
|
|||
break;
|
||||
case IMR:
|
||||
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 */
|
||||
iu_txrdy_a_irq();
|
||||
iu_txrdy_b_irq();
|
||||
|
@ -784,7 +816,7 @@ t_stat iu_tx(uint8 portno, uint8 val)
|
|||
p->stat |= STS_RXR;
|
||||
if (iu_state.imr & imr_mask) {
|
||||
iu_state.istat |= ists;
|
||||
csr_data |= CSRUART;
|
||||
SET_INT;
|
||||
}
|
||||
|
||||
return SCPE_OK;
|
||||
|
@ -800,12 +832,12 @@ t_stat iu_tx(uint8 portno, uint8 val)
|
|||
/* Write the character to the SIMH console */
|
||||
sim_debug(EXECUTE_MSG, &tto_dev,
|
||||
"[iu_tx] CONSOLE transmit %02x (%c)\n",
|
||||
(uint8) c, (char) c);
|
||||
(uint8) c, PCHAR(c));
|
||||
status = sim_putchar_s(c);
|
||||
} else {
|
||||
sim_debug(EXECUTE_MSG, &contty_dev,
|
||||
"[iu_tx] CONTTY transmit %02x (%c)\n",
|
||||
(uint8) c, (char) c);
|
||||
(uint8) c, PCHAR(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 */
|
||||
port->dma = DMA_NONE;
|
||||
|
||||
dma_state.mask |= (1 << channel);
|
||||
dma_state.status |= (1 << channel);
|
||||
csr_data |= CSRDMA;
|
||||
SET_DMA_INT;
|
||||
}
|
||||
|
||||
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.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"
|
||||
|
||||
#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_csr.h"
|
||||
#include "3b2_io.h"
|
||||
#include "3b2_mmu.h"
|
||||
|
||||
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_mem.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
/* State container for the card */
|
||||
NI_STATE ni;
|
||||
|
@ -286,12 +286,12 @@ static void ni_disable()
|
|||
sim_debug(DBG_TRACE, &ni_dev,
|
||||
"[ni_disable] Disabling the interface.\n");
|
||||
ni.enabled = FALSE;
|
||||
cio[ni.cid].intr = FALSE;
|
||||
sim_cancel(ni_unit);
|
||||
sim_cancel(rcv_unit);
|
||||
sim_cancel(rq_unit);
|
||||
sim_cancel(cio_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)
|
||||
|
@ -870,7 +870,7 @@ t_stat ni_sanity_svc(UNIT *uptr)
|
|||
cio_cqueue(ni.cid, CIO_STAT, NIQESIZE, &cqe, app_data);
|
||||
|
||||
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);
|
||||
|
@ -885,7 +885,7 @@ t_stat ni_cio_svc(UNIT *uptr)
|
|||
if (cio[ni.cid].ivec > 0) {
|
||||
sim_debug(DBG_TRACE, &ni_dev,
|
||||
"[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;
|
||||
|
@ -952,7 +952,7 @@ void ni_process_packet()
|
|||
|
||||
/* Trigger an interrupt */
|
||||
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_io.h"
|
||||
#include "3b2_mem.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
/* Static function declarations */
|
||||
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 */
|
||||
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);
|
||||
|
||||
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) {
|
||||
|
@ -740,7 +740,7 @@ t_stat ports_rcv_svc(UNIT *uptr)
|
|||
if (cio[cid].ivec > 0 &&
|
||||
cio_rqueue(cid, PORTS_RCV_QUEUE,
|
||||
PPQESIZE, &rentry, rapp_data) == SCPE_OK) {
|
||||
cio[cid].intr = TRUE;
|
||||
CIO_SET_INT(cid);
|
||||
|
||||
/* Write the character to the memory address */
|
||||
pwrite_b(rentry.address, c);
|
||||
|
@ -814,7 +814,7 @@ t_stat ports_xmt_svc(UNIT *uptr)
|
|||
centry.address = ports_state[ln].tx_req_addr;
|
||||
app_data[0] = RC_FLU;
|
||||
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_sys.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
uint16 csr_data;
|
||||
|
||||
|
@ -166,15 +166,19 @@ void csr_write(uint32 pa, uint32 val, size_t size)
|
|||
break;
|
||||
case 0x33: /* Set PIR9 */
|
||||
csr_data |= CSRPIR9;
|
||||
CPU_SET_INT(INT_PIR9);
|
||||
break;
|
||||
case 0x37: /* Clear PIR9 */
|
||||
csr_data &= ~CSRPIR9;
|
||||
CPU_CLR_INT(INT_PIR9);
|
||||
break;
|
||||
case 0x3b: /* Set PIR8 */
|
||||
csr_data |= CSRPIR8;
|
||||
CPU_SET_INT(INT_PIR8);
|
||||
break;
|
||||
case 0x3f: /* Clear PIR8 */
|
||||
csr_data &= ~CSRPIR8;
|
||||
CPU_CLR_INT(INT_PIR8);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -79,6 +79,18 @@
|
|||
#define CSRDMA 0x0002 /* DMA Interrupt */
|
||||
#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 */
|
||||
#define MEMSIZE_REG 0x4C003
|
||||
#define MEMID_512K 0
|
||||
|
|
|
@ -85,15 +85,9 @@
|
|||
|
||||
#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_mem.h"
|
||||
#include "3b2_mmu.h"
|
||||
|
||||
#define MAU_ID 0 /* Coprocessor ID of MAU */
|
||||
|
||||
|
@ -282,7 +276,11 @@ DEVICE mau_dev = {
|
|||
NULL, /* attach routine */
|
||||
NULL, /* detach routine */
|
||||
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 */
|
||||
mau_debug, /* debug flag names */
|
||||
NULL, /* memory size change */
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
from the author.
|
||||
*/
|
||||
|
||||
#include "3b2_rev2_mmu.h"
|
||||
|
||||
#include "3b2_sys.h"
|
||||
#include "3b2_cpu.h"
|
||||
#include "3b2_mmu.h"
|
||||
#include "3b2_sys.h"
|
||||
|
||||
UNIT mmu_unit = { UDATA(NULL, 0, 0) };
|
||||
|
||||
|
|
|
@ -187,9 +187,6 @@
|
|||
/* Shift and mask the flag bits for the current CPU mode */
|
||||
#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 */
|
||||
#define MMU_F_SDTLEN 0x03
|
||||
#define MMU_F_PW 0x04
|
||||
|
|
|
@ -31,14 +31,16 @@
|
|||
#include "3b2_defs.h"
|
||||
|
||||
#include "3b2_cpu.h"
|
||||
#include "3b2_csr.h"
|
||||
#include "3b2_ctc.h"
|
||||
#include "3b2_id.h"
|
||||
#include "3b2_if.h"
|
||||
#include "3b2_iu.h"
|
||||
#include "3b2_ni.h"
|
||||
#include "3b2_ports.h"
|
||||
#include "3b2_rev2_mau.h"
|
||||
#include "3b2_mau.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#include "3b2_rev3_csr.h"
|
||||
|
||||
#include "3b2_cpu.h"
|
||||
#include "3b2_csr.h"
|
||||
#include "3b2_if.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
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)
|
||||
{
|
||||
uint32 reg = pa - CSRBASE;
|
||||
|
@ -139,24 +146,31 @@ void csr_write(uint32 pa, uint32 val, size_t size)
|
|||
|
||||
case 0x00:
|
||||
CSRBIT(CSRCLK, val);
|
||||
SET_INT(INT_CLOCK, val);
|
||||
break;
|
||||
case 0x04:
|
||||
CSRBIT(CSRPWRDN, val);
|
||||
SET_INT(INT_PWRDWN, val);
|
||||
break;
|
||||
case 0x08:
|
||||
CSRBIT(CSROPINT15, val);
|
||||
SET_INT(INT_BUS_OP, val);
|
||||
break;
|
||||
case 0x0c:
|
||||
CSRBIT(CSRUART, val);
|
||||
SET_INT(INT_UART, val);
|
||||
break;
|
||||
case 0x10:
|
||||
CSRBIT(CSRDMA, val);
|
||||
SET_INT(INT_UART_DMA, val);
|
||||
break;
|
||||
case 0x14:
|
||||
CSRBIT(CSRPIR9, val);
|
||||
SET_INT(INT_PIR9, val);
|
||||
break;
|
||||
case 0x18:
|
||||
CSRBIT(CSRPIR8, val);
|
||||
SET_INT(INT_PIR8, val);
|
||||
break;
|
||||
case 0x1c:
|
||||
CSRBIT(CSRITIM, val);
|
||||
|
@ -234,15 +248,31 @@ void csr_write(uint32 pa, uint32 val, size_t size)
|
|||
break;
|
||||
case 0x5c:
|
||||
CSRBIT(CSRSBERR, val);
|
||||
if (val) {
|
||||
if (!(csr_data & CSRISBERR)) {
|
||||
SET_INT(INT_SBERR, TRUE);
|
||||
}
|
||||
} else {
|
||||
SET_INT(INT_SBERR, FALSE);
|
||||
}
|
||||
break;
|
||||
case 0x60:
|
||||
CSRBIT(CSRMBERR, val);
|
||||
SET_INT(INT_MBERR, val);
|
||||
break;
|
||||
case 0x64:
|
||||
CSRBIT(CSRUBUBF, val);
|
||||
SET_INT(INT_BUS_RXF, val);
|
||||
break;
|
||||
case 0x68:
|
||||
CSRBIT(CSRTIMO, val);
|
||||
if (val) {
|
||||
if (!(csr_data & CSRITIMO)) {
|
||||
SET_INT(INT_BUS_TMO, TRUE);
|
||||
}
|
||||
} else {
|
||||
SET_INT(INT_BUS_TMO, FALSE);
|
||||
}
|
||||
break;
|
||||
case 0x6c:
|
||||
CSRBIT(CSRFRF, val);
|
||||
|
|
|
@ -33,12 +33,63 @@
|
|||
|
||||
#define NUM_REGISTERS 32
|
||||
|
||||
#define DEFMEMSIZE MSIZ_4M
|
||||
#define DEFMEMSIZE MSIZ_16M
|
||||
#define MAXMEMSIZE MSIZ_64M
|
||||
|
||||
#define HWORD_OP_COUNT 12
|
||||
#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 */
|
||||
#define MEMID_4M 6
|
||||
#define MEMID_16M 7
|
||||
|
@ -95,38 +146,4 @@
|
|||
#define DMA_IUB 0x47
|
||||
#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
|
||||
|
|
|
@ -28,11 +28,11 @@
|
|||
from the author.
|
||||
*/
|
||||
|
||||
#include "3b2_rev3_mmu.h"
|
||||
|
||||
#include "3b2_cpu.h"
|
||||
#include "3b2_csr.h"
|
||||
#include "3b2_mem.h"
|
||||
#include "3b2_rev3_csr.h"
|
||||
#include "3b2_mmu.h"
|
||||
|
||||
UNIT mmu_unit = { UDATA(NULL, 0, 0) };
|
||||
|
||||
|
|
|
@ -167,14 +167,14 @@
|
|||
#define SDC_IDX(va) ((uint8)((va) >> 17) & 7)
|
||||
|
||||
/* Convert from sd to sd cache entry */
|
||||
#define SD_TO_SDCH(hi,lo) ((hi) & SD_ADDR_MASK | \
|
||||
((lo) & SD_C_MASK) >> 1 | \
|
||||
((lo) & SD_CACHE_MASK) >> 1 | \
|
||||
#define SD_TO_SDCH(hi,lo) (((hi) & SD_ADDR_MASK) | \
|
||||
((lo) & SD_C_MASK) >> 1 | \
|
||||
((lo) & SD_CACHE_MASK) >> 1 | \
|
||||
(SDC_G_MASK))
|
||||
#define SD_TO_SDCL(lo,va) (((lo) & SD_ACC_MASK) | \
|
||||
((lo) & SD_MAX_OFF_MASK) >> 3 | \
|
||||
((lo) & SD_R_MASK) << 18 | \
|
||||
((lo) & SD_M_MASK) << 21 | \
|
||||
#define SD_TO_SDCL(lo,va) (((lo) & SD_ACC_MASK) | \
|
||||
((lo) & SD_MAX_OFF_MASK) >> 3 | \
|
||||
((lo) & SD_R_MASK) << 18 | \
|
||||
((lo) & SD_M_MASK) << 21 | \
|
||||
((va) & SD_VADDR_MASK) >> 20)
|
||||
|
||||
/* Convert from sd cache entry to sd */
|
||||
|
@ -188,18 +188,18 @@
|
|||
SD_V_MASK | SD_P_MASK)
|
||||
|
||||
/* Convert from pd cache entry to pd */
|
||||
#define PDCE_TO_PD(pdcl) (((pdcl & PDC_PADDR_MASK) << 11) | \
|
||||
((pdcl & PDC_W_MASK) >> 17) | \
|
||||
((pdcl & PDC_M_MASK) >> 21) | \
|
||||
((pdcl & PDC_R_MASK) >> 18) | \
|
||||
#define PDCE_TO_PD(pdcl) ((((pdcl) & PDC_PADDR_MASK) << 11) | \
|
||||
(((pdcl) & PDC_W_MASK) >> 17) | \
|
||||
(((pdcl) & PDC_M_MASK) >> 21) | \
|
||||
(((pdcl) & PDC_R_MASK) >> 18) | \
|
||||
PD_P_MASK)
|
||||
|
||||
/* Convert from pd to pd cache entry (low word) */
|
||||
#define PD_TO_PDCL(pd, sd_lo) (((pd & PD_PADDR_MASK) >> 11) | \
|
||||
((pd & PD_W_MASK) << 17) | \
|
||||
((pd & PD_M_MASK) << 21) | \
|
||||
((pd & PD_R_MASK) << 18) | \
|
||||
(sd_lo & SD_ACC_MASK))
|
||||
#define PD_TO_PDCL(pd, sd_lo) ((((pd) & PD_PADDR_MASK) >> 11) | \
|
||||
(((pd) & PD_W_MASK) << 17) | \
|
||||
(((pd) & PD_M_MASK) << 21) | \
|
||||
(((pd) & PD_R_MASK) << 18) | \
|
||||
((sd_lo) & SD_ACC_MASK))
|
||||
|
||||
/* Convert from va to pd cache entry (high word / tag) */
|
||||
#define VA_TO_PDCH(va, sd_lo) ((1 << 30) | \
|
||||
|
|
|
@ -31,13 +31,15 @@
|
|||
#include "3b2_defs.h"
|
||||
|
||||
#include "3b2_cpu.h"
|
||||
#include "3b2_csr.h"
|
||||
#include "3b2_if.h"
|
||||
#include "3b2_iu.h"
|
||||
#include "3b2_mau.h"
|
||||
#include "3b2_ni.h"
|
||||
#include "3b2_ports.h"
|
||||
#include "3b2_rev2_mau.h" /* TODO: Replace with Rev 3 MAU when implemented */
|
||||
#include "3b2_scsi.h"
|
||||
#include "3b2_stddev.h"
|
||||
#include "3b2_timer.h"
|
||||
|
||||
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)
|
||||
};
|
||||
|
||||
#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 ha_unit[] = {
|
||||
|
@ -335,7 +335,7 @@ t_stat ha_svc(UNIT *uptr)
|
|||
sim_debug(HA_TRACE, &ha_dev,
|
||||
"[%08x] [ha_svc] IRQ for board %d (VEC=%d).\n",
|
||||
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;
|
||||
|
|
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
|
||||
|
||||
|
@ -32,21 +32,15 @@
|
|||
This file contains system-specific registers and devices for the
|
||||
following 3B2 devices:
|
||||
|
||||
- timer 8253 interval timer
|
||||
- nvram Non-Volatile RAM
|
||||
- csr Control Status Registers
|
||||
- tod MM58174A Real-Time-Clock
|
||||
- flt Fault Register
|
||||
*/
|
||||
|
||||
#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_csr.h"
|
||||
|
||||
DEBTAB sys_deb_tab[] = {
|
||||
{ "INIT", INIT_MSG, "Init" },
|
||||
|
@ -58,14 +52,9 @@ DEBTAB sys_deb_tab[] = {
|
|||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
struct timer_ctr TIMERS[3];
|
||||
|
||||
uint32 *NVRAM = NULL;
|
||||
|
||||
int32 tmxr_poll = 16667;
|
||||
|
||||
/* NVRAM */
|
||||
|
||||
UNIT nvram_unit = {
|
||||
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
|
||||
*
|
||||
* 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 = {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -28,40 +28,11 @@
|
|||
from the author.
|
||||
*/
|
||||
|
||||
#ifndef _3B2_REV2_SYSDEV_H_
|
||||
#define _3B2_REV2_SYSDEV_H_
|
||||
#ifndef _3B2_STDDEV_H_
|
||||
#define _3B2_STDDEV_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 */
|
||||
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);
|
||||
|
@ -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);
|
||||
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 */
|
||||
|
||||
typedef struct tod_data {
|
||||
int32 delta; /* Delta between simulated time and real time (sec.) */
|
||||
uint8 tsec; /* 1/10 seconds */
|
||||
|
@ -125,11 +75,8 @@ void tod_write(uint32, uint32 val, size_t size);
|
|||
|
||||
#if defined(REV3)
|
||||
/* Fault Register */
|
||||
|
||||
uint32 flt_read(uint32 pa, size_t size);
|
||||
void flt_write(uint32 pa, uint32 val, size_t size);
|
||||
#endif
|
||||
|
||||
extern int32 tmxr_poll;
|
||||
|
||||
#endif /* _3B2_REV2_SYSDEV_H_ */
|
||||
#endif /* _3B2_STDDEV_H_ */
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
from the author.
|
||||
*/
|
||||
|
||||
#ifndef _3B2_REV2_SYS_H_
|
||||
#define _3B2_REV2_SYS_H_
|
||||
#ifndef _3B2_SYS_H_
|
||||
#define _3B2_SYS_H_
|
||||
|
||||
#include "3b2_defs.h"
|
||||
|
||||
|
@ -43,4 +43,4 @@ extern char sim_name[];
|
|||
extern REG *sim_PC;
|
||||
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
|
||||
==================
|
||||
|
||||
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:
|
||||
|
||||
|
@ -23,6 +29,7 @@ devices are given in parentheses:
|
|||
- uPD7261A Integrated MFM Fixed Disk Controller (IDISK)
|
||||
- Non-Volatile Memory (NVRAM)
|
||||
- MM58174A Time Of Day Clock (TOD)
|
||||
- CM195A Ethernet Network Interface (NI)
|
||||
- CM195B 4-port Serial MUX (PORTS)
|
||||
- CM195H Cartridge Tape Controller (CTC)
|
||||
|
||||
|
|
|
@ -239,6 +239,10 @@
|
|||
RelativePath="..\3B2\3b2_rev3_sys.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev3_timer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_scsi.c"
|
||||
>
|
||||
|
@ -536,11 +540,11 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev2_csr.h"
|
||||
RelativePath="..\3B2\3b2_rev3_csr.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev2_defs.h"
|
||||
RelativePath="..\3B2\3b2_rev3_defs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -548,11 +552,15 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev2_mmu.h"
|
||||
RelativePath="..\3B2\3b2_rev3_mmu.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev2_sys.h"
|
||||
RelativePath="..\3B2\3b2_rev3_sys.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev3_timer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
|
|
@ -251,6 +251,10 @@
|
|||
RelativePath="..\3B2\3b2_rev2_csr.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev2_timer.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_stddev.c"
|
||||
>
|
||||
|
@ -559,6 +563,10 @@
|
|||
RelativePath="..\3B2\3b2_rev2_csr.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\3B2\3b2_rev2_timer.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
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 \
|
||||
${ATT3B2D}/3b2_rev2_sys.c ${ATT3B2D}/3b2_rev2_mmu.c \
|
||||
${ATT3B2D}/3b2_rev2_mau.c ${ATT3B2D}/3b2_rev2_csr.c \
|
||||
${ATT3B2D}/3b2_stddev.c ${ATT3B2D}/3b2_mem.c \
|
||||
${ATT3B2D}/3b2_iu.c ${ATT3B2D}/3b2_if.c \
|
||||
${ATT3B2D}/3b2_id.c ${ATT3B2D}/3b2_dmac.c \
|
||||
${ATT3B2D}/3b2_io.c ${ATT3B2D}/3b2_ports.c \
|
||||
${ATT3B2D}/3b2_ctc.c ${ATT3B2D}/3b2_ni.c
|
||||
${ATT3B2D}/3b2_rev2_timer.c ${ATT3B2D}/3b2_stddev.c \
|
||||
${ATT3B2D}/3b2_mem.c ${ATT3B2D}/3b2_iu.c \
|
||||
${ATT3B2D}/3b2_if.c ${ATT3B2D}/3b2_id.c \
|
||||
${ATT3B2D}/3b2_dmac.c ${ATT3B2D}/3b2_io.c \
|
||||
${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_ctc.c \
|
||||
${ATT3B2D}/3b2_ni.c
|
||||
ATT3B2M400_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV2 -I ${ATT3B2D} ${NETWORK_OPT}
|
||||
|
||||
ATT3B2M600 = ${ATT3B2D}/3b2_cpu.c ${ATT3B2D}/3b2_sys.c \
|
||||
${ATT3B2D}/3b2_rev3_sys.c ${ATT3B2D}/3b2_rev3_mmu.c \
|
||||
${ATT3B2D}/3b2_rev2_mau.c ${ATT3B2D}/3b2_rev3_csr.c \
|
||||
${ATT3B2D}/3b2_stddev.c ${ATT3B2D}/3b2_mem.c \
|
||||
${ATT3B2D}/3b2_iu.c ${ATT3B2D}/3b2_if.c \
|
||||
${ATT3B2D}/3b2_dmac.c ${ATT3B2D}/3b2_io.c \
|
||||
${ATT3B2D}/3b2_ports.c ${ATT3B2D}/3b2_scsi.c \
|
||||
${ATT3B2D}/3b2_ni.c
|
||||
${ATT3B2D}/3b2_rev3_timer.c ${ATT3B2D}/3b2_stddev.c \
|
||||
${ATT3B2D}/3b2_mem.c ${ATT3B2D}/3b2_iu.c \
|
||||
${ATT3B2D}/3b2_if.c ${ATT3B2D}/3b2_dmac.c \
|
||||
${ATT3B2D}/3b2_io.c ${ATT3B2D}/3b2_ports.c \
|
||||
${ATT3B2D}/3b2_scsi.c ${ATT3B2D}/3b2_ni.c
|
||||
ATT3B2M600_OPT = -DUSE_INT64 -DUSE_ADDR64 -DREV3 -I ${ATT3B2D} ${NETWORK_OPT}
|
||||
|
||||
SIGMAD = ${SIMHD}/sigma
|
||||
|
|
Loading…
Add table
Reference in a new issue