384 lines
11 KiB
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);
|
|
}
|