{File name: IOPMain.mc
Last edited by Jim August 20, 1981 2:20 PM: Fix for new assembler.
Last Edited by Jim Frandeen: March 23, 1981 2:07 PM: Fix bug in WriteSwapped that caused grief when transferring only one word.
Last Edited by Sandman: January 22, 1981 11:32 AM
Last Edited by Roy Ogus: July 8, 1980 12:04 AM
Description: Microcode to implement the IOP-CPport functions.
Author: Roy Ogus,
}

{NOTES:
- Word counter is used. Must be an even number of bytes.
- BYTE ORDER:
normal byte order is low byte, high byte.
-
swapped byte order is high byte, low byte.
- Memory addresses are real.
- The inner loop uses a maximum buffer address as terminator.}

{Register usage:
IOP-Memory address
rhIOP-High memory address
rTmp-Temp accumulator
uBufMax-Maximum buffer address}
Set[IOPTask, 5];
Set[IOPOutMode, 2];
{IOP port output mode}
Set[IOPAWMode, 3];
{IOP port alwaysWU mode}
{ loaded into L7
COMMANDS:
0 - Write Memory Block
1 - Read Memory Block
2 - Do Naked Notify
3 - (unimplemented)
4 - (unimplemented)
5 - Write Swapped Block
6 - Read Swapped Block}
{IOP Task code}

SetTask[IOPTask], StartAddress[IOPIdle];

{Top of the IOP code. The code is started at this point for a new command.
IOP Control should be set to InMode.}

IOPIdle:
CANCELBR[$,0F],c1; {Dispatch}
Xbus ← IOPIData, XDisp,c2;
L7 ← 0, DISP3[IOPCmd],c3;


{**************************************************************************}

{COMMAND 0: Write memory block.
Format of transfer (bytes):
command (2 bits), low addr (10:17), mid. addr (2:9), high addr (0:1),
low count-1 (8:15), high count-1 (0:7),
low data, high data, .....

IOP Control is in InMode}

{return from IOPSub}
rTmp ← rTmp + rIOP,c3, at[0,10,IOPRet];
WFirst:uBufMax ← rTmp, GOTO[WLo2],c1;

WLo:
MAR ← [rhIOP, rIOP], rIOP←rIOP+1,c1;
WLo2:
MDR ← rTmp, rTmp ← IOPIData, LOOPHOLE[mdrok], CANCELBR[$, 0],c2;
rTmp ← rTmp LRot8,c3;

WHiByte:
[] ← rIOP xor uBufMax, ZeroBr,c1;
rTmp ← rTmp or IOPIData, BRANCH[$,WLo3Last],c2;
rTmp ← rTmp LRot8, GOTO[WLo],c3;

{This byte is the last byte. Since we have to do one more click, set AlwaysWakeMode. Have to put in an extra click to get everything done. **Try to fix**. There will be no page crossing, so do the memory reference and then go back to top of the loop.}

WLo3Last:
IOPCtl ← IOPAWMode,c3;

rTmp ← rTmp LRot8,c1;
Noop,c2;
Noop,c3;

WLoLast:
MAR← [rhIOP, rIOP+0],c1;
MDR ← rTmp,c2;
IOPDone:
IOPCtl ← IOPInMode, GOTO [IOPIdle],c3;


{**************************************************************************}

{COMMAND 1: Read memory block.
Format of transfer (bytes):
command (4 bits), low addr (10:17), mid. addr (2:9), high addr (0:1),
low count-1 (8:15), high count (0:7)
=> returns: low data, high data, .....

IOP Control is in InMode}

CReadMem:
rIOP ← IOPIData, CALL[IOPSubc2],c1, at [1,4,IOPCmd];

rTmp ← rTmp + rIOP, IOPCtl ← IOPOutMode,c3, at[1,10,IOPRet];
RLo:MAR ← [rhIOP, rIOP+0], BRANCH[RFirst, RRest],c1;
RFirst:
uBufMax ← rTmp, GOTO[RFetch],c2;
RRest:
GOTO[RFetch],c2;
RFetch:
IOPOData ← rTmp ← MD,c3;

