PDP-8-E-Simulator/RK8E/RK8Eiot.c

384 lines
11 KiB
C

/*
* PDP-8/E Simulator Source Code
*
* Copyright © 1994-2015 Bernhard Baehr
*
* RK8Eiot.h - IOTs for the RK8-E plugin
*
* This file is part of PDP-8/E Simulator.
*
* PDP-8/E Simulator 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import <Cocoa/Cocoa.h>
#define USE_RK8E_REGISTERS_DIRECTLY 1
#define USE_PDP8_REGISTERS_DIRECTLY 1
#include "PluginFramework/PluginAPI.h"
#include "PluginFramework/PDP8.h"
#include "RK8Eiot.h"
#include "RK8E.h"
#include "RK05.h"
void i6741 (void) /* DSKP 6741 */
{
RK8E *rk8e = PLUGIN_POINTER(RK8E);
[rk8e lockControl];
if (pdp8->IOFLAGS & rk8e->ioflag)
pdp8->PC++;
[rk8e unlockControl];
EXECUTION_TIME (26);
}
unsigned s6741 (void) /* DSKP 6741 skiptest */
{
return pdp8->IOFLAGS & PLUGIN_POINTER(RK8E)->ioflag;
}
void i6742 (void) /* DCLR 6742 */
{
RK05 *pack;
RK8E *rk8e = PLUGIN_POINTER(RK8E);
[rk8e lockControl];
rk8e->status = 0;
switch (pdp8->AC & 3) {
case 03 :
/* Unlock the drive - else MAINDEC-08-DHRKA-B-PB (diskless control test)
fails on second pass at test 15 because the drives are write protected.
(What happens with a real RK8-E in this case?)
if (! rk8e.pack[(pdp8.AC & 06) >> 1].pb.ioRefNum)
rk8e.pack[(pdp8.AC & 06) >> 1].locked = false;
*/
/* undefined 03 does the same as 00 - fall through */
case 00 :
pdp8->AC &= 010000 ;
pdp8->IOFLAGS &= ~rk8e->ioflag;
pack = rk8e->rk05[(rk8e->command >> 1) & 3];
if (! [pack isMounted])
rk8e->status |= STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY;
if ([pack isCalibrating]) {
rk8e->status |= STATUS_CONTROL_BUSY | STATUS_ERROR;
pdp8->IOFLAGS |= rk8e->ioflag;
}
break;
case 01 :
pdp8->AC &= 010000;
pdp8->IMASK &= ~rk8e->ioflag;
pdp8->IOFLAGS &= ~rk8e->ioflag;
rk8e->command = 0;
rk8e->block &= ~010000; /* CRC is not affected */
rk8e->curaddr = 0;
[rk8e->rk05[0] abortAllCommands];
[rk8e->rk05[1] abortAllCommands];
[rk8e->rk05[2] abortAllCommands];
[rk8e->rk05[3] abortAllCommands];
rk8e->maint = false;
rk8e->ldbfill = 0;
rk8e->ldb[0] = 0;
rk8e->ldb[1] = 0;
rk8e->ldb[2] = 0;
rk8e->ldb[3] = 0;
rk8e->udb = 0;
rk8e->wordcount = 0;
rk8e->shifts = 0;
if (! [rk8e->rk05[0] isMounted])
rk8e->status |= STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY;
break;
case 02 : /* recalibrate to track 0 */
pdp8->AC &= 010000;
pack = rk8e->rk05[(rk8e->command >> 1) & 3];
BOOL wasCalibrating = [pack isCalibrating];
[pack setRecalibrating];
if ([pack isMounted]) {
[pack setFlushCylinder];
[pack setReadCylinder:0];
rk8e->status |= STATUS_DONE;
pdp8->IOFLAGS |= rk8e->ioflag;
if ([pack isBusy]) {
[pack setRaiseFlag];
[pack start];
}
} else {
rk8e->status |= STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY | STATUS_ERROR;
if (wasCalibrating)
rk8e->status |= STATUS_CONTROL_BUSY;
if (! rk8e->maint)
pdp8->IOFLAGS |= rk8e->ioflag;
[pack start];
}
break ;
}
[rk8e unlockControl];
EXECUTION_TIME (26);
}
void i6743 (void) /* DLAG 6743 */
{
RK8E *rk8e = PLUGIN_POINTER(RK8E);
[rk8e lockControl];
rk8e->wordcount = (rk8e->command & COMMAND_HALF_BLOCK) ? 128 : 0;
RK05 *pack = rk8e->rk05[(rk8e->command >> 1) & 3];
if ((! [pack isWriteProtected] || rk8e->maint) && ! [pack isCalibrating]) {
rk8e->block = ((rk8e->command & 1) << 12) | (pdp8->AC & 07777);
rk8e->crc = rk8e->checkcrc = rk8e->block & 017740;
/* cylinder in 16 bit format 000xxxxxxxx00000*/
}
pdp8->AC &= 010000;
[pack setStatusAndAbortAllCommands];
switch (rk8e->command & 07000) {
case 00000 : /* Read Data */
[pack setRead:YES write:NO all:NO newBlock:rk8e->block];
break;
case 01000 : /* Read All */
[pack setRead:YES write:NO all:YES newBlock:rk8e->block];
break ;
case 02000 : /* Set Write Protect */
[pack setWriteProtected:YES];
break ;
case 03000 : /* Seek Only */
[pack setRead:NO write:NO all:NO newBlock:rk8e->block];
break ;
case 04000 : /* Write Data */
[pack setRead:NO write:YES all:NO newBlock:rk8e->block];
break;
case 05000 : /* Write All */
[pack setRead:NO write:YES all:YES newBlock:rk8e->block];
break;
case 06000 : /* unused */
case 07000 : /* unused */
pdp8->IOFLAGS |= rk8e->ioflag;
rk8e->status |= STATUS_DONE | STATUS_TIMING_ERROR;
break;
}
if ([pack isMounted])
[pack start];
else {
[pack abortAllCommands];
rk8e->status |= STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY | STATUS_ERROR;
pdp8->IOFLAGS |= rk8e->ioflag;
}
[rk8e unlockControl];
EXECUTION_TIME (36);
}
void i6744 (void) /* DLCA 6744 */
{
RK8E *rk8e = PLUGIN_POINTER(RK8E);
[rk8e lockControl];
rk8e->curaddr = pdp8->AC & 07777;
pdp8->AC &= 010000;
if ([rk8e->rk05[(rk8e->command >> 1) & 3] isCalibrating]) {
rk8e->status |= STATUS_CONTROL_BUSY;
pdp8->IOFLAGS |= rk8e->ioflag;
}
[rk8e unlockControl];
EXECUTION_TIME (26);
}
void i6745 (void) /* DRST 6745 */
{
RK8E *rk8e = PLUGIN_POINTER(RK8E);
[rk8e lockControl];
pdp8->AC = (pdp8->AC & 010000) | rk8e->status;
[rk8e unlockControl];
EXECUTION_TIME (36);
}
void i6746 (void) /* DLDC 6746 */
{
RK8E *rk8e = PLUGIN_POINTER(RK8E);
[rk8e lockControl];
rk8e->status = 0;
pdp8->IOFLAGS &= ~rk8e->ioflag;
RK05 *pack = rk8e->rk05[(rk8e->command >> 1) & 3];
if (! rk8e->maint || ! [pack isCalibrating]) {
rk8e->command = pdp8->AC & 07777;
if (rk8e->command & 1)
rk8e->block |= 010000; /* CRC is not affected */
pack = rk8e->rk05[(rk8e->command >> 1) & 3];
}
pdp8->AC &= 010000;
if ([pack isMounted]) {
if ([pack isBusy])
rk8e->status |= STATUS_HEAD_IN_MOTION; /* still seeking */
// detected by Clang: rk8e->status is already 0
// else
// rk8e->status &= ~STATUS_HEAD_IN_MOTION; /* seek already done */
if ((rk8e->command & COMMAND_SET_DONE_ON_SEEK_DONE)) {
if (! [pack isBusy]) {
rk8e->status |= STATUS_DONE;
pdp8->IOFLAGS |= rk8e->ioflag;
}
} else
[pack clearRaiseFlag];
} else {
rk8e->status = STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY;
if ([pack isCalibrating]) {
rk8e->status |= STATUS_CONTROL_BUSY | STATUS_ERROR;
pdp8->IOFLAGS |= rk8e->ioflag;
}
}
if (rk8e->command & COMMAND_INTERRUPT_ON_DONE)
pdp8->IMASK |= rk8e->ioflag;
else
pdp8->IMASK &= ~rk8e->ioflag;
[rk8e unlockControl];
EXECUTION_TIME (36);
}
void i6747 (void) /* DMAN 6747 */
{
RK8E *rk8e = PLUGIN_POINTER(RK8E);
[rk8e lockControl];
RK05 *pack = rk8e->rk05[(rk8e->command >> 1) & 3];
if (pdp8->AC & 04000) {
/* enter maintenance mode */
rk8e->maint = true;
rk8e->shifts = 0;
rk8e->shiftEnabled = false;
if (! (rk8e->status & ~(STATUS_HEAD_IN_MOTION | STATUS_FILE_NOT_READY | STATUS_ERROR)))
pdp8->IOFLAGS &= ~rk8e->ioflag;
}
if (rk8e->maint) {
switch (pdp8->AC & 07760) {
case 02000 :
/* enable to shift to lower data buffer */
rk8e->shiftEnabled = true;
break;
case 01200 :
/* combination of 01000 and 00200 where the bit shifted into lower data
buffer is the logical OR of the bits from CRC and surface & sector */
rk8e->ldb[0] = ((rk8e->block << 11) | (rk8e->ldb[0] >> 1)) & 07777;
rk8e->crc = ((pdp8->AC & 2) << 14) | (rk8e->crc >> 1);
rk8e->block = (rk8e->crc & 017740) | ((rk8e->block >> 1) & 037);
if (++rk8e->shifts == 12 && rk8e->ldbfill == 0) {
rk8e->ldbfill = 1;
rk8e->shifts = 0;
}
break;
case 01000 :
/* shift CRC to lower data buffer and AC10 to CRC */
rk8e->ldb[0] = ((rk8e->crc << 11) | (rk8e->ldb[0] >> 1)) & 07777;
rk8e->crc = ((pdp8->AC & 2) << 14) | (rk8e->crc >> 1);
rk8e->block = (rk8e->crc & 017740) | (rk8e->block & 037);
if (++rk8e->shifts == 12 && rk8e->ldbfill == 0) {
rk8e->ldbfill = 1;
rk8e->shifts = 0;
}
if (! rk8e->shiftEnabled && ! rk8e->ldbfill) {
rk8e->status |= STATUS_DATA_REQUEST_LATE;
pdp8->IOFLAGS |= rk8e->ioflag;
}
if ([pack isCalibrating]) {
rk8e->status |= STATUS_DONE;
pdp8->IOFLAGS |= rk8e->ioflag;
}
break;
case 00400 :
/* shift command register to lower data buffer */
rk8e->ldb[0] = ((rk8e->ldb[0] << 1) | (rk8e->command >> 11)) & 0177777;
rk8e->command = (rk8e->command << 1) & 07777;
rk8e->block &= ~010000;
rk8e->crc &= ~010000;
if (rk8e->command & COMMAND_INTERRUPT_ON_DONE)
pdp8->IMASK |= rk8e->ioflag;
else
pdp8->IMASK &= ~rk8e->ioflag;
if (++rk8e->shifts == 12 && rk8e->ldbfill == 0)
rk8e->ldbfill = 1;
break;
case 00200 :
/* shift surface and sector to lower data buffer */
rk8e->ldb[0] = ((rk8e->block << 11) | (rk8e->ldb[0] >> 1)) & 07777;
rk8e->block = (rk8e->block & 07740) | ((rk8e->block & 037) >> 1);
if (++rk8e->shifts == 12 && rk8e->ldbfill == 0) {
rk8e->ldbfill = 1;
rk8e->shifts = 0;
}
break;
case 00100 :
/* shift AC10 to upper data buffer, buffer should sink in the silo when full */
if (rk8e->ldbfill < 4 && rk8e->wordcount < 256) {
rk8e->udb = ((pdp8->AC & 2) << 10) | (rk8e->udb >> 1);
if (++rk8e->shifts == 12) {
if ((rk8e->command & COMMAND_HALF_BLOCK) && rk8e->wordcount >= 128)
rk8e->udb = 0;
rk8e->ldb[3] = rk8e->ldb[2];
rk8e->ldb[2] = rk8e->ldb[1];
rk8e->ldb[1] = rk8e->ldb[0];
rk8e->ldb[0] = rk8e->udb;
rk8e->ldbfill++;
rk8e->wordcount++;
rk8e->shifts = 0;
}
if (((rk8e->command & COMMAND_HALF_BLOCK) && rk8e->wordcount == 128 &&
rk8e->shifts == 0)
|| (rk8e->wordcount == 255 && rk8e->shifts == 11)) {
rk8e->status |= STATUS_DONE;
pdp8->IOFLAGS |= rk8e->ioflag;
}
} else {
rk8e->status |= STATUS_DATA_REQUEST_LATE;
pdp8->IOFLAGS |= rk8e->ioflag;
}
break;
case 00040 :
/* single cycle data break */
if ((rk8e->command & 07000) == 04000 || (rk8e->command & 07000) == 05000) {
/* write */
if (rk8e->wordcount < 256 && rk8e->ldbfill < 4) {
rk8e->ldb[3] = rk8e->ldb[2];
rk8e->ldb[2] = rk8e->ldb[1];
rk8e->ldb[1] = rk8e->ldb[0];
rk8e->ldb[0] =
pdp8->mem[((rk8e->command & 070) << 9) | rk8e->curaddr];
rk8e->ldbfill++;
rk8e->wordcount++;
}
} else { /* read */
if (((rk8e->command & 070) << 9) < pdp8->_hw.memsize) {
pdp8->mem[((rk8e->command & 070) << 9) | rk8e->curaddr] =
(rk8e->ldbfill > 0) ? rk8e->ldb[--rk8e->ldbfill] : 0;
}
}
rk8e->curaddr = (rk8e->curaddr + 1) & 07777;
break;
case 04020 :
case 00020 :
/* read lower data buffer into AC */
if (rk8e->ldbfill > 0)
pdp8->AC = (pdp8->AC & 010000) | (rk8e->ldb[--rk8e->ldbfill] & 07777);
else
pdp8->AC &= 010000;
break;
}
}
[pack stopCalibrating];
[rk8e unlockControl];
EXECUTION_TIME (46);
}