/***************************************************************************** * Change Log * Date | Change *-----------+----------------------------------------------------------------- * 26-Dec-85 | [1.238] Created * 25-Feb-86 | [1.379] include <> => include "" * 10-Nov-91 | [1.428] converted to Microsoft C 6.0 * 18-Nov-91 | [1.428] memory.h => mem1401.h, avoid ANSI name * 17-Jan-95 | [1.600J] JRJ Implement tape CU instructions *****************************************************************************/ #include #include #include #include "boolean.h" #include "btypes.h" #include "mem1401.h" #include "mach.h" #include "diag.h" #include "instr.h" #include "ifetch.h" #include "alerts.h" #include "alert.h" #include "button.h" #include "color.h" #include "io.h" #include "tape.h" /***************************************************************************** 1401 Simulator Control Unit Instruction Control Unit ------------ Instruction format Mnemonic Op Code A-address d-char -------- ------- --------- ------ CU U %xn d Function: Applies the control function of the d-character to the unit designated by the A-address. Word Marks: Word marks are not affected I-Add A-Add B-Add ----- ----- ----- NSI %xn Bp Chaining: The instruction does not chain *****************************************************************************/ extern boolean CU_illegal(unsigned char d); extern boolean CU_backspace(unsigned char d); extern boolean CU_skip_and_blank(unsigned char d); extern boolean CU_write_tm(unsigned char d); extern boolean CU_rewind(unsigned char d); extern boolean CU_unload(unsigned char d); static boolean (* dcodes[64]) (unsigned char d) = { CU_illegal, /* 0 - sp illegal */ CU_illegal, /* 1 - 1 illegal */ CU_illegal, /* 2 - 2 illegal */ CU_illegal, /* 3 - 3 illegal */ CU_illegal, /* 4 - 4 illegal */ CU_illegal, /* 5 - 5 illegal */ CU_illegal, /* 6 - 6 illegal */ CU_illegal, /* 7 - 7 illegal */ CU_illegal, /* 8 - 8 illegal */ CU_illegal, /* 9 - 9 illegal */ CU_illegal, /* 10 - 0 illegal */ CU_illegal, /* 11 - #/= illegal */ CU_illegal, /* 12 - @/' illegal */ CU_illegal, /* 13 - : illegal */ CU_illegal, /* 14 - > illegal */ CU_illegal, /* 15 - tm illegal */ CU_illegal, /* 16 - b illegal */ CU_illegal, /* 17 - / illegal */ CU_illegal, /* 18 - S illegal */ CU_illegal, /* 19 - T illegal */ CU_unload, /* 20 - U rewind/unload */ CU_illegal, /* 21 - V illegal */ CU_illegal, /* 22 - W illegal */ CU_illegal, /* 23 - X illegal */ CU_illegal, /* 24 - Y illegal */ CU_illegal, /* 25 - Z illegal */ CU_illegal, /* 26 - rm illegal */ CU_illegal, /* 27 - , illegal */ CU_illegal, /* 28 - %/( illegal */ CU_illegal, /* 29 - ws illegal */ CU_illegal, /* 30 - \ illegal */ CU_illegal, /* 31 - seg mk illegal */ CU_illegal, /* 32 - - illegal */ CU_illegal, /* 33 - J illegal */ CU_illegal, /* 34 - K illegal */ CU_illegal, /* 35 - L illegal */ CU_write_tm, /* 36 - M write tape mark */ CU_illegal, /* 37 - N illegal */ CU_illegal, /* 38 - O illegal */ CU_illegal, /* 39 - P illegal */ CU_illegal, /* 40 - Q illegal */ CU_rewind, /* 41 - R rewind */ CU_illegal, /* 42 - ! illegal */ CU_illegal, /* 43 - $ illegal */ CU_illegal, /* 44 - * illegal */ CU_illegal, /* 45 - ] illegal */ CU_illegal, /* 46 - ; illegal */ CU_illegal, /* 47 - loz illegal */ CU_illegal, /* 48 - &/+ illegal */ CU_illegal, /* 49 - A illegal */ CU_backspace, /* 50 - B backspace */ CU_illegal, /* 51 - C illegal */ CU_illegal, /* 52 - D illegal */ CU_skip_and_blank, /* 53- E skip and blank tape */ CU_illegal, /* 54 - F illegal */ CU_illegal, /* 55 - G illegal */ CU_illegal, /* 56 - H illegal */ CU_illegal, /* 57 - I illegal */ CU_illegal, /* 58 - ? illegal */ CU_illegal, /* 59 - . illegal */ CU_illegal, /* 60 - ) illegal */ CU_illegal, /* 61 - [ illegal */ CU_illegal, /* 62 - < illegal */ CU_illegal /* 63 - gm illegal */ }; /**************************************************************************** * inst_CU * Result: boolean * true if operation succeeded * false if operation failed * Effect: * Depends on d character ****************************************************************************/ boolean inst_CU() { boolean status = false; tell_op(op_A|op_d); switch(I_cycle) { /* length dispatch */ case 5: /* Normal */ if(dcodes[d_char] == NULL) { /* Missing d character */ bad_d("No CU dispatch",d_char); alert(alert_process); return(false); } status = (*dcodes[d_char])(d_char); break; default: /* illegal length */ illegal_length(); return false; } /* length dispatch */ single_cycle_state = single_cycle_complete; tell_new_state("CU"); return status; } /***************************************************************************** * CU_illegal * Inputs: * unsigned char d: d-char we have encountered * Result: * false (always) * Effect: * Initiates a process halt becuase of an illegal CU d character *****************************************************************************/ boolean CU_illegal(unsigned char d) { bad_d("CU",d); alert(alert_process); return(false); } /***************************************************************************** * CU_backspace * Inputs: * unsigned char d: d-char we have encountered * Result: * true unless we can't select the tape unit. * Effect: * Initiates a backspace tape record operation *****************************************************************************/ boolean CU_backspace(unsigned char d) { tapedrive *tape = NULL; /* Select tape drive. Quit if that fails (with tape alert set. Because we aren't multitasking, we can't do what a real 1401 would do: just wait */ if((tape = tape_io_select()) == NULL) { return(false); } /* If the tape unit is not ready, return an error. */ if(!tape->loaded || !tape->start.active || tape->file == NULL) { sprintf(diag_buffer,"Tape unit %d Not Ready.\n",tape->unit); tell(diag_buffer); alert(alert_tape); return(false); } /* If at load point, this is a no-op. */ if(ftell(tape->file) == 0L) { return(true); } /* Do the backspace by taking two steps back and one forward until we hit BOT or an IRG or some other error occurs. */ while(true) { /* Take 2 steps back... */ if(fseek(tape->file,-2L,SEEK_CUR) != 0) { sprintf(diag_buffer, "Tape unit %d backspace %s error (seek).\n", strerror(errno),tape->unit); tell(diag_buffer); alert(alert_tape); return(false); } /* Check for BOT */ if(ftell(tape->file) == 0L) { tape->at_irg = false; tape->indicate.active = false; return(true); } /* Take one step forward. If EOF, we are all done. It really shouldn't happen! (A REAL SHORT REEL). */ if(fread(&(tape->buff),1,1,tape->file) != 1) { if(!feof(tape->file)) { sprintf(diag_buffer, "Tape unit %d backspace %s error. (read)\n", strerror(errno),tape->unit); tell(diag_buffer); alert(alert_tape); return(false); } tape->indicate.active = true; return(true); } /* Check the byte for an IRG. In which case we're done. */ if(tape->buff & TAPE_IRG) { tape->buff &= (~TAPE_IRG); tape->indicate.active = false; tape->at_irg = true; return(true); } } } /***************************************************************************** * CU_skip_and_blank * Inputs: * unsigned char d: d-char we have encountered * Result: * true (always) * Effect: * Initiates a skip and blank tape operation, which, because PC output * tapes have no bad spots, does absolutely nothing. *****************************************************************************/ boolean CU_skip_and_blank(unsigned char d) { return(true); } /***************************************************************************** * CU_write_tm * Inputs: * unsigned char d: d-char we have encountered * Result: * true unless some PC write error occurs on output. * Effect: * Initiates a write tape mark operation *****************************************************************************/ boolean CU_write_tm(unsigned char d) { tapedrive *tape = NULL; /* Select tape drive. Quite if that fails (with tape alert set. Because we aren't multitasking, we can't wait like a real 1401 would. */ if((tape = tape_io_select()) == NULL) { return(false); } /* If the tape unit is not ready or is RO, return an error. */ if(!tape->loaded || !tape->start.active || tape->file == NULL) { sprintf(diag_buffer,"Tape unit %d Not Ready.\n",tape->unit); tell(diag_buffer); alert(alert_tape); return(false); } /* If tape is Read Only, set transfer error and return. */ if(tape->readonly) { tape_transfer_error = true; alert(alert_tape); return(true); } /* Write out the Tape Mark. */ tape->buff = BCD_TM | TAPE_IRG; tape_transfer_error = false; tape->indicate.active = false; tape->at_irg = false; tape_io_char_write(tape); return(true); } /***************************************************************************** * CU_rewind * Inputs: * unsigned char d: d-char we have encountered * Result: * true unless an error occurs. * Effect: * Initiates a rewind tape operation *****************************************************************************/ boolean CU_rewind(unsigned char d) { tapedrive *tape = NULL; /* Select tape drive. Quit if that fails, with an error. (Normally, a real 1401 would just wait, but we can't). */ if((tape = tape_io_select()) == NULL) { return(false); } /* If the tape unit is not ready, return an error. */ if(!tape->loaded || !tape->start.active || tape->file == NULL) { sprintf(diag_buffer,"Tape unit %d Not Ready.\n",tape->unit); tell(diag_buffer); alert(alert_tape); return(false); } /* Rewind! */ if(fseek(tape->file,0L,SEEK_SET) != 0) { sprintf(diag_buffer,"Tape unit %d rewind % error (seek).\n", strerror(errno),tape->unit); tell(diag_buffer); alert(alert_tape); return(false); } tape->indicate.active = 0; tape_transfer_error = 0; tape->at_irg = false; return(true); } /***************************************************************************** * CU_unload * Inputs: * unsigned char d: d-char we have encountered * Result: * true, unless an error occurs. * Effect: * Initiates a rewind and unload tape operation *****************************************************************************/ boolean CU_unload(unsigned char d) { tapedrive *tape = NULL; /* Select tape drive. Quit if that fails, with an error. (Normally, a real 1401 would just wait, but we can't). */ if((tape = tape_io_select()) == NULL) { return(false); } /* If the tape unit is not ready, return an error. */ if(!tape->loaded || !tape->start.active || tape->file == NULL) { sprintf(diag_buffer,"Tape unit %d Not Ready.\n",tape->unit); tell(diag_buffer); alert(alert_tape); return(false); } /* Do the rewind and unload operation. If it failed, we snapped the tape! In which case, we still continue on. */ tape_transfer_error = false; if(fclose(tape->file) != 0) { sprintf(diag_buffer,"Tape SNAPPED (close error %s) unit %d.\n", strerror(errno),tape->unit); tape_transfer_error = true; tell(diag_buffer); alert(alert_tape); } tape->file = NULL; tape->loaded = false; tape->readonly = false; tape->indicate.border = COLOR_GREEN; tape->indicate.active = false; tape->start.active = false; tape->at_irg = false; return(true); }