mikpe.pdp10-tools/sim/pdp10-ea.c
2018-05-08 22:42:06 +02:00

174 lines
4.8 KiB
C

/*
* pdp10-ea.c -- PDP10 Effective-Address Calculation
* Copyright (C) 2018 Mikael Pettersson
*
* This file is part of pdp10-tools.
*
* pdp10-tools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* pdp10-tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with pdp10-tools. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pdp10-core.h"
#include "pdp10-arith.h"
/* c.f. Figure 1.9 in the Toad-1 Architecture Manual */
static
uint64_t pdp10_section_zero_ea(struct pdp10_cpu *cpu, uint64_t MB)
{
/* Instruction Fetch (not done here)
*
* MB := C(PC)
* IR := MB_<0:12>
*/
for (;;) {
uint32_t Y = BITS36(MB, 18, 35); /* Y := MB_<18:35> */
unsigned int X = BITS36(MB, 14, 17); /* X := MB_<14:17> */
unsigned int I = BIT36(MB, 13); /* I := MB_<13> */
uint32_t E; /* 18 bits */
if (X == 0) {
E = Y;
} else {
E = BITS36LOW18(Y + BITS36LOW18(cpu->AC[X])); /* E := Y + C(X)_<18:35> */
}
if (I == 0) {
return E;
}
/* MB := C(E), but handle ACs */
if (E <= 017) {
MB = cpu->AC[E];
} else {
MB = pdp10_vmem_read(&cpu->vmem, E);
if (MB == (uint64_t)-1)
return MB; /* propagate page fault */
}
}
}
/* c.f. Figure 1.11 in the Toad-1 Architecture Manual */
static
uint64_t pdp10_extended_ea(struct pdp10_cpu *cpu, uint64_t MB)
{
uint32_t E; /* 30 bits */
/* Instruction Fetch (not done here)
*
* if PC_<18:31> == 0 then MB := C(PC_<32:35>)
* else MB := C(PC_<6:35>)
* IR := MB_<0:12>
*/
E = BITS36(cpu->PC, 6, 17) << 18; /* E_<6:17> := PC_<6:17> */
/* Local-Format Address Word */
/* A Local Address is in the same section as this Address Word */
for (;;) {
unsigned int I = BIT36(MB, 13); /* I := MB_<13> */
{
uint32_t Y = BITS36(MB, 18, 35); /* Y_<18:35> := MB_<18:35> */
unsigned int X = BITS36(MB, 14, 17); /* X := MB_<14:17> */
/* Indexed Address? Test X field. */
if (X == 0) {
/* No Indexing */
E = BITS36(E, 6, 17) | Y; /* E_<18:35> := Y_<18:35> */
} else {
/* X field != 0 */
pdp10_uint36_t CX = cpu->AC[X];
/* Test Section Number in E_<6:17> */
if (BITS36(E, 6, 17) == 0) { /* Section 0 */
/* Local Index */
E = BITS36(E, 6, 17) | BITS36LOW18(CX + Y); /* E_<18:35> := C(X)_<18:35> + Y_<18:35> */
} else {
/* Section != 0 */
/* Test C(X). Global Index when (C(X)_<0> == 0) && (C(X)_<6:17> != 0) */
if (!(BIT36(CX, 0) == 0 && BITS36(CX, 6, 17) != 0)) {
/* Local Index */
E = BITS36(E, 6, 17) | BITS36LOW18(CX + Y); /* E_<18:35> := C(X)_<18:35> + Y_<18:35> */
} else {
/* Global Index */
Y = pdp10_sext_uint18(Y); /* Y_<6:17> := 07777 * Y_<18> */
E = BITS36((CX + Y), 6, 35); /* E_<6:35> := C(X)_<6:35> + Y_<6:35> */
}
}
}
}
for (;;) {
/* Indirect Addressing? Test I bit. */
if (I == 0) { /* Done! */
/* E is the Effective Address */
/* The "XCT Continues" loop is implemented by the caller. */
return E;
}
/* Fetch the Indirect Word: MB := C(E) */
/* FIXME: handle ACs? */
MB = pdp10_vmem_read(&cpu->vmem, E);
if (MB == (uint64_t)-1)
return MB; /* propagate page fault */
/* Non-Zero Section? Test E_<6:17> */
if (BITS36(E, 6, 17) == 0) {
/* Section 0 */
break;
} else {
/* Section != 0 */
/* Decode Indirect Word MB_<0:1> */
switch (BITS36(MB, 0, 1)) {
case 2:
/* Local Indirect */
break;
case 3:
/* Page Failure */
return (uint64_t)-1;
case 0:
case 1: {
/* Global Indirect Word */
uint32_t Y = BITS36(MB, 6, 35); /* Y := MB_<6:35> */
unsigned int X = BITS36(MB, 2, 5); /* X := MB_<2:5> */
I = BIT36(MB, 1); /* I := MB_<1> */
/* Indexed Address? Test X field. */
if (X == 0) {
E = Y; /* E_<6:35> := Y_<6:35> */
} else {
E = BITS36((cpu->AC[X] + Y), 6, 35); /* E_<6:35> := C(X)_6:35 + Y_<6:35> */
}
continue;
}
}
}
break;
}
}
}
static
int pdp10_section_zero_p(struct pdp10_cpu *cpu)
{
/* My interpretation is that the choice of EA procedure is only based on
* whether the CPU is extended or not, so an extended CPU should always
* use the extended EA procedure, regardless of which section PC is in.
*/
return 0;
}
uint64_t pdp10_ea(struct pdp10_cpu *cpu, uint64_t MB)
{
if (pdp10_section_zero_p(cpu))
return pdp10_section_zero_ea(cpu, MB);
else
return pdp10_extended_ea(cpu, MB);
}