AltairZ80: Add support for the AB Digital B810.

The AB Digital Design B810 RAM card is a 256K Dynamic RAM card
with onboard refresh logic.  AltairZ80 support emulates four of
these cards for a total of 16 banks.

As used for the OASIS operating system, the B810 is configured
with common memory at the low addresses (0000h-3FFFh) with 16
banks of 48K from 4000h-FFFFh.

In order to have the common memory appear from 0000-3FFFh, set
the COMMONLOW register to 1:

D COMMONLOW 1
This commit is contained in:
Howard M. Harte 2020-12-12 20:43:07 -08:00
parent bcaf577d21
commit d0c009504b

View file

@ -242,6 +242,7 @@ UNIT cpu_unit = {
int32 SR = 0; /* switch register */ int32 SR = 0; /* switch register */
static int32 bankSelect = 0; /* determines selected memory bank */ static int32 bankSelect = 0; /* determines selected memory bank */
static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ static uint32 common = 0xc000; /* addresses >= 'common' are in common memory */
static uint32 common_low = 0; /* Common area is in low memory */
static uint32 previousCapacity = MAXBANKSIZE; /* safe for previous memory capacity */ static uint32 previousCapacity = MAXBANKSIZE; /* safe for previous memory capacity */
static uint32 clockFrequency = 0; /* in kHz, 0 means as fast as possible */ static uint32 clockFrequency = 0; /* in kHz, 0 means as fast as possible */
static uint32 sliceLength = 10; /* length of time-slice for CPU speed */ static uint32 sliceLength = 10; /* length of time-slice for CPU speed */
@ -465,6 +466,8 @@ REG cpu_reg[] = {
REG_HRO }, /* 80 */ REG_HRO }, /* 80 */
{ HRDATAD (WRU, sim_int_char, 8, "Interrupt character pseudo register"), { HRDATAD (WRU, sim_int_char, 8, "Interrupt character pseudo register"),
}, /* 81 */ }, /* 81 */
{ HRDATAD(COMMONLOW,common_low, 1, "If set, use low memory for common area"),
}, /* 82 */
{ NULL } { NULL }
}; };
@ -521,6 +524,8 @@ static MTAB cpu_mod[] = {
NULL, NULL, "Sets the RAM type to Vector RAM for 8080 / Z80 / 8086" }, NULL, NULL, "Sets the RAM type to Vector RAM for 8080 / Z80 / 8086" },
{ MTAB_XTD | MTAB_VDV, 3, NULL, "CRAM", &cpu_set_ramtype, { MTAB_XTD | MTAB_VDV, 3, NULL, "CRAM", &cpu_set_ramtype,
NULL, NULL, "Sets the RAM type to Cromemco RAM for 8080 / Z80 / 8086" }, NULL, NULL, "Sets the RAM type to Cromemco RAM for 8080 / Z80 / 8086" },
{ MTAB_XTD | MTAB_VDV, 4, NULL, "B810", &cpu_set_ramtype,
NULL, NULL, "Sets the RAM type AB Digital Design B810 8080 / Z80 / 8086"},
{ MTAB_VDV, 4, NULL, "4KB", &cpu_set_size, { MTAB_VDV, 4, NULL, "4KB", &cpu_set_size,
NULL, NULL, "Sets the RAM size to 4KB for 8080 / Z80 / 8086" }, NULL, NULL, "Sets the RAM size to 4KB for 8080 / Z80 / 8086" },
{ MTAB_VDV, 8, NULL, "8KB", &cpu_set_size, { MTAB_VDV, 8, NULL, "8KB", &cpu_set_size,
@ -649,8 +654,15 @@ const char* handlerNameForPort(const int32 port) {
return dev_table[port & 0xff].name; return dev_table[port & 0xff].name;
} }
static int32 ramtype = 0;
#define MAX_RAM_TYPE 3 #define RAM_TYPE_AZ80 0 /* Altair-Z80 RAM card */
#define RAM_TYPE_HRAM 1 /* North Start Horizon RAM card */
#define RAM_TYPE_VRAM 2 /* Vector Graphic RAM card */
#define RAM_TYPE_CRAM 3 /* Cromemco RAM card */
#define RAM_TYPE_B810 4 /* AB Digital Design B810 RAM card */
#define MAX_RAM_TYPE RAM_TYPE_B810
static int32 ramtype = RAM_TYPE_AZ80;
ChipType chiptype = CHIP_TYPE_8080; ChipType chiptype = CHIP_TYPE_8080;
@ -1787,7 +1799,7 @@ uint32 sim_map_resource(uint32 baseaddr, uint32 size, uint32 resource_type,
if (resource_type == RESOURCE_TYPE_MEMORY) { if (resource_type == RESOURCE_TYPE_MEMORY) {
for (i = 0; i < (size >> LOG2PAGESIZE); i++) { for (i = 0; i < (size >> LOG2PAGESIZE); i++) {
addr = (baseaddr & 0xfff00) + (i << LOG2PAGESIZE); addr = (baseaddr & 0xfff00) + (i << LOG2PAGESIZE);
if ((cpu_unit.flags & UNIT_CPU_BANKED) && (addr < common)) if ((cpu_unit.flags & UNIT_CPU_BANKED) && (((common_low == 0) && (addr < common)) || ((common_low == 1) && (addr >= common))))
addr |= bankSelect << MAXBANKSIZELOG2; addr |= bankSelect << MAXBANKSIZELOG2;
page = addr >> LOG2PAGESIZE; page = addr >> LOG2PAGESIZE;
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
@ -1835,8 +1847,9 @@ static void PutBYTE(register uint32 Addr, const register uint32 Value) {
MDEV m; MDEV m;
Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */
if ((cpu_unit.flags & UNIT_CPU_BANKED) && (Addr < common)) if ((cpu_unit.flags & UNIT_CPU_BANKED) && (((common_low == 0) && (Addr < common)) || ((common_low == 1) && (Addr >= common))))
Addr |= bankSelect << MAXBANKSIZELOG2; Addr |= bankSelect << MAXBANKSIZELOG2;
m = mmu_table[Addr >> LOG2PAGESIZE]; m = mmu_table[Addr >> LOG2PAGESIZE];
if (m.isRAM) if (m.isRAM)
@ -1878,7 +1891,7 @@ static uint32 GetBYTE(register uint32 Addr) {
MDEV m; MDEV m;
Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */
if ((cpu_unit.flags & UNIT_CPU_BANKED) && (Addr < common)) if ((cpu_unit.flags & UNIT_CPU_BANKED) && (((common_low == 0) && (Addr < common)) || ((common_low == 1) && (Addr >= common))))
Addr |= bankSelect << MAXBANKSIZELOG2; Addr |= bankSelect << MAXBANKSIZELOG2;
m = mmu_table[Addr >> LOG2PAGESIZE]; m = mmu_table[Addr >> LOG2PAGESIZE];
@ -6185,7 +6198,8 @@ static t_stat sim_instr_mmu (void) {
/* simulation halted */ /* simulation halted */
PC_S = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : (PC & ADDRMASK); PC_S = ((reason == STOP_OPCODE) || (reason == STOP_MEM)) ? PCX : (PC & ADDRMASK);
if ((cpu_unit.flags & UNIT_CPU_BANKED) && ((uint32)PC_S < common)) if ((cpu_unit.flags & UNIT_CPU_BANKED) && ((((common_low == 0) && ((uint32)PC_S < common))) || (((common_low == 1) && ((uint32)PC_S >= common)))))
PC_S |= bankSelect << MAXBANKSIZELOG2; PC_S |= bankSelect << MAXBANKSIZELOG2;
pcq_r -> qptr = pcq_p; /* update pc q ptr */ pcq_r -> qptr = pcq_p; /* update pc q ptr */
AF_S = AF; AF_S = AF;
@ -6412,7 +6426,7 @@ const static CPUFLAG *cpuflags[NUM_CHIP_TYPE] = { cpuflags8080, cpuflagsZ80,
cpuflags8086, cpuflagsM68K, }; cpuflags8086, cpuflagsM68K, };
/* needs to be set for each ramtype <= MAX_RAM_TYPE */ /* needs to be set for each ramtype <= MAX_RAM_TYPE */
static const char *ramTypeToString[] = { "AZ80", "HRAM", "VRAM", "CRAM" }; static const char *ramTypeToString[] = { "AZ80", "HRAM", "VRAM", "CRAM", "B810" };
static t_stat chip_show(FILE *st, UNIT *uptr, int32 val, CONST void *desc) { static t_stat chip_show(FILE *st, UNIT *uptr, int32 val, CONST void *desc) {
fprintf(st, cpu_unit.flags & UNIT_CPU_OPSTOP ? "ITRAP, " : "NOITRAP, "); fprintf(st, cpu_unit.flags & UNIT_CPU_OPSTOP ? "ITRAP, " : "NOITRAP, ");
@ -6549,14 +6563,14 @@ static t_stat cpu_set_nonbanked(UNIT *uptr, int32 value, CONST char *cptr, void
static int32 bankseldev(const int32 port, const int32 io, const int32 data) { static int32 bankseldev(const int32 port, const int32 io, const int32 data) {
if (io) { if (io) {
switch(ramtype) { switch(ramtype) {
case 1: case RAM_TYPE_HRAM:
if (data & 0x40) { if (data & 0x40) {
sim_printf("HRAM: Parity %s\n", data & 1 ? "ON" : "OFF"); sim_printf("HRAM: Parity %s\n", data & 1 ? "ON" : "OFF");
} else { } else {
sim_printf("HRAM BANKSEL=%02x\n", data); sim_printf("HRAM BANKSEL=%02x\n", data);
} }
break; break;
case 2: case RAM_TYPE_VRAM:
/* sim_printf("VRAM BANKSEL=%02x\n", data);*/ /* sim_printf("VRAM BANKSEL=%02x\n", data);*/
switch(data & 0xFF) { switch(data & 0xFF) {
case 0x01: case 0x01:
@ -6590,7 +6604,7 @@ static int32 bankseldev(const int32 port, const int32 io, const int32 data) {
break; break;
} }
break; break;
case 3: case RAM_TYPE_CRAM:
/* sim_printf(ADDRESS_FORMAT " CRAM BANKSEL=%02x\n", PCX, data); */ /* sim_printf(ADDRESS_FORMAT " CRAM BANKSEL=%02x\n", PCX, data); */
switch(data & 0x7F) { switch(data & 0x7F) {
case 0x01: case 0x01:
@ -6621,9 +6635,14 @@ static int32 bankseldev(const int32 port, const int32 io, const int32 data) {
sim_printf("Invalid bank select 0x%02x for CRAM\n", data); sim_printf("Invalid bank select 0x%02x for CRAM\n", data);
break; break;
} }
case RAM_TYPE_B810:
if (data < 16) {
setBankSelect(data);
} else {
sim_printf("Invalid bank select 0x%02x for B810\n", data);
}
break; break;
case 0: case RAM_TYPE_AZ80:
default: default:
break; break;
} }
@ -6746,21 +6765,26 @@ static t_stat cpu_set_ramtype(UNIT *uptr, int32 value, CONST char *cptr, void *d
} }
switch(ramtype) { switch(ramtype) {
case 1: case RAM_TYPE_HRAM:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("Unmapping NorthStar HRAM\n"); sim_printf("Unmapping NorthStar HRAM\n");
sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", TRUE); sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", TRUE);
break; break;
case 2: case RAM_TYPE_VRAM:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("Unmapping Vector RAM\n"); sim_printf("Unmapping Vector RAM\n");
sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", TRUE); sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", TRUE);
break; break;
case 3: case RAM_TYPE_CRAM:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("Unmapping Cromemco RAM\n"); sim_printf("Unmapping Cromemco RAM\n");
sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", TRUE); sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", TRUE);
break; break;
case RAM_TYPE_B810:
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("Unmapping AB Digital Design B810 RAM\n");
sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", TRUE);
break;
case 0: case 0:
default: default:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
@ -6769,21 +6793,26 @@ static t_stat cpu_set_ramtype(UNIT *uptr, int32 value, CONST char *cptr, void *d
} }
switch(value) { switch(value) {
case 1: case RAM_TYPE_HRAM:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("NorthStar HRAM Selected\n"); sim_printf("NorthStar HRAM Selected\n");
sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", FALSE); sim_map_resource(0xC0, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", FALSE);
break; break;
case 2: case RAM_TYPE_VRAM:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("Vector RAM Selected\n"); sim_printf("Vector RAM Selected\n");
sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", FALSE); sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", FALSE);
break; break;
case 3: case RAM_TYPE_CRAM:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("Cromemco RAM Selected\n"); sim_printf("Cromemco RAM Selected\n");
sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", FALSE); sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", FALSE);
break; break;
case RAM_TYPE_B810:
if (cpu_unit.flags & UNIT_CPU_VERBOSE)
sim_printf("AB Digital Design B810 RAM Selected\n");
sim_map_resource(0x40, 1, RESOURCE_TYPE_IO, &bankseldev, "bankseldev", FALSE);
break;
case 0: case 0:
default: default:
if (cpu_unit.flags & UNIT_CPU_VERBOSE) if (cpu_unit.flags & UNIT_CPU_VERBOSE)