1 /* vax780_stddev.c: VAX 11/780 standard I/O devices
3 Copyright (c) 1998-2007, Robert M Supnik
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 Except as contained in this notice, the name of Robert M Supnik shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from Robert M Supnik.
32 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock
33 29-Oct-2006 RMS Added clock coscheduler function
34 Synced keyboard to clock for idling
35 11-May-06 RMS Revised timer logic for EVKAE
36 22-Nov-05 RMS Revised for new terminal processing routines
37 10-Mar-05 RMS Fixed bug in timer schedule routine (from Mark Hittinger)
38 08-Sep-04 RMS Cloned from vax_stddev.c, vax_sysdev.c, and pdp11_rx.c
40 The console floppy protocol is based on the description in the 1982 VAX
41 Architecture Reference Manual:
43 TXDB<11:8> = 0 -> normal console output
44 TXDB<11:8> = 1 -> data output to floppy
45 TXDB<11:8> = 3 -> read communications region
46 TXDB<11:8> = 9 -> command output to floppy
47 TXDB<11:8> = F -> flag output (e.g., reboot)
49 RXDB<11:8> = 0 -> normal terminal input
50 RXDB<11:8> = 1 -> data input from floppy
51 RXDB<11:8> = 3 -> communications region data
52 RXDB<11:8> = 2 -> status input from floppy
53 RXDB<11:8> = 9 -> "command" input from floppy (protocol error)
59 /* Terminal definitions */
61 #define RXCS_RD (CSR_DONE + CSR_IE) /* terminal input */
62 #define RXCS_WR (CSR_IE)
63 #define RXDB_ERR 0x8000 /* error */
64 #define RXDB_OVR 0x4000 /* overrun */
65 #define RXDB_FRM 0x2000 /* framing error */
66 #define TXCS_RD (CSR_DONE + CSR_IE) /* terminal output */
67 #define TXCS_WR (CSR_IE)
68 #define TXDB_V_SEL 8 /* unit select */
69 #define TXDB_M_SEL 0xF
70 #define TXDB_FDAT 0x1 /* floppy data */
71 #define TXDB_COMM 0x3 /* console mem read */
72 #define TXDB_FCMD 0x9 /* floppy cmd */
73 #define TXDB_MISC 0xF /* console misc */
74 #define COMM_LNT 0200 /* comm region lnt */
75 #define COMM_MASK (COMM_LNT - 1) /* comm region mask */
76 #define COMM_GH 0144 /* GH flag */
77 #define COMM_WRMS 0145 /* warm start */
78 #define COMM_CLDS 0146 /* cold start */
79 #define COMM_APTL 0147 /* APT load */
80 #define COMM_LAST 0150 /* last position */
81 #define COMM_AUTO 0151 /* auto restart */
82 #define COMM_PCSV 0152 /* PCS version */
83 #define COMM_WCSV 0153 /* WCS version */
84 #define COMM_WCSS 0154 /* WCS secondary */
85 #define COMM_FPLV 0155 /* FPLA version */
86 #define COMM_DATA 0x300 /* comm data return */
87 #define MISC_MASK 0xFF /* console data mask */
88 #define MISC_SWDN 0x1 /* software done */
89 #define MISC_BOOT 0x2 /* reboot */
90 #define MISC_CLWS 0x3 /* clear warm start */
91 #define MISC_CLCS 0x4 /* clear cold start */
92 #define TXDB_SEL (TXDB_M_SEL << TXDB_V_SEL) /* non-terminal */
93 #define TXDB_GETSEL(x) (((x) >> TXDB_V_SEL) & TXDB_M_SEL)
95 /* Clock definitions */
97 #define TMR_CSR_ERR 0x80000000 /* error W1C */
98 #define TMR_CSR_DON 0x00000080 /* done W1C */
99 #define TMR_CSR_IE 0x00000040 /* int enb RW */
100 #define TMR_CSR_SGL 0x00000020 /* single WO */
101 #define TMR_CSR_XFR 0x00000010 /* xfer WO */
102 #define TMR_CSR_RUN 0x00000001 /* run RW */
103 #define TMR_CSR_RD (TMR_CSR_W1C | TMR_CSR_WR)
104 #define TMR_CSR_W1C (TMR_CSR_ERR | TMR_CSR_DON)
105 #define TMR_CSR_WR (TMR_CSR_IE | TMR_CSR_RUN)
106 #define TMR_INC 10000 /* usec/interval */
107 #define CLK_DELAY 5000 /* 100 Hz */
108 #define TMXR_MULT 1 /* 100 Hz */
110 /* Floppy definitions */
112 #define FL_NUMTR 77 /* tracks/disk */
113 #define FL_M_TRACK 0377
114 #define FL_NUMSC 26 /* sectors/track */
115 #define FL_M_SECTOR 0177
116 #define FL_NUMBY 128 /* bytes/sector */
117 #define FL_SIZE (FL_NUMTR * FL_NUMSC * FL_NUMBY) /* bytes/disk */
118 #define UNIT_V_WLK (UNIT_V_UF) /* write locked */
119 #define UNIT_WLK (1u << UNIT_V_UF)
120 #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */
122 #define FL_IDLE 0 /* idle state */
123 #define FL_RWDS 1 /* rw, sect next */
124 #define FL_RWDT 2 /* rw, track next */
125 #define FL_READ 3 /* read */
127 #define FL_WRITE 5 /* write */
129 #define FL_FILL 7 /* fill buffer */
130 #define FL_EMPTY 8 /* empty buffer */
131 #define FL_READSTA 9 /* read status */
132 #define FL_DONE 10 /* cmd done */
134 #define FL_V_FNC 0 /* floppy function */
135 #define FL_M_FNC 0xFF
136 #define FL_FNCRD 0x0 /* read */
137 #define FL_FNCWR 0x1 /* write */
138 #define FL_FNCRS 0x2 /* read status */
139 #define FL_FNCWD 0x3 /* write del data */
140 #define FL_FNCCA 0x4 /* cancel */
141 #define FL_CDATA 0x100 /* returned data */
142 #define FL_CDONE 0x200 /* completion code */
143 #define FL_STACRC 0x001 /* status bits */
144 #define FL_STAPAR 0x002
145 #define FL_STAINC 0x004
146 #define FL_STADDA 0x040
147 #define FL_STAERR 0x080
148 #define FL_CPROT 0x905 /* protocol error */
149 #define FL_GETFNC(x) (((x) >> FL_V_FNC) & FL_M_FNC)
151 #define TRACK u3 /* current track */
152 #define CALC_DA(t,s) (((t) * FL_NUMSC) + ((s) - 1)) * FL_NUMBY
154 int32 tti_csr
= 0; /* control/status */
155 int32 tti_buf
= 0; /* buffer */
156 int32 tti_int
= 0; /* interrupt */
157 int32 tto_csr
= 0; /* control/status */
158 int32 tto_buf
= 0; /* buffer */
159 int32 tto_int
= 0; /* interrupt */
161 int32 tmr_iccs
= 0; /* interval timer csr */
162 uint32 tmr_icr
= 0; /* curr interval */
163 uint32 tmr_nicr
= 0; /* next interval */
164 uint32 tmr_inc
= 0; /* timer increment */
165 int32 tmr_sav
= 0; /* timer save */
166 int32 tmr_int
= 0; /* interrupt */
167 int32 tmr_use_100hz
= 1; /* use 100Hz for timer */
168 int32 clk_tps
= 100; /* ticks/second */
169 int32 tmxr_poll
= CLK_DELAY
* TMXR_MULT
; /* term mux poll */
170 int32 tmr_poll
= CLK_DELAY
; /* pgm timer poll */
171 int32 todr_reg
= 0; /* TODR register */
173 int32 fl_fnc
= 0; /* function */
174 int32 fl_esr
= 0; /* error status */
175 int32 fl_ecode
= 0; /* error code */
176 int32 fl_track
= 0; /* desired track */
177 int32 fl_sector
= 0; /* desired sector */
178 int32 fl_state
= FL_IDLE
; /* controller state */
179 int32 fl_stopioe
= 1; /* stop on error */
180 int32 fl_swait
= 100; /* seek, per track */
181 int32 fl_cwait
= 50; /* command time */
182 int32 fl_xwait
= 20; /* tr set time */
183 uint8 fl_buf
[FL_NUMBY
] = { 0 }; /* sector buffer */
184 int32 fl_bptr
= 0; /* buffer pointer */
186 uint8 comm_region
[COMM_LNT
] = { 0 }; /* comm region */
188 extern int32 sim_switches
;
189 extern jmp_buf save_env
;
191 t_stat
tti_svc (UNIT
*uptr
);
192 t_stat
tto_svc (UNIT
*uptr
);
193 t_stat
clk_svc (UNIT
*uptr
);
194 t_stat
tmr_svc (UNIT
*uptr
);
195 t_stat
tti_reset (DEVICE
*dptr
);
196 t_stat
tto_reset (DEVICE
*dptr
);
197 t_stat
clk_reset (DEVICE
*dptr
);
198 t_stat
tmr_reset (DEVICE
*dptr
);
199 t_stat
fl_svc (UNIT
*uptr
);
200 t_stat
fl_reset (DEVICE
*dptr
);
201 int32
icr_rd (t_bool interp
);
202 void tmr_incr (uint32 inc
);
203 void tmr_sched (void);
204 t_stat
todr_powerup (void);
205 t_stat
fl_wr_txdb (int32 data
);
206 t_bool
fl_test_xfr (UNIT
*uptr
, t_bool wr
);
207 void fl_protocol_error (void);
209 /* TTI data structures
211 tti_dev TTI device descriptor
212 tti_unit TTI unit descriptor
213 tti_reg TTI register list
216 UNIT tti_unit
= { UDATA (&tti_svc
, TT_MODE_8B
, 0), 0 };
219 { HRDATA (RXDB
, tti_buf
, 16) },
220 { HRDATA (RXCS
, tti_csr
, 16) },
221 { FLDATA (INT
, tti_int
, 0) },
222 { FLDATA (DONE
, tti_csr
, CSR_V_DONE
) },
223 { FLDATA (IE
, tti_csr
, CSR_V_IE
) },
224 { DRDATA (POS
, tti_unit
.pos
, T_ADDR_W
), PV_LEFT
},
225 { DRDATA (TIME
, tti_unit
.wait
, 24), PV_LEFT
},
230 { TT_MODE
, TT_MODE_7B
, "7b", "7B", NULL
},
231 { TT_MODE
, TT_MODE_8B
, "8b", "8B", NULL
},
236 "TTI", &tti_unit
, tti_reg
, tti_mod
,
238 NULL
, NULL
, &tti_reset
,
243 /* TTO data structures
245 tto_dev TTO device descriptor
246 tto_unit TTO unit descriptor
247 tto_reg TTO register list
250 UNIT tto_unit
= { UDATA (&tto_svc
, TT_MODE_8B
, 0), SERIAL_OUT_WAIT
};
253 { HRDATA (TXDB
, tto_buf
, 16) },
254 { HRDATA (TXCS
, tto_csr
, 16) },
255 { FLDATA (INT
, tto_int
, 0) },
256 { FLDATA (DONE
, tto_csr
, CSR_V_DONE
) },
257 { FLDATA (IE
, tto_csr
, CSR_V_IE
) },
258 { DRDATA (POS
, tto_unit
.pos
, T_ADDR_W
), PV_LEFT
},
259 { DRDATA (TIME
, tto_unit
.wait
, 24), PV_LEFT
+ REG_NZ
},
264 { TT_MODE
, TT_MODE_7B
, "7b", "7B", NULL
},
265 { TT_MODE
, TT_MODE_8B
, "8b", "8B", NULL
},
266 { TT_MODE
, TT_MODE_7P
, "7p", "7P", NULL
},
271 "TTO", &tto_unit
, tto_reg
, tto_mod
,
273 NULL
, NULL
, &tto_reset
,
278 /* TODR and TMR data structures */
280 UNIT clk_unit
= { UDATA (&clk_svc
, UNIT_IDLE
, 0), CLK_DELAY
}; /* 100Hz */
283 { DRDATA (TODR
, todr_reg
, 32), PV_LEFT
},
284 { DRDATA (TIME
, clk_unit
.wait
, 24), REG_NZ
+ PV_LEFT
},
285 { DRDATA (TPS
, clk_tps
, 8), REG_HIDDEN
+ REG_NZ
+ PV_LEFT
},
290 "TODR", &clk_unit
, clk_reg
, NULL
,
292 NULL
, NULL
, &clk_reset
,
297 UNIT tmr_unit
= { UDATA (&tmr_svc
, 0, 0) }; /* timer */
300 { HRDATA (ICCS
, tmr_iccs
, 32) },
301 { HRDATA (ICR
, tmr_icr
, 32) },
302 { HRDATA (NICR
, tmr_nicr
, 32) },
303 { HRDATA (INCR
, tmr_inc
, 32), REG_HIDDEN
},
304 { HRDATA (SAVE
, tmr_sav
, 32), REG_HIDDEN
},
305 { FLDATA (USE100HZ
, tmr_use_100hz
, 0), REG_HIDDEN
},
306 { FLDATA (INT
, tmr_int
, 0) },
311 "TMR", &tmr_unit
, tmr_reg
, NULL
,
313 NULL
, NULL
, &tmr_reset
,
318 /* RX01 data structures
320 fl_dev RX device descriptor
322 fl_reg RX register list
323 fl_mod RX modifier list
326 UNIT fl_unit
= { UDATA (&fl_svc
,
327 UNIT_FIX
+UNIT_ATTABLE
+UNIT_BUFABLE
+UNIT_MUSTBUF
, FL_SIZE
) };
330 { HRDATA (FNC
, fl_fnc
, 8) },
331 { HRDATA (ES
, fl_esr
, 8) },
332 { HRDATA (ECODE
, fl_ecode
, 8) },
333 { HRDATA (TA
, fl_track
, 8) },
334 { HRDATA (SA
, fl_sector
, 8) },
335 { DRDATA (STATE
, fl_state
, 4), REG_RO
},
336 { DRDATA (BPTR
, fl_bptr
, 7) },
337 { DRDATA (CTIME
, fl_cwait
, 24), PV_LEFT
},
338 { DRDATA (STIME
, fl_swait
, 24), PV_LEFT
},
339 { DRDATA (XTIME
, fl_xwait
, 24), PV_LEFT
},
340 { FLDATA (STOP_IOE
, fl_stopioe
, 0) },
341 { BRDATA (DBUF
, fl_buf
, 16, 8, FL_NUMBY
) },
342 { BRDATA (COMM
, comm_region
, 16, 8, COMM_LNT
) },
347 { UNIT_WLK
, 0, "write enabled", "WRITEENABLED", NULL
},
348 { UNIT_WLK
, UNIT_WLK
, "write locked", "LOCKED", NULL
},
353 "RX", &fl_unit
, fl_reg
, fl_mod
,
354 1, DEV_RDX
, 20, 1, DEV_RDX
, 8,
355 NULL
, NULL
, &fl_reset
,
360 /* Terminal MxPR routines
362 rxcs_rd/wr input control/status
364 txcs_rd/wr output control/status
365 txdb_wr output buffer
370 return (tti_csr
& RXCS_RD
);
373 void rxcs_wr (int32 data
)
375 if ((data
& CSR_IE
) == 0) tto_int
= 0;
376 else if ((tti_csr
& (CSR_DONE
+ CSR_IE
)) == CSR_DONE
)
378 tti_csr
= (tti_csr
& ~RXCS_WR
) | (data
& RXCS_WR
);
384 int32 t
= tti_buf
; /* char + error */
386 tti_csr
= tti_csr
& ~CSR_DONE
; /* clr done */
387 tti_buf
= tti_buf
& BMASK
; /* clr errors */
394 return (tto_csr
& TXCS_RD
);
397 void txcs_wr (int32 data
)
399 if ((data
& CSR_IE
) == 0) tto_int
= 0;
400 else if ((tto_csr
& (CSR_DONE
+ CSR_IE
)) == CSR_DONE
)
402 tto_csr
= (tto_csr
& ~TXCS_WR
) | (data
& TXCS_WR
);
406 void txdb_wr (int32 data
)
408 tto_buf
= data
& WMASK
; /* save data */
409 tto_csr
= tto_csr
& ~CSR_DONE
; /* clear flag */
410 tto_int
= 0; /* clear int */
411 if (tto_buf
& TXDB_SEL
) fl_wr_txdb (tto_buf
); /* floppy? */
412 else sim_activate (&tto_unit
, tto_unit
.wait
); /* no, console */
416 /* Terminal input service (poll for character) */
418 t_stat
tti_svc (UNIT
*uptr
)
422 sim_activate (uptr
, KBD_WAIT (uptr
->wait
, tmr_poll
)); /* continue poll */
423 if ((c
= sim_poll_kbd ()) < SCPE_KFLAG
) return c
; /* no char or error? */
424 if (c
& SCPE_BREAK
) /* break? */
425 tti_buf
= RXDB_ERR
| RXDB_FRM
;
426 else tti_buf
= sim_tt_inpcvt (c
, TT_GET_MODE (uptr
->flags
));
427 uptr
->pos
= uptr
->pos
+ 1;
428 tti_csr
= tti_csr
| CSR_DONE
;
429 if (tti_csr
& CSR_IE
) tti_int
= 1;
433 /* Terminal input reset */
435 t_stat
tti_reset (DEVICE
*dptr
)
440 sim_activate_abs (&tti_unit
, KBD_WAIT (tti_unit
.wait
, tmr_poll
));
444 /* Terminal output service (output character) */
446 t_stat
tto_svc (UNIT
*uptr
)
451 if ((tto_buf
& TXDB_SEL
) == 0) { /* for console? */
452 c
= sim_tt_outcvt (tto_buf
, TT_GET_MODE (uptr
->flags
));
454 if ((r
= sim_putchar_s (c
)) != SCPE_OK
) { /* output; error? */
455 sim_activate (uptr
, uptr
->wait
); /* retry */
456 return ((r
== SCPE_STALL
)? SCPE_OK
: r
); /* !stall? report */
459 uptr
->pos
= uptr
->pos
+ 1;
461 tto_csr
= tto_csr
| CSR_DONE
;
462 if (tto_csr
& CSR_IE
) tto_int
= 1;
466 /* Terminal output reset */
468 t_stat
tto_reset (DEVICE
*dptr
)
473 sim_cancel (&tto_unit
); /* deactivate unit */
477 /* Programmable timer
479 The architected VAX timer, which increments at 1Mhz, cannot be
480 accurately simulated due to the overhead that would be required
481 for 1M clock events per second. Instead, a hidden calibrated
482 100Hz timer is run (because that's what VMS expects), and a
483 hack is used for the interval timer.
485 When the timer is started, the timer interval is inspected.
487 if the interval is >= 10msec, then the 100Hz timer drives the
489 if the interval is < 10mec, then count instructions
491 If the interval register is read, then its value between events
492 is interpolated using the current instruction count versus the
493 count when the most recent event started, the result is scaled
494 to the calibrated system clock, unless the interval being timed
495 is less than a calibrated system clock tick (or the calibrated
496 clock is running very slowly) at which time the result will be
497 the elapsed instruction count.
502 return tmr_iccs
& TMR_CSR_RD
;
505 void iccs_wr (int32 val
)
507 if ((val
& TMR_CSR_RUN
) == 0) { /* clearing run? */
508 sim_cancel (&tmr_unit
); /* cancel timer */
510 if (tmr_iccs
& TMR_CSR_RUN
) /* run 1 -> 0? */
511 tmr_icr
= icr_rd (TRUE
); /* update itr */
513 tmr_iccs
= tmr_iccs
& ~(val
& TMR_CSR_W1C
); /* W1C csr */
514 tmr_iccs
= (tmr_iccs
& ~TMR_CSR_WR
) | /* new r/w */
516 if (val
& TMR_CSR_XFR
) tmr_icr
= tmr_nicr
; /* xfr set? */
517 if (val
& TMR_CSR_RUN
) { /* run? */
518 if (val
& TMR_CSR_XFR
) /* new tir? */
519 sim_cancel (&tmr_unit
); /* stop prev */
520 if (!sim_is_active (&tmr_unit
)) /* not running? */
521 tmr_sched (); /* activate */
523 else if (val
& TMR_CSR_SGL
) { /* single step? */
524 tmr_incr (1); /* incr tmr */
525 if (tmr_icr
== 0) /* if ovflo, */
526 tmr_icr
= tmr_nicr
; /* reload tir */
528 if ((tmr_iccs
& (TMR_CSR_DON
| TMR_CSR_IE
)) != /* update int */
529 (TMR_CSR_DON
| TMR_CSR_IE
)) tmr_int
= 0;
533 int32
icr_rd (t_bool interp
)
537 if (interp
|| (tmr_iccs
& TMR_CSR_RUN
)) { /* interp, running? */
538 delta
= sim_grtime () - tmr_sav
; /* delta inst */
539 if (tmr_use_100hz
&& (tmr_poll
> TMR_INC
)) /* scale large int */
540 delta
= (uint32
) ((((double) delta
) * TMR_INC
) / tmr_poll
);
541 if (delta
>= tmr_inc
) delta
= tmr_inc
- 1;
542 return tmr_icr
+ delta
;
552 void nicr_wr (int32 val
)
557 /* 100Hz base clock unit service */
559 t_stat
clk_svc (UNIT
*uptr
)
561 tmr_poll
= sim_rtcn_calb (clk_tps
, TMR_CLK
); /* calibrate clock */
562 sim_activate (&clk_unit
, tmr_poll
); /* reactivate unit */
563 tmxr_poll
= tmr_poll
* TMXR_MULT
; /* set mux poll */
564 todr_reg
= todr_reg
+ 1; /* incr TODR */
565 if ((tmr_iccs
& TMR_CSR_RUN
) && tmr_use_100hz
) /* timer on, std intvl? */
566 tmr_incr (TMR_INC
); /* do timer service */
570 /* Interval timer unit service */
572 t_stat
tmr_svc (UNIT
*uptr
)
574 tmr_incr (tmr_inc
); /* incr timer */
578 /* Timer increment */
580 void tmr_incr (uint32 inc
)
582 uint32 new_icr
= (tmr_icr
+ inc
) & LMASK
; /* add incr */
584 if (new_icr
< tmr_icr
) { /* ovflo? */
585 tmr_icr
= 0; /* now 0 */
586 if (tmr_iccs
& TMR_CSR_DON
) /* done? set err */
587 tmr_iccs
= tmr_iccs
| TMR_CSR_ERR
;
588 else tmr_iccs
= tmr_iccs
| TMR_CSR_DON
; /* set done */
589 if (tmr_iccs
& TMR_CSR_RUN
) { /* run? */
590 tmr_icr
= tmr_nicr
; /* reload */
591 tmr_sched (); /* reactivate */
593 if (tmr_iccs
& TMR_CSR_IE
) tmr_int
= 1; /* ie? set int req */
597 tmr_icr
= new_icr
; /* no, update icr */
598 if (tmr_iccs
& TMR_CSR_RUN
) /* still running? */
599 tmr_sched (); /* reactivate */
604 /* Timer scheduling */
606 void tmr_sched (void)
608 tmr_sav
= sim_grtime (); /* save intvl base */
609 tmr_inc
= (~tmr_icr
+ 1); /* inc = interval */
610 if (tmr_inc
== 0) tmr_inc
= 1;
611 if (tmr_inc
< TMR_INC
) { /* 100Hz multiple? */
612 sim_activate (&tmr_unit
, tmr_inc
); /* schedule timer */
615 else tmr_use_100hz
= 1; /* let clk handle */
619 /* Clock coscheduling routine */
621 int32
clk_cosched (int32 wait
)
625 t
= sim_is_active (&clk_unit
);
626 return (t
? t
- 1: wait
);
629 /* 100Hz clock reset */
631 t_stat
clk_reset (DEVICE
*dptr
)
633 tmr_poll
= sim_rtcn_init (clk_unit
.wait
, TMR_CLK
); /* init 100Hz timer */
634 sim_activate_abs (&clk_unit
, tmr_poll
); /* activate 100Hz unit */
635 tmxr_poll
= tmr_poll
* TMXR_MULT
; /* set mux poll */
639 /* Interval timer reset */
641 t_stat
tmr_reset (DEVICE
*dptr
)
648 sim_cancel (&tmr_unit
); /* cancel timer */
649 if (sim_switches
& SWMASK ('P')) todr_powerup (); /* powerup? set TODR */
660 void todr_wr (int32 data
)
666 t_stat
todr_powerup (void)
672 curr
= time (NULL
); /* get curr time */
673 if (curr
== (time_t) -1) return SCPE_NOFNC
; /* error? */
674 ctm
= localtime (&curr
); /* decompose */
675 if (ctm
== NULL
) return SCPE_NOFNC
; /* error? */
676 base
= (((((ctm
->tm_yday
* 24) + /* sec since 1-Jan */
677 ctm
->tm_hour
) * 60) +
680 todr_reg
= (base
* 100) + 0x10000000; /* cvt to VAX form */
684 /* Console write, txdb<11:8> != 0 (console unit) */
686 t_stat
fl_wr_txdb (int32 data
)
688 int32 sel
= TXDB_GETSEL (data
); /* get selection */
690 if (sel
== TXDB_FCMD
) { /* floppy command? */
691 fl_fnc
= FL_GETFNC (data
); /* get function */
692 if (fl_state
!= FL_IDLE
) switch (fl_fnc
) { /* cmd in prog? */
694 case FL_FNCCA
: /* cancel? */
695 sim_cancel (&fl_unit
); /* stop op */
699 default: /* all others */
700 fl_protocol_error ();
704 else switch (fl_fnc
) { /* idle, case */
706 case FL_FNCRS
: /* read status */
707 fl_state
= FL_READSTA
;
710 case FL_FNCCA
: /* cancel, nop */
714 case FL_FNCRD
: case FL_FNCWR
: /* data xfer */
716 fl_esr
= 0; /* clear errors */
718 fl_bptr
= 0; /* init buffer */
719 fl_state
= FL_RWDS
; /* sector next */
722 default: /* all others */
723 fl_protocol_error ();
727 sim_activate (&fl_unit
, fl_cwait
); /* sched command */
729 else if (sel
== TXDB_FDAT
) { /* floppy data? */
730 switch (fl_state
) { /* data */
732 case FL_RWDS
: /* expecting sector */
733 fl_sector
= data
& FL_M_SECTOR
;
737 case FL_RWDT
: /* expecting track */
738 fl_track
= data
& FL_M_TRACK
;
739 if (fl_fnc
== FL_FNCRD
) fl_state
= FL_READ
;
740 else fl_state
= FL_FILL
;
743 case FL_FILL
: /* expecting wr data */
744 fl_buf
[fl_bptr
++] = data
& BMASK
;
745 if (fl_bptr
>= FL_NUMBY
) fl_state
= FL_WRITE
;
749 fl_protocol_error ();
753 sim_activate (&fl_unit
, fl_xwait
); /* schedule xfer */
754 } /* end else data */
756 sim_activate (&tto_unit
, tto_unit
.wait
); /* set up timeout */
757 if (sel
== TXDB_COMM
) { /* read comm region? */
758 data
= data
& COMM_MASK
; /* byte to select */
759 tti_buf
= comm_region
[data
] | COMM_DATA
;
760 tti_csr
= tti_csr
| CSR_DONE
; /* set input flag */
761 if (tti_csr
& CSR_IE
) tti_int
= 1;
763 else if (sel
== TXDB_MISC
) { /* misc function? */
764 switch (data
& MISC_MASK
) { /* case on function */
766 comm_region
[COMM_WRMS
] = 0;
768 comm_region
[COMM_CLDS
] = 0;
782 /* Unit service; the action to be taken depends on the transfer state:
784 FL_IDLE Should never get here
785 FL_RWDS Set TXCS<done> (driver sends sector, sets FL_RWDT)
786 FL_RWDT Set TXCS<done> (driver sends track, sets FL_READ/FL_FILL)
787 FL_READ Set TXCS<done>, schedule FL_READ1
788 FL_READ1 Read sector, schedule FL_EMPTY
789 FL_EMPTY Copy data to RXDB, set RXCS<done>
790 if fl_bptr >= max, schedule completion, else continue
791 FL_FILL Set TXCS<done> (driver sends next byte, sets FL_WRITE)
792 FL_WRITE Set TXCS<done>, schedule FL_WRITE1
793 FL_WRITE1 Write sector, schedule FL_DONE
794 FL_DONE Copy requested data to TXDB, set FL_IDLE
797 t_stat
fl_svc (UNIT
*uptr
)
801 int8
*fbuf
= uptr
->filebuf
;
803 switch (fl_state
) { /* case on state */
805 case FL_IDLE
: /* idle */
806 return SCPE_IERR
; /* done */
808 case FL_READ
: case FL_WRITE
: /* read, write */
809 fl_state
= fl_state
+ 1; /* set next state */
810 t
= abs (fl_track
- uptr
->TRACK
); /* # tracks to seek */
811 if (t
== 0) t
= 1; /* minimum 1 */
812 sim_activate (uptr
, fl_swait
* t
); /* schedule seek */
813 /* fall thru, set flag */
814 case FL_RWDS
: case FL_RWDT
: case FL_FILL
: /* rwds, rwdt, fill */
815 tto_csr
= tto_csr
| CSR_DONE
; /* set output done */
816 if (tto_csr
& CSR_IE
) tto_int
= 1;
819 case FL_READ1
: /* read, seek done */
820 if (fl_test_xfr (uptr
, FALSE
)) { /* transfer ok? */
821 da
= CALC_DA (fl_track
, fl_sector
); /* get disk address */
822 for (i
= 0; i
< FL_NUMBY
; i
++) /* copy sector to buf */
823 fl_buf
[i
] = fbuf
[da
+ i
];
824 tti_buf
= fl_esr
| FL_CDONE
; /* completion code */
825 tti_csr
= tti_csr
| CSR_DONE
; /* set input flag */
826 if (tti_csr
& CSR_IE
) tti_int
= 1;
827 fl_state
= FL_EMPTY
; /* go empty */
829 else fl_state
= FL_DONE
; /* error? cmd done */
830 sim_activate (uptr
, fl_xwait
); /* schedule next */
833 case FL_EMPTY
: /* empty buffer */
834 if ((tti_csr
& CSR_DONE
) == 0) { /* prev data taken? */
835 tti_buf
= FL_CDATA
| fl_buf
[fl_bptr
++]; /* get next byte */
836 tti_csr
= tti_csr
| CSR_DONE
; /* set input flag */
837 if (tti_csr
& CSR_IE
) tti_int
= 1;
838 if (fl_bptr
>= FL_NUMBY
) { /* buffer empty? */
839 fl_state
= FL_IDLE
; /* cmd done */
843 sim_activate (uptr
, fl_xwait
); /* schedule next */
846 case FL_WRITE1
: /* write, seek done */
847 if (fl_test_xfr (uptr
, TRUE
)) { /* transfer ok? */
848 da
= CALC_DA (fl_track
, fl_sector
); /* get disk address */
849 for (i
= 0; i
< FL_NUMBY
; i
++) /* copy buf to sector */
850 fbuf
[da
+ i
] = fl_buf
[i
];
852 if (da
> uptr
->hwmark
) uptr
->hwmark
= da
; /* update hwmark */
854 if (fl_fnc
== FL_FNCWD
) fl_esr
|= FL_STADDA
; /* wrdel? set status*/
855 fl_state
= FL_DONE
; /* command done */
856 sim_activate (uptr
, fl_xwait
); /* schedule */
859 case FL_DONE
: /* command done */
860 if (tti_csr
& CSR_DONE
) /* input buf empty? */
861 sim_activate (uptr
, fl_xwait
); /* no, wait */
863 tti_buf
= fl_esr
| FL_CDONE
; /* completion code */
864 tti_csr
= tti_csr
| CSR_DONE
; /* set input flag */
865 if (tti_csr
& CSR_IE
) tti_int
= 1;
866 fl_state
= FL_IDLE
; /* floppy idle */
870 case FL_READSTA
: /* read status */
871 if ((tti_csr
& CSR_DONE
) == 0) { /* input buf empty? */
872 tti_buf
= fl_ecode
; /* return err code */
873 tti_csr
= tti_csr
| CSR_DONE
; /* set input flag */
874 if (tti_csr
& CSR_IE
) tti_int
= 1;
875 fl_state
= FL_DONE
; /* command done */
877 sim_activate (uptr
, fl_xwait
);
883 /* Test for data transfer okay */
885 t_bool
fl_test_xfr (UNIT
*uptr
, t_bool wr
)
887 if ((uptr
->flags
& UNIT_BUF
) == 0) /* not buffered? */
889 else if (fl_track
>= FL_NUMTR
) /* bad track? */
890 fl_ecode
= 0040; /* done, error */
891 else if ((fl_sector
== 0) || (fl_sector
> FL_NUMSC
)) /* bad sect? */
892 fl_ecode
= 0070; /* done, error */
893 else if (wr
&& (uptr
->flags
& UNIT_WPRT
)) /* write and locked? */
894 fl_ecode
= 0100; /* done, error */
896 uptr
->TRACK
= fl_track
; /* now on track */
899 fl_esr
= fl_esr
| FL_STAERR
; /* set error */
903 /* Set protocol error */
905 void fl_protocol_error (void)
907 if ((tto_csr
& CSR_DONE
) == 0) { /* output busy? */
908 tto_csr
= tto_csr
| CSR_DONE
; /* set done */
909 if (tto_csr
& CSR_IE
) tto_int
= 1;
911 if ((tti_csr
& CSR_DONE
) == 0) { /* input idle? */
912 tti_csr
= tti_csr
| CSR_DONE
; /* set done */
913 if (tti_csr
& CSR_IE
) tti_int
= 1;
915 tti_buf
= FL_CPROT
; /* status */
916 fl_state
= FL_IDLE
; /* floppy idle */
922 t_stat
fl_reset (DEVICE
*dptr
)
927 fl_ecode
= 0; /* clear error */
928 fl_sector
= 0; /* clear addr */
930 fl_state
= FL_IDLE
; /* ctrl idle */
932 sim_cancel (&fl_unit
); /* cancel drive */
934 for (i
= 0; i
< COMM_LNT
; i
++) comm_region
[i
] = 0;
935 comm_region
[COMM_FPLV
] = VER_FPLA
;
936 comm_region
[COMM_PCSV
] = VER_PCS
;
937 comm_region
[COMM_WCSV
] = VER_WCSP
;
938 comm_region
[COMM_WCSS
] = VER_WCSS
;
939 comm_region
[COMM_GH
] = 1;