/* LU3_command.c Implement messaging and commands in FLISP LU3 systems 2012-10-19 Started RoJ 2012-12-13 BETA-version RoJ */ #include "lu3.h" void AsynchControl( DATAPATH *dp ); unsigned char Qstate[16]; unsigned char Istate[256]; static CMD cmdbuf[MAX_CMD_BUF]; static int Q; static DATAPATH dp; static unsigned char cmd_in, cmd_out; void initCmd(void) { cmd_in = 0; cmd_out = 0; } void putCmd( PCMD p ) { unsigned char t; t = (cmd_in+1)% MAX_CMD_BUF; if(t == cmd_out) return; /* commad buffer overflow */ else { cmd_in=t; cmdbuf[cmd_in].message = p->message; cmdbuf[cmd_in].p1 = p->p1; cmdbuf[cmd_in].p2 = p->p2; } } PCMD getCmd( void ) { if(cmd_in == cmd_out) return (PCMD) 0; else { cmd_out=(cmd_out + 1)% MAX_CMD_BUF; return( & cmdbuf[cmd_out] ); } } 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; } static void refreshDatapath( DATAPATH *d ) { /* copy control signals from LU3-SE to internal data structures */ unsigned char tmp; d->regT.clrenab = 0; /* always, cannot be used by external logic */ tmp = readIn( 3 ); if( tmp & 1) d->regA.ldenab = 1; else d->regA.ldenab = 0; if( tmp & 2) d->regT.ldenab = 1; else d->regT.ldenab = 0; if( tmp & 4) d->nf = 1; else d->nf = 0; if( tmp & 8) d->regX.ldenab = 1; else d->regX.ldenab = 0; if( tmp & 0x10) d->regY.ldenab = 1; else d->regY.ldenab = 0; if( tmp & 0x20) d->regSP.ldenab = 1; else d->regSP.ldenab = 0; if( tmp & 0x40) d->regSP.incenab = 1; else d->regSP.incenab = 0; if( tmp & 0x80) d->regSP.decenab = 1; else d->regSP.decenab = 0; tmp = readIn( 4 ); if( tmp & 1) d->regPC.ldenab = 1; else d->regPC.ldenab = 0; if( tmp & 2) d->regPC.incenab = 1; else d->regPC.incenab = 0; if( tmp & 4) d->regTA.ldenab = 1; else d->regTA.ldenab = 0; if( tmp & 8) d->regR.ldenab = 1; else d->regR.ldenab = 0; if( tmp & 0x10) d->regCC.ldenab = 1; else d->regCC.ldenab = 0; if( tmp & 0x20) d->regI.ldenab = 1; else d->regI.ldenab = 0; if( tmp & 0x40) d->mainmem.mw = 1; else d->mainmem.mw = 0; if( tmp & 0x80) d->mainmem.mr = 1; else d->mainmem.mr = 0; tmp = readIn( 5 ); if( tmp & 1) d->alu.f0 = 1; else d->alu.f0 = 0; if( tmp & 2) d->alu.f1 = 1; else d->alu.f1 = 0; if( tmp & 4) d->alu.f2 = 1; else d->alu.f2 = 0; if( tmp & 8) d->alu.f3 = 1; else d->alu.f3 = 0; if( tmp & 0x10) d->mux.g14 = 1; else d->mux.g14 = 0; if( tmp & 0x20) d->mux.g13 = 1; else d->mux.g13 = 0; if( tmp & 0x40) d->mux.g12 = 1; else d->mux.g12 = 0; if( tmp & 0x80) d->mux.g9 = 1; else d->mux.g9 = 0; tmp = readIn( 6 ); if( tmp & 1) d->mux.g8 = 1; else d->mux.g8 = 0; if( tmp & 2) d->mux.g7 = 1; else d->mux.g7 = 0; if( tmp & 4) d->mux.g6 = 1; else d->mux.g6 = 0; if( tmp & 8) d->mux.g5 = 1; else d->mux.g5 = 0; if( tmp & 0x10) d->mux.g4 = 1; else d->mux.g4 = 0; if( tmp & 0x20) d->mux.g3 = 1; else d->mux.g3 = 0; if( tmp & 0x40) d->mux.g2 = 1; else d->mux.g2 = 0; if( tmp & 0x80) d->mux.g1 = 1; else d->mux.g1 = 0; tmp = readIn( 7 ); if( tmp & 1) d->regA.oeenab = 1; else d->regA.oeenab = 0; if( tmp & 2) d->regR.oeenab = 1; else d->regR.oeenab = 0; if( tmp & 4) d->regCC.oeenab = 1; else d->regCC.oeenab = 0; if( tmp & 8) d->regX.oeenab = 1; else d->regX.oeenab = 0; if( tmp & 0x10) d->regY.oeenab = 1; else d->regY.oeenab = 0; if( tmp & 0x20) d->regSP.oeenab = 1; else d->regSP.oeenab = 0; if( tmp & 0x40) d->regSP.oeenab = 1; else d->regSP.oeenab = 0; if( tmp & 0x80) d->mux.g0 = 1; else d->mux.g0 = 0; } static unsigned char regprint( unsigned char c ) { unsigned char val=0; if( c & 1) val |= 0x80; if( c & 2) val |= 0x40; if( c & 4) val |= 0x20; if( c & 8) val |= 0x10; if( c & 0x10) val |= 8; if( c & 0x20) val |= 4; if( c & 0x40) val |= 2; if( c & 0x80) val |= 1; return val; } static void updateDatapath( DATAPATH *d ) { /* copy cotrol signals from internal data structures to LU3-DV */ unsigned char tmp; unsigned short q; int i; outbusHigh( regprint(dp.regA.cval) ); outbusLow( regprint(dp.regT.cval) ); selectOut( 1 ); outbusHigh( regprint(dp.regX.cval) ); outbusLow( regprint(dp.regY.cval) ); selectOut( 2 ); outbusHigh( regprint(dp.regSP.cval) ); outbusLow( regprint(dp.regPC.cval) ); selectOut( 3 ); outbusHigh( regprint(dp.alu.Dval) ); outbusLow( regprint(dp.alu.Uval) ); selectOut( 4 ); outbusHigh( regprint(dp.regR.cval) ); outbusLow( regprint(dp.regTA.cval) ); selectOut( 5 ); outbusHigh( regprint(dp.regI.cval )); outbusLow( regprint(dp.regCC.cval )); selectOut( 6 ); tmp = 0; if( d->regA.ldenab) tmp |= 1; if( d->regT.ldenab) tmp |= 2; if( d->regT.clrenab) tmp |= 4; if( d->regX.ldenab) tmp |= 8; if( d->regY.ldenab) tmp |= 0x10; if( d->regSP.ldenab) tmp |= 0x20; if( d->regSP.incenab) tmp |= 0x40; if( d->regSP.decenab) tmp |= 0x80; outbusHigh( tmp ); tmp = 0; if( d->regPC.ldenab) tmp |= 1; if( d->regPC.incenab) tmp |= 2; if( d->regTA.ldenab) tmp |= 4; if( d->regR.ldenab) tmp |= 8; if( d->regCC.ldenab) tmp |= 0x10; if( d->regI.ldenab) tmp |= 0x20; if( d->mainmem.mw ) tmp |= 0x40; if( d->mainmem.mr ) tmp |= 0x80; outbusLow( tmp ); selectOut( 7 ); tmp = 0; if( d->alu.f0 ) tmp |= 1; if( d->alu.f1 ) tmp |= 2; if( d->alu.f2 ) tmp |= 4; if( d->alu.f3 ) tmp |= 8; if( d->mux.g14 ) tmp |= 0x10; if( d->mux.g13 ) tmp |= 0x20; if( d->mux.g12 ) tmp |= 0x40; if( d->mux.g9 ) tmp |= 0x80; outbusHigh( tmp ); tmp = 0; if( d->mux.g8 ) tmp |= 1; if( d->mux.g7 ) tmp |= 2; if( d->mux.g6 ) tmp |= 4; if( d->mux.g5 ) tmp |= 8; if( d->mux.g4 ) tmp |= 0x10; if( d->mux.g3 ) tmp |= 0x20; if( d->mux.g2 ) tmp |= 0x40; if( d->mux.g1 ) tmp |= 0x80; outbusLow( tmp ); selectOut( 8 ); tmp = 0; if( d->regA.oeenab ) tmp |= 1; if( d->regR.oeenab ) tmp |= 2; if( d->regCC.oeenab ) tmp |= 4; if( d->regX.oeenab ) tmp |= 8; if( d->regY.oeenab ) tmp |= 0x10; if( d->regSP.oeenab ) tmp |= 0x20; if( d->regPC.oeenab ) tmp |= 0x40; if( d->mux.g0 ) tmp |= 0x80; outbusLow( tmp ); selectOut( 9 ); switch( Q ) { case 0: q = 0x100; break; case 1: q = 0x200; break; case 2: q = 0x400; break; case 3: q = 0x800; break; case 4: q = 0x1000; break; case 5: q = 0x2000; break; case 6: q = 0x4000; break; case 7: q = 0x8000; break; case 8: q = 1; break; case 9: q = 2; break; case 10: q = 4; break; case 11: q = 8; break; case 12: q = 0x10; break; case 13: q = 0x20; break; case 14: q = 0x40; break; case 15: q = 0x80; break; } outbusHigh( (q >> 8) ); outbusLow( q & 0xFF ); selectOut( 10 ); tmp = 0; if( d->regI.cval == 0x03 ) tmp |= 1; else if( d->regI.cval == 0x04 ) tmp |= 2; else if( d->regI.cval == 0xDF ) tmp |= 4; else if( d->regI.cval == 0xEF ) tmp |= 8; if( d->regCC.cval & 8 ) tmp |= 0x10; if( d->regCC.cval & 4 ) tmp |= 0x20; if( d->regCC.cval & 2 ) tmp |= 0x40; if( d->regCC.cval & 1 ) tmp |= 0x80; outbusHigh( tmp ); selectOut( 11 ); if( Q < 8) { outbusLow( 0 ); /* clears Q8-Q15 */ tmp = 1; for( i = 0; i < 8; i++ ) { if (Qstate[i]){ outbusHigh( tmp ); break; } tmp = tmp << 1; } }else{ outbusHigh( 0 ); /* clears Q0-Q7 */ tmp = 1; for( i = 8; i < 16; i++ ) { if (Qstate[i]){ outbusLow( tmp ); break; } tmp = tmp << 1; } } selectOut(10); updateAddressDisplay( 0 ); updateDataDisplay( 0 ); } static void synchDatapath(DATAPATH *d){ // a CLOCK signal has occured... unsigned char c; // Take care of INC and CLEAR Signals, LOAD-s will override... if(d->regSP.incenab) d->regSP.cval = d->regSP.cval+1; else if(d->regSP.decenab) d->regSP.cval = d->regSP.cval-1; if(d->regPC.incenab) d->regPC.cval = d->regPC.cval+1; if(d->regT.ldenab) d->regT.cval = d->busval; if(d->regT.clrenab) d->regT.cval = 0; if(d->regA.ldenab) d->regA.cval = d->busval; if(d->regY.ldenab) d->regY.cval = d->busval; if(d->regX.ldenab) d->regX.cval = d->busval; if(d->regPC.ldenab) d->regPC.cval = d->busval; if(d->regSP.ldenab) d->regSP.cval = d->busval; if(d->regTA.ldenab) d->regTA.cval = d->busval; if(d->regI.ldenab) d->regI.cval = d->busval; if(d->regR.ldenab) d->regR.cval = d->alu.Uval; // Evaluate tentative input for CC register if(d->regCC.ldenab){ /* Evaluate g11-g2 */ c = 0; if( d->mux.g11 ) c = 2; if( d->mux.g10) c |=1; switch ( c ) /* I flag */ { case 0: d->regCC.cval &= ~0x10; break; /* clear I flag */ case 1: if ( d->busval & 0x10 ) d->regCC.cval |= 0x10; else d->regCC.cval &= ~0x10; break; /* b4 */ case 2: d->regCC.cval |= 0x10; break; /* set I flag */ case 3: break; /* no change */ } c = 0; if( d->mux.g9 ) c = 2; if( d->mux.g8 ) c |=1; switch ( c ) { case 0: d->regCC.cval &= ~0x8; d->regCC.cval |= ( d->alu.flags & 0x8 ); break; /* ALU(N) */ case 1: if ( d->busval & 8 ) d->regCC.cval |= 8; else d->regCC.cval &= ~8; break; /* b3 */ case 2: d->regCC.cval &= ~8; break; /* clear N flag */ case 3: break; /* no change */ } c = 0; if( d->mux.g7 ) c = 2; if( d->mux.g6 ) c |=1; switch ( c ) { case 0: d->regCC.cval &= ~0x4; d->regCC.cval |= ( d->alu.flags & 0x4 ); break; /* ALU(Z) */ case 1: if ( d->busval & 4 ) d->regCC.cval |= 4; else d->regCC.cval &= ~4; break; /* b2 */ case 2: d->regCC.cval &= ~0x4; break; /* clear Z flag */ case 3: break; /* no change */ } c = 0; if( d->mux.g5 ) c = 2; if( d->mux.g4 ) c |=1; switch ( c ) { case 0: d->regCC.cval &= ~0x2; d->regCC.cval |= ( d->alu.flags & 0x2 ); break; /* ALU(V) */ case 1: if ( d->busval & 2 ) d->regCC.cval |= 2; else d->regCC.cval &= ~2; break; /* b1 */ case 2: d->regCC.cval &= ~0x2; break; /* clear V flag */ case 3: break; /* no change */ } c = 0; if( d->mux.g3 ) c = 2; if( d->mux.g2 ) c |=1; switch ( c ) { case 0: d->regCC.cval &= ~0x1; d->regCC.cval |= ( d->alu.flags & 0x1 ); break; /* ALU(C) */ case 1: if ( d->busval & 1 ) d->regCC.cval |= 1; else d->regCC.cval &= ~1; break; /* b0 */ case 2: d->regCC.cval &= ~0x1; break; /* clear C flag */ case 3: break; /* no change */ } } // ALU supplied from regT d->alu.Eval = d->regT.cval; // Clock into memory... if(d->mainmem.mw){ setMemory(d->memadd, d->busval); } } static void asynchDatapath( DATAPATH *dp ) { int tsum,arop,vout,cout; int c; unsigned char v; /* refresh the bus value */ c=0;v=0; if(dp->regA.oeenab){ v = v | dp->regA.cval; c++; } if(dp->regY.oeenab){ v = v | dp->regY.cval; c++; } if(dp->regR.oeenab){ v = v | dp->regR.cval; c++; } if(dp->regX.oeenab){ v = v | dp->regX.cval; c++; } if(dp->regSP.oeenab){ v = v | dp->regSP.cval; c++; } if(dp->regPC.oeenab){ v = v | dp->regPC.cval; c++; } if(dp->regCC.oeenab){ v = v | dp->regCC.cval; c++; } //p->adress_register_offset.value=0; //// Evaluate input for address select mux if( dp->mux.g14 ) { dp->memadd = dp->regTA.cval; } else{ if( dp->mux.g13 && dp->mux.g12 ) { // 11 dp->memadd = dp->regX.cval + dp->regT.cval; // p->adress_register_offset.value=dp->regT.cval; }else if( dp->mux.g13 && (! dp->mux.g12) ) { // 10 dp->memadd = dp->regY.cval + dp->regT.cval; // p->adress_register_offset.value=dp->regT.cval; }else if( ( ! dp->mux.g13) && dp->mux.g12 ) { // 01 dp->memadd = dp->regSP.cval + dp->regT.cval; // p->adress_register_offset.value=dp->regT.cval; }else{ // 00 dp->memadd = dp->regPC.cval ; // No offset for PC } } if(dp->mainmem.mr){ v = v | getMemory(dp->memadd ); c++; } if(c == 0){ v = (unsigned char) 0xFF; } dp->busval = v; // ALU input from BUS... dp->alu.Dval = dp->busval; // ALU input from regT dp->alu.Eval = dp->regT.cval; // ALU input Cin (g1 and g0 signals ) if( (!dp->mux.g1) && (!dp->mux.g0)){ dp->alu.cin = 0; }else if( (!dp->mux.g1) && dp->mux.g0){ dp->alu.cin = 1; }else if( dp->mux.g1 && (!dp->mux.g0) ){ // C-flag from CC dp->alu.cin = dp->regCC.cval & 1; }else{ // C-flag complement if( dp->regCC.cval & 1 ) dp->alu.cin = 0; else dp->alu.cin = 1; } // Perform ALU-operation arop = 0; cout = 0; vout = 0; dp->alu.func = dp->alu.f0; dp->alu.func |= (dp->alu.f1 << 1); dp->alu.func |= (dp->alu.f2 << 2); dp->alu.func |= (dp->alu.f3 << 3); switch (dp->alu.func){ case 0: dp->alu.Uval = 0; break; case 1: dp->alu.Uval =(char)0xFD; break; case 2: dp->alu.Uval =(char)0xFE; break; case 3: dp->alu.Uval =(char)0xFF; break; case 4: dp->alu.Uval = dp->alu.Eval; break; case 5: dp->alu.Uval = (~dp->alu.Dval)+dp->alu.cin; if(dp->alu.Dval==0x80)vout =1; else vout=0; if(dp->alu.Dval==0)cout =0; else cout=1; break; break; case 6: dp->alu.Uval = dp->alu.Dval | dp->alu.Eval; break; case 7: dp->alu.Uval = dp->alu.Dval & dp->alu.Eval; break; case 8: dp->alu.Uval = dp->alu.Dval ^ dp->alu.Eval; break; case 9: tsum = dp->alu.Dval + dp->alu.cin; arop++; break; case 10: tsum = dp->alu.Dval+0xFF; arop++; break; case 11: tsum = dp->alu.Dval+dp->alu.Eval+dp->alu.cin; arop++; break; case 12: tsum = dp->alu.Dval + (~(dp->alu.Eval+ dp->alu.cin)+1); arop++; break; case 13: // shift left operation: dp->alu.Uval = (dp->alu.Dval << 1) + dp->alu.cin; if( dp->alu.Dval & 0x80 ) cout = 1; if( (cout && ((dp->alu.Uval & 0x80) == 0)) || ((dp->alu.Uval & 0x80) && cout==0)) vout = 1 ; break; case 14: // shift right operation: dp->alu.Uval = (dp->alu.Dval >> 1) ; if( dp->alu.cin ) dp->alu.Uval |= 0x80; if( dp->alu.Dval & 1 ) cout = 1; if( (cout && ((dp->alu.Uval & 0x80) == 0)) || ((dp->alu.Uval & 0x80) && cout==0)) vout = 1 ; break; case 15: // arithmetic shift right operation: dp->alu.Uval = (dp->alu.Dval >> 1) ; if( dp->alu.Dval & 0x80 ) dp->alu.Uval |= 0x80; if( dp->alu.Dval & 1 ) cout = 1; if( (cout && ((dp->alu.Uval & 0x80) == 0)) || ((dp->alu.Uval & 0x80) && cout==0)) vout = 1 ; break; } if(arop){ // handle Cout and Vout dp->alu.Uval = (unsigned char) tsum; // check carry out if( tsum & 0x100 ) cout = 1; // check Vout if(dp->alu.func==12){ // subtraction if (( ( dp->alu.Dval & 0x80) && ((~dp->alu.Eval) & 0x80) && ( !(dp->alu.Uval & 0x80)) )|| ( (!(dp->alu.Dval & 0x80)) && (!((~dp->alu.Eval) & 0x80)) && ( dp->alu.Uval & 0x80) ) ) vout = 1; }else{ if (( ( dp->alu.Dval & 0x80) && (dp->alu.Eval & 0x80) && ( !(dp->alu.Uval & 0x80)) )|| ( (!(dp->alu.Dval & 0x80)) && (!(dp->alu.Eval & 0x80)) && ( dp->alu.Uval & 0x80) ) ) vout = 1; } } dp->alu.flags = 0; if( dp->alu.Uval & 0x80 ) dp->alu.flags |= 8; if( dp->alu.Uval == 0) dp->alu.flags |= 4; if(cout) dp->alu.flags |= 1; if (vout) dp->alu.flags |= 2; } int isExternalOpcode( void ) { return ((Q>3)&&( ( dp.regI.cval == 0x03 )||( dp.regI.cval == 0x04 )||( dp.regI.cval == 0xDF )||( dp.regI.cval == 0xEF ))); } void doExternalOpcode( void ) { /* Called from main loop */ refreshDatapath( &dp ); /* read logic from external board */ asynchDatapath( &dp ); /* do asynch operations */ updateDatapath( &dp ); } void updateAll( void ) { int i; char external_opcode; dp.irq = 0; /* always */ external_opcode = isExternalOpcode(); /* Set Qstate and I-vectors */ for( i = 0; i < 16; i++ ) Qstate[i] = 0; if( Q < 16 ) Qstate[Q] = 1; for( i = 0; i < 256; i++ ) Istate[i] = 0; Istate[ (int) dp.regI.cval ] = 1; if( external_opcode ){ refreshDatapath( &dp ); /* read logic frpm external board */ }else{ AsynchControl( &dp ); /* evaluate AND/OR logic */ } asynchDatapath( &dp ); /* do asynch operations */ setAutoAddress( dp.memadd ); updateDatapath( &dp ); } void doFlispReset( void ) { Q = 0; updateAll(); } void doFlispNF( void ) { Q = 3; updateAll(); } void doFlispClk(void) { int nfflag; nfflag = dp.nf; synchDatapath( &dp ); if( nfflag ) Q = 3; else{ Q++; if( Q > 15) Q = 0; } updateAll(); }