RHigh:
IOPOData ← rTmp LRot8,c1;
[] ← rIOP xor uBufMax, ZeroBr,c2;
rIOP ← rIOP+1, NZeroBr, BRANCH[RLo, RDone],c3;

RDone:
CANCELBR[IOPDonec2,1],c1;



{**************************************************************************}
{COMMAND 2: Do Naked Notify.
Format of command:
command (2 bits), low interrupt mask, high interrupt mask.

IOP Control is in InMode}

{return from IOPSub with mask in rTmp; need to do another click}
IOPCtl ← IOPAWMode,c3, at[2,10,IOPRet];
{OR into wakeup U-register. This must be done in one click.}
rIOP ← uWP, MesaIntRq,c1;
rTmp ← rTmp or rIOP, IOPCtl ← IOPInMode,c2;
uWP ← rTmp, GOTO [IOPIdle],c3;

{**************************************************************************}
{COMMAND 3: (unimplemented)}
Command3:Noop,c1, at[3,10,IOPCmd];
IOPDonec2:
CANCELBR [IOPDone, 2],c2;


{**************************************************************************}
{COMMAND 4: (unimplemented)}
Command4:
IOPDonec1:
GOTO[IOPDonec2],c1, at[4,10,IOPCmd];


{**************************************************************************}
{COMMAND 5: Write Swapped Block}
WriteSwapped:rIOP ← IOPIData, CALL[IOPSubc2],c1, at[5,10,IOPCmd];

rTmp ← rTmp + rIOP,c3, at[5,10,IOPRet];

uBufMax ← rTmp, GOTO[WSHighx],c1;

WSHigh:
rIOP ← rIOP+1, BRANCH[$,WSDone],c1;
WSHighx:
rTmp ← IOPIData, c2;
rTmp ← rTmp LRot8,c3;

WSLo:
MAR ← [rhIOP, rIOP+0],c1;
MDR ← rTmp or IOPIData, CANCELBR[$, 0],c2;
[] ← rIOP xor uBufMax, ZeroBr, GOTO [WSHigh],c3;

WSDone:
GOTO[IOPDone],c2;


{**************************************************************************}
{COMMAND 6: Read Swapped Block}
ReadSwapped:rIOP ← IOPIData, CALL[IOPSubc2],c1, at[6,10,IOPCmd];

rTmp ← rTmp + rIOP, IOPCtl ← IOPOutMode,c3, at[6,10,IOPRet];
RSLo:MAR ← [rhIOP, rIOP+0], BRANCH[RSFirst, RSRest],c1;
RSFirst:
uBufMax ← rTmp, GOTO[RSFetch],c2;
RSRest:
IOPOData ← rTmp LRot0, GOTO[RSFetch],c2;
RSFetch:
rTmp ← MD,c3;

RSHigh:
IOPOData ← rTmp LRot8,c1;
[] ← rIOP xor uBufMax, ZeroBr,c2;
rIOP ← rIOP+1, NZeroBr, BRANCH[RSLo, RSDone],c3;

RSDone:
IOPOData ← rTmp LRot0, CANCELBR[IOPDonec2,1],c1;


{**************************************************************************
Address and count fetching subroutine
**************************************************************************}
{Read the low address (10:17)}
IOPCmd:
IOPSubc1:
rIOP ← IOPIData,c1, at [0,10,IOPCmd];
IOPSubc2:
rIOP ← rIOP LRot8,c2;
Noop,c3;

{Read the middle address (2:9)}
rIOP ← rIOP or IOPIData,c1;
rIOP ← rIOP LRot8,c2;
Noop,c3;

{Read the high address (0:1) into rhIOP}
rhIOP ← IOPIData,c1;
Noop,c2;
Noop,c3;

{Next comes the next parameter. It is count-1 for write and read and mask for naked notify.}

IOPSub2:
rTmp ← IOPIData,c1, at[2,10,IOPCmd];
rTmp ← rTmp LRot8,c2;
Noop,c3;

rTmp ← rTmp or IOPIData, L7Disp,c1;
rTmp ← rTmp LRot8, RET[IOPRet],c2;


{END}