/* LU4_command.c Implement messaging and commands in FLISP LU4 systems */ #include "console.h" #include "lu4.h" #include "flispcontrol.h" void AsynchControl( DATAPATH *dp ); static int Q; static DATAPATH dp; static int inException; unsigned char memory[256]; void setFlispRegisterValue(unsigned char r, unsigned char d) { switch( r ) { case 'a': case 'A': dp.regA.cval = d; break; case 't': case 'T': dp.regT.cval = d; break; case 'x': case 'X': dp.regX.cval = d; break; case 'y': case 'Y': dp.regY.cval = d; break; case 's': case 'S': dp.regSP.cval = d; break; case 'p': case 'P': dp.regPC.cval = d; break; case 'u': case 'U': dp.regTA.cval = d; break; case 'c': case 'C': dp.regCC.cval = d; break; case 'r': case 'R': dp.regR.cval = d; break; case 'i': case 'I': dp.regI.cval = d; break; } } unsigned char getFlispRegisterValue(unsigned char r) { switch( r ) { case 'a': case 'A': return ( dp.regA.cval ); case 't': case 'T': return ( dp.regT.cval ); case 'x': case 'X': return ( dp.regX.cval ); case 'y': case 'Y': return ( dp.regY.cval ); case 's': case 'S': return ( dp.regSP.cval ); case 'p': case 'P': return ( dp.regPC.cval ); case 'u': case 'U': return ( dp.regTA.cval ); case 'c': case 'C': return ( dp.regCC.cval ); case 'r': case 'R': return ( dp.regR.cval ); case 'i': case 'I': return ( dp.regI.cval ); } return 0; } unsigned char translateFlispRegister(unsigned char r) { switch( r ) { case 'a': case 'A': return ( 'A' ); case 't': case 'T': return ( 'T' ); case 'x': case 'X': return ( 'X' ); case 'y': case 'Y': return ( 'Y' ); case 's': case 'S': return ( 'S' ); case 'p': case 'P': return ( 'P' ); case 'u': case 'U': return ( 'U' ); case 'c': case 'C': return ( 'C' ); case 'r': case 'R': return ( 'R' ); case 'i': case 'I': return ( 'I' ); } return 0xFF; } /* NOTE: Version 1.X flags in CC are interpreted as NZVC in LU3 and INVZC in LU4 There is no other quickfix than allow this disqrepancy and posstpone the real fix to version 2.0, therefore, the "1.01"-changes below */ static void updateDatapath( DATAPATH *d ) { /* copy values from internal data structures to LU4 */ unsigned char tmp; setOutDisplay (dp.regA.cval, 1); setOutDisplay (dp.regX.cval, 2); setOutDisplay (dp.regY.cval, 3); setOutDisplay (dp.regSP.cval, 4); setOutDisplay (dp.regPC.cval, 5); tmp = 0; if( d->regCC.cval & 0x10 ) /* IFLAG */ tmp |= 0x10; if( d->regCC.cval & 8 ) /* NFLAG */ tmp |= 8; if( d->regCC.cval & 4 ) /* ZFLAG */ tmp |= 2; // 1.01 change // tmp |= 4; if( d->regCC.cval & 2 ) /* VFLAG */ tmp |= 4; // 1.01 change // tmp |= 2; if( d->regCC.cval & 1 ) /* CFLAG */ tmp |= 1; if ( inException ) { tmp |= 0x80; } outbusLow( tmp ); outbusHigh( tmp ); selectOut( 6 ); updateAddressDisplay( 0 ); updateDataDisplay( 0 ); } void updateAll( void ) { setAutoAddress( dp.regPC.cval ); updateDatapath( &dp ); } void doFlispClk(void) { int i, nfflag; nfflag = dp.nf; /* Set Qstate and I-vectors */ for( i = 0; i < 16; i++ ) dp.Qstate[i] = 0; if( Q < 16 ) dp.Qstate[Q] = 1; for( i = 0; i < 256; i++ ) dp.Istate[i] = 0; dp.Istate[ (int) dp.regI.cval ] = 1; asynchControl( &dp ); /* evaluate AND/OR logic */ asynchDatapath( &dp ); /* do asynch operations */ synchDatapath( &dp ); if( nfflag ) Q = 3; else{ Q++; if( Q > 15) Q = 0; } } void doFlispReset( void ) { /* Do reset sequence */ getMemory( 0xFD, 0 ); /* Will clear any pending interrupt request */ setMemory( 0xFB, 0, 0 ); setMemory( 0xFC, 0, 0 ); Q = 0; inException= 0; doFlispClk(); doFlispClk(); doFlispClk(); dp.memadd = dp.regPC.cval; updateAll(); } static int isExternalOpcode(void) { switch (dp.regI.cval & 0xFF) { case 0x03: case 0x04: case 0xDF: case 0xEF: return 1; } return 0; } static void push( unsigned char val) { dp.regSP.cval--; setMemory( dp.regSP.cval, val, 0 ); } #define I_FLAG 0x10 void doStepInstruction( void ) { char tmp; Q = 3; if( ( ! (dp.regCC.cval & 0x10) ) && isFlispIrq() ) { push( dp.regPC.cval); push( dp.regY.cval); push( dp.regX.cval); push( dp.regA.cval); push( dp.regCC.cval); dp.regCC.cval |= 0x10; /* set I-flag */ dp.regPC.cval = getMemory( 0xFD, 0 ); /* Will clear interrupt request */ dp.memadd = dp.regPC.cval; inException = 1; }else{ tmp = dp.regPC.cval; doFlispClk(); while( Q != 3 ) { doFlispClk(); } if (isExternalOpcode()) { /* Software trap */ asynchControl(&dp); /* evaluate AND/OR logic */ asynchDatapath(&dp); /* do asynch operations */ push(++tmp);; push(dp.regY.cval); push(dp.regX.cval); push(dp.regA.cval); push(dp.regCC.cval); dp.regCC.cval |= I_FLAG; /* set I-flag */ dp.regPC.cval = getMemory(0xFE, &dp); dp.memadd = dp.regPC.cval; inException = 1; asynchControl(&dp); /* evaluate AND/OR logic */ asynchDatapath(&dp); /* do asynch operations */ } if( dp.regI.cval == 0x44 ) /* done RTI instruction */ inException= 0; } updateAll(); } /* Hardware has these bits mixed up, so we has to mirror them... */ static unsigned char mirror( unsigned char in ) { unsigned char res = 0; if(in & 0x80) res |=1; if(in & 0x40) res |=2; if(in & 0x20) res |=4; if(in & 0x10) res |=8; if(in & 0x8) res |=0x10; if(in & 0x4) res |=0x20; if(in & 0x2) res |=0x40; if(in & 0x1) res |=0x80; return res; } void setMemory(unsigned char add, unsigned char data, DATAPATH *dp) { if( add == 0xFB ){ outbusLow( mirror(data) ); selectOut( 14 ); }else if( add == 0xFC ) { outbusLow( mirror(data) ); selectOut( 15 ); }else{ memory[add] = data; } } unsigned char getMemory(unsigned char add, DATAPATH *dp ) { if( add == 0xFB ){ return (mirror( readIn( 3 ) ) ); }else if( add == 0xFC ) { return ( mirror(readIn( 4 ) ) ); }else if( add == 0xFD ){ /* Clear IRQ flipflop */ selectOut( 12 ); /* fall through and return value */ } return memory[add]; }