icycle() { int op,a1,a2,x1,x2,i1,i2,setting,setmask,onemask,oldmask; int ecd; /* Error Code */ /* setjmp(svstck) to save stack for return */ /* from possible segment and page faults */ if((ecd=setjmp(svstck)) != 0) { goto except; } ir = pm[cmap(pc)]; pc++; /* extract instruction fields into op, a1, a2; */ /* generate the eff. virtual addresses v1, v2 */ /* using the algorithm in the Reference Manual */ op = extract(ir,24,6); a1 = extract(ir,12,10); a2 = extract(ir,0,10); x1 = extract(ir,22,1); x2 = extract(ir,10,1); i1 = extract(ir,23,1); i2 = extract(ir,11,1); v1 = a1; v2 = a2; /* address field forms initial value */ if (i1 == 1) v1 = pm[dmap(v1)]; /* if indirection, get ind. loc */ if (i2 == 1) v2 = pm[dmap(v2)]; if (x1 == 1) v1 = v1 + xr; /* if indexing specified, add xr */ if (x2 == 1) v2 = v2 + xr; switch(op) { case 1: gr = pm[dmap(v1)]; /* gr load */ break; case 2: pm[dmap(v1)] = gr; /* gr store */ break; case 3: xr = pm[dmap(v1)]; /* xr load */ break; case 4: pm[dmap(v1)] = xr; /* xr store */ break; case 5: sr = pm[dmap(v1)]; /* sr load */ break; case 6: pm[dmap(v1)] = sr; /* sr store */ break; case 8: pm[dmap(v2)] = pm[dmap(v1)]; /* copy */ break; case 9: pm[dmap(v2)] += pm[dmap(v1)]; /* add */ break; case 10: pm[dmap(v2)] -= pm[dmap(v1)]; /* subtract */ break; case 11: pm[dmap(v2)] *= pm[dmap(v1)]; /* multiply */ break; case 12: /* Divide */ if (pm[dmap(v1)] == 0) { ecd = ARITFLT; printf ("\nDivide Fault\n"); goto except; } else pm[dmap(v2)] /= pm[dmap(v1)]; break; case 13: pm[dmap(v2)] &= pm[dmap(v1)]; /* and */ break; case 14: pm[dmap(v2)] |= pm[dmap(v1)]; /* or */ break; case 16: pc = v1; /* go to */ break; case 17: if (pm[dmap(v1)] != pm[dmap(v2)]) pc++; /* if = */ break; case 18: if (pm[dmap(v1)] == pm[dmap(v2)]) pc++; /* if != */ break; case 19: if (pm[dmap(v1)] >= pm[dmap(v2)]) pc++; /* if < */ break; case 20: if (pm[dmap(v1)] < pm[dmap(v2)]) pc++; /* if >= */ break; case 21: xr++; /* loop */ if (xr < pm[dmap(v1)]) pc = v2; break; case 22: sr = pc; pc = v1; /* call */ break; case 23: pc = sr + pm[dmap(v1)]; /* return */ break; case 26: xr = v1; /* xr set */ break; case 27: pm[dmap(v2)] = v1; /* vm set */ break; case 28: pm[dmap(v2)] = extract(pm[dmap(v1 + gr/4)],(gr%4)*8,8); /* get byte */ break; case 29: setting = extract(pm[dmap(v2)],0, 8); /* set byte */ /* Byte want to set in pos with 0s other */ setmask = setting << (gr%4)*8; onemask = 0xFFFFFFFF - (0xFF << (gr%4) * 8); /* mask with ones 'cept 0's in pos. */ oldmask = pm[dmap(v1+(gr/4))] & onemask; /* old value of word with 0's in pos */ pm[dmap(v1+(gr/4))] = oldmask | setmask; /* new word to write to memory */ break; case 31: ; /* noop */ break; case 32: hlt = TRUE; /* halt */ break; case 33: /* error */ hlt = TRUE; /* A1 serves as error code */ printf("\n ERROR: %x\n",a1); break; case 34: /* PmVmCp -- Primary Mem V Mem copy */ if (md < 0) goto illins; pm [dmap(v2)] = pm [v1]; break; case 35: /* VmPmCp */ if (md < 0) goto illins; pm [v2] = pm[dmap(v1)]; break; case 36: /* Arm */ if (md < 0) goto illins; ar |= pm [dmap(v1)]; break; case 37: /* Disarm */ if (md < 0) goto illins; ar &= (-1-pm[dmap(v1)]); break; case 38: /* OS Call */ if (md > 0) goto illins; ie |= EBIT; /* set exception */ pm [sp+PSR_ECD] = a1; /* OS Call Number */ break; case 40: /* Floppy IO */ if (md < 0) goto illins; if (pm[LCL_FCP] < 0) { hlt = TRUE; break; } floppy_io (); break; case 41: /* Disk IO */ if (md < 0) goto illins; if (pm[LCL_DCP] < 0) { hlt = TRUE; break; } disk_io (); break; case 42: /* Print IO */ /* Advance one line and printf pm[v1] */ if (md < 0) goto illins; fprintf (printer,"\t%s\t%8x\n",LP_STR,pm[v1]); fflush(printer); break; case 43: /* Log */ if (md < 0) goto illins; log (v1, v2); break; /* Cases 44 and 45 not written yet */ case 44: /* TTY IN */ if (md < 0) goto illins; break; case 45: /* TTY Out */ if (md < 0) goto illins; break; /*********************************************/ case 48: /* Head Record */ if (moverec(v1,v2,pm[dmap(v1)])) pc++; break; case 49: /* Move Record */ if (moverec (v1, v2, xr)) pc++; break; case 50: /* Insert Record */ if (xr < 0) break; insrec (v1, pm[dmap(v2)], xr); pc++; break; case 51: /* Find Record */ while (((pm[dmap(v1)+1] & pm[dmap(v2)]) != gr) && (pm[dmap(v1)] > 0)) { v1 = pm[dmap(v1)]; } if ((pm[dmap(v1)+1] & pm[dmap(v2)]) == gr) { xr = v1; pc++; } break; case 53: /* Allocate */ if (allocate(v1,v2,gr)) pc++; break; case 54: /* DeAllocate */ if (deallocate(v1,v2,gr)) pc++; break; case 56: /* SP Load */ if (md < 0) goto illins; sp = pm [dmap(v1)]; break; case 57: /* Switch Process */ if (md < 0) goto illins; swcontxt (v1, v2); break; case 60: /* Send Message */ if (md < 0) goto illins; if (pm [LCL_MSF] > 0) send_mesg (); break; case 61: /* Receive Message */ if (md < 0) goto illins; if (pm[dmap(sp + PSR_MSQ)] > 0) recv_mesg (); else { /* reset M bit and switch to scheduler */ pc--; pm[dmap(sp + PSR_STW)] |= MBIT; swcontxt (pm[LCL_SCH], pc); } break; default: hlt = TRUE; /* Unused Op */ break; } /* End Case */ goto realtm ; /* Ready for real time section */ /* Real Time Code */ realtm: pm [LCL_TOD]++; /* Increment Time of Day */ pm [LCL_ALM]++; /* Increment Alarm */ if (pm [LCL_ALM] == 0) ie |= ABIT; /* Set the Alarm */ if (sp > 0) pm [sp+PSR_CPT]++; /* Increment CPU time */ if (fbsyrd) /* Floppy busy? Get 2 wrds */ { /* Read two words */ /* is it pointing to the correct place? */ if (fread (&pm[ftx], WD_B, 2, floppy) != 2) { fbsyrd = 0; pc --; } else { ftx += 2; if (ftx == ftul) { fbsyrd = 0; ie |= FBIT; md &= ~(1<<FBIT); } } } if (dbsyrd) /* Disk Busy Reading ? Get 2 Words */ { recv (dmasock, &pm[dtx], 2*WD_B, 0); dtx += 2; if (dtx == dtul) { dbsyrd = 0; ie |= DBIT; md &= ~(1<<DBIT); } } else if (dbsywr) /* Disk Writing (and not reading) Send 2 words */ { write (dmasock, &pm[dtx], 2*WD_B); dtx += 2; if (dtx == dtul) { dbsywr = 0; ie |= DBIT; md &= ~(1<<DBIT); } } /* Interrupt Handling */ if (ie != 0 && ar < 0) { int intr; int md_sign; int md_val; /* If something else running and this is not a greater one ignore for now */ if ((extract (md,0,WD_L-1) != 0) && (md <= ie)) return; /* Go away */ /* Get sign bit */ md_sign = (extract (md,(WD_L-1),1)) << (WD_L-1) ; /* Get the rightmost interrupt and make sure it can execute */ for (i=0; i< LEV_N; i++) { if ( (intr = (ffs (ie)-1)) != -1) /* Find the int */ if (extract (ar,intr,1)) /* Is it armed? */ { if (sp > 0) /* Set the "return to" value to SP */ pm [LCL_ITV + (2*intr) +1] = sp; else { hlt = TRUE ; break ; } ie &= ~(1<<intr); /* Clear the int */ swcontxt (pm[LCL_ITV+(2*intr)], pc); /* Switch to it */ md = (1 << intr); /* Set mode register */ /* md = ((1<<intr) | md_sign); /* Set mode register */ break; } } } return; /* Illegal instruction */ illins: ecd = INSTFLT; printf ("\n\nIll Ins ECD : %x\n\n", ecd); goto except; /* Exception */ except: ie |= EBIT; printf ("\nException Handler ECD : %x\n", ecd); if (sp > 0) pm [sp+PSR_ECD] = ecd; else hlt = TRUE; return; }
void imsai_fif_out(BYTE data) { static int fdstate = 0; /* state of the fd */ static int fdaddr[16]; /* address of disk descriptors */ static int descno; /* descriptor # */ void disk_io(int); /* * The controller understands these commands: * 0x10: set address of a disk descriptor from the following two out's * 0x00: do the work as setup in the disk descriptor * 0x20: reset a drive to home position, the lower digit contains * the drive to reset, 0x2f for all drives * * The dd address only needs to be set once, the OS then can adjust * the wanted I/O in the descriptor and send the 0x00 command * multiple times for this descriptor. * * The commands 0x10 and 0x00 are OR'ed with a descriptor number * 0x0 - 0xf, so there can be 16 different disk descriptors that * need to be remembered. */ switch (fdstate) { case 0: /* start of command phase */ switch (data & 0xf0) { case 0x00: /* do what disk descriptor says */ descno = data & 0xf; disk_io(fdaddr[descno]); break; case 0x10: /* next 2 is address of disk descriptor */ descno = data & 0xf; fdstate++; break; case 0x20: /* reset drive(s) */ break; /* no mechanical drives, so nothing to do */ default: printf("FIF: unknown cmd %02x\r\n", data); return; } break; case 1: /* LSB of disk descriptor address */ fdaddr[descno] = data; fdstate++; break; case 2: /* MSB of disk descriptor address */ fdaddr[descno] += data << 8; fdstate = 0; break; default: printf("FIF: internal state error\r\n"); cpu_error = IOERROR; cpu_state = STOPPED; break; } }