1 /* id_uvc.c: Interdata universal clock
3 Copyright (c) 2001-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.
26 pic precision incremental clock
27 lfc line frequency clock
29 18-Jun-07 RMS Added UNIT_IDLE flag
30 18-Oct-06 RMS Changed LFC to be free running, export tmr_poll
31 23-Jul-05 RMS Fixed {} error in OC
32 01-Mar-03 RMS Added SET/SHOW LFC FREQ support
33 Changed precision clock algorithm for V7 UNIX
39 /* Device definitions */
41 #define UNIT_V_DIAG (UNIT_V_UF + 0) /* diag mode */
42 #define UNIT_DIAG (1 << UNIT_V_DIAG)
44 #define STA_OVF 0x08 /* PIC overflow */
45 #define CMD_STRT 0x20 /* start */
46 #define PIC_V_RATE 12 /* rate */
47 #define PIC_M_RATE 0xF
48 #define PIC_RATE (PIC_M_RATE << PIC_V_RATE)
49 #define PIC_CTR 0x0FFF /* PIC counters */
50 #define GET_RATE(x) (((x) >> PIC_V_RATE) & PIC_M_RATE)
51 #define GET_CTR(x) ((x) & PIC_CTR)
54 extern uint32 int_req
[INTSZ
], int_enb
[INTSZ
];
56 int32 pic_db
= 0; /* output buf */
57 int32 pic_ric
= 0; /* reset count */
58 int32 pic_cic
= 0; /* current count */
59 uint32 pic_save
= 0; /* saved time */
60 uint32 pic_ovf
= 0; /* overflow */
63 uint32 pic_cnti
= 0; /* instr/timer */
64 uint32 pic_arm
= 0; /* int arm */
65 uint32 pic_decr
= 1; /* decrement */
66 uint16 pic_time
[4] = { 1, 10, 100, 1000 }; /* delays */
67 uint16 pic_usec
[4] = { 1, 10, 100, 1000 }; /* usec per tick */
68 static int32 pic_map
[16] = { /* map rate to delay */
69 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
73 uint32
pic (uint32 dev
, uint32 op
, uint32 dat
);
74 t_stat
pic_svc (UNIT
*uptr
);
75 t_stat
pic_reset (DEVICE
*dptr
);
76 void pic_sched (t_bool strt
);
77 uint32
pic_rd_cic (void);
79 int32 lfc_tps
= 120; /* ticks per */
80 int32 lfc_poll
= 8000;
81 uint32 lfc_arm
= 0; /* int arm */
84 uint32
lfc (uint32 dev
, uint32 op
, uint32 dat
);
85 t_stat
lfc_svc (UNIT
*uptr
);
86 t_stat
lfc_reset (DEVICE
*dptr
);
87 t_stat
lfc_set_freq (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
88 t_stat
lfc_show_freq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
90 /* PIC data structures
92 pic_dev PIC device descriptor
93 pic_unit PIC unit descriptor
94 pic_reg PIC register list
97 DIB pic_dib
= { d_PIC
, -1, v_PIC
, NULL
, &pic
, NULL
};
99 UNIT pic_unit
= { UDATA (&pic_svc
, UNIT_IDLE
, 0), 1000 };
102 { HRDATA (BUF
, pic_db
, 16) },
103 { HRDATA (RIC
, pic_ric
, 16) },
104 { HRDATA (CIC
, pic_cic
, 12) },
105 { FLDATA (RDP
, pic_rdp
, 0) },
106 { FLDATA (WDP
, pic_wdp
, 0) },
107 { FLDATA (OVF
, pic_ovf
, 0) },
108 { FLDATA (IREQ
, int_req
[l_PIC
], i_PIC
) },
109 { FLDATA (IENB
, int_enb
[l_PIC
], i_PIC
) },
110 { FLDATA (IARM
, pic_arm
, 0) },
111 { BRDATA (TIME
, pic_time
, 10, 16, 4), REG_NZ
+ PV_LEFT
},
112 { DRDATA (SAVE
, pic_save
, 32), REG_HRO
+ PV_LEFT
},
113 { DRDATA (DECR
, pic_decr
, 16), REG_HRO
+ PV_LEFT
},
114 { FLDATA (MODE
, pic_cnti
, 0), REG_HRO
},
115 { HRDATA (DEVNO
, pic_dib
.dno
, 8), REG_HRO
},
120 { UNIT_DIAG
, UNIT_DIAG
, "diagnostic mode", "DIAG", NULL
},
121 { UNIT_DIAG
, 0, NULL
, "NORMAL", NULL
},
122 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO",
123 &set_dev
, &show_dev
, NULL
},
128 "PIC", &pic_unit
, pic_reg
, pic_mod
,
130 NULL
, NULL
, &pic_reset
,
132 &pic_dib
, DEV_DISABLE
135 /* LFC data structures
137 lfc_dev LFC device descriptor
138 lfc_unit LFC unit descriptor
139 lfc_reg LFC register list
142 DIB lfc_dib
= { d_LFC
, -1, v_LFC
, NULL
, &lfc
, NULL
};
144 UNIT lfc_unit
= { UDATA (&lfc_svc
, UNIT_IDLE
, 0), 8333 };
147 { FLDATA (IREQ
, int_req
[l_LFC
], i_LFC
) },
148 { FLDATA (IENB
, int_enb
[l_LFC
], i_LFC
) },
149 { FLDATA (IARM
, lfc_arm
, 0) },
150 { DRDATA (TIME
, lfc_unit
.wait
, 24), REG_NZ
+ PV_LEFT
},
151 { DRDATA (TPS
, lfc_tps
, 8), PV_LEFT
+ REG_HRO
},
152 { HRDATA (DEVNO
, lfc_dib
.dno
, 8), REG_HRO
},
157 { MTAB_XTD
|MTAB_VDV
, 100, NULL
, "50HZ",
158 &lfc_set_freq
, NULL
, NULL
},
159 { MTAB_XTD
|MTAB_VDV
, 120, NULL
, "60HZ",
160 &lfc_set_freq
, NULL
, NULL
},
161 { MTAB_XTD
|MTAB_VDV
, 0, "FREQUENCY", NULL
,
162 NULL
, &lfc_show_freq
, NULL
},
163 { MTAB_XTD
|MTAB_VDV
, 0, "DEVNO", "DEVNO",
164 &set_dev
, &show_dev
, NULL
},
169 "LFC", &lfc_unit
, lfc_reg
, lfc_mod
,
171 NULL
, NULL
, &lfc_reset
,
173 &lfc_dib
, DEV_DISABLE
176 /* Precision clock: IO routine */
178 uint32
pic (uint32 dev
, uint32 op
, uint32 dat
)
182 switch (op
) { /* case IO op */
184 case IO_ADR
: /* select */
185 return HW
; /* HW capable */
187 case IO_RH
: /* read halfword */
188 pic_rdp
= 0; /* clr ptr */
189 return pic_rd_cic ();
191 case IO_RD
: /* read */
192 t
= pic_rd_cic (); /* get cic */
193 if (pic_rdp
) t
= t
& DMASK8
; /* 2nd? get lo */
194 else t
= (t
>> 8) & DMASK8
; /* 1st? get hi */
195 pic_rdp
= pic_rdp
^ 1; /* flip byte ptr */
198 case IO_WH
: /* write halfword */
199 pic_wdp
= 0; /* clr ptr */
203 case IO_WD
: /* write */
204 if (pic_wdp
) pic_db
= (pic_db
& 0xFF00) | dat
;
205 else pic_db
= (pic_db
& 0xFF) | (dat
<< 8);
206 pic_wdp
= pic_wdp
^ 1; /* flip byte ptr */
209 case IO_SS
: /* sense status */
210 if (pic_ovf
) { /* overflow? */
211 pic_ovf
= 0; /* clear flag */
212 CLR_INT (v_PIC
); /* clear intr */
217 case IO_OC
: /* output cmd */
218 pic_arm
= int_chg (v_PIC
, dat
, pic_arm
); /* upd int ctrl */
219 if (dat
& CMD_STRT
) { /* start? */
220 pic_ric
= pic_db
; /* new ric */
221 pic_cic
= GET_CTR (pic_ric
); /* new cic */
222 pic_ovf
= 0; /* clear flag */
223 sim_cancel (&pic_unit
); /* stop clock */
224 pic_rdp
= pic_wdp
= 0; /* init ptrs */
225 if (pic_ric
& PIC_RATE
) pic_sched (TRUE
); /* any rate? */
235 t_stat
pic_svc (UNIT
*uptr
)
237 t_bool rate_chg
= FALSE
;
239 if (pic_cnti
) pic_cic
= 0; /* one shot? */
240 pic_cic
= pic_cic
- pic_decr
; /* decrement */
241 if (pic_cic
<= 0) { /* overflow? */
242 if (pic_wdp
) pic_ovf
= 1; /* broken wr? set flag */
243 if (pic_arm
) SET_INT (v_PIC
); /* if armed, intr */
244 if (GET_RATE (pic_ric
) != GET_RATE (pic_db
)) /* rate change? */
246 pic_ric
= pic_db
; /* new ric */
247 pic_cic
= GET_CTR (pic_ric
); /* new cic */
248 if ((pic_ric
& PIC_RATE
) == 0) return SCPE_OK
;
250 pic_sched (rate_chg
);
254 /* Schedule next interval
256 If eff rate < 1ms, or diagnostic mode, count instructions
257 If eff rate = 1ms, and not diagnostic mode, use timer
260 void pic_sched (t_bool strt
)
262 int32 r
, t
, intv
, intv_usec
;
264 pic_save
= sim_grtime (); /* save start */
265 r
= pic_map
[GET_RATE (pic_ric
)]; /* get mapped rate */
266 intv
= pic_cic
? pic_cic
: 1; /* get cntr */
267 intv_usec
= intv
* pic_usec
[r
]; /* cvt to usec */
268 if (!(pic_unit
.flags
& UNIT_DIAG
) && /* not diag? */
269 ((intv_usec
% 1000) == 0)) { /* 1ms multiple? */
270 pic_cnti
= 0; /* clr mode */
271 pic_decr
= pic_usec
[3 - r
]; /* set decrement */
272 if (strt
) t
= sim_rtcn_init (pic_time
[3], TMR_PIC
); /* init or */
273 else t
= sim_rtcn_calb (PIC_TPS
, TMR_PIC
); /* calibrate */
276 pic_cnti
= 1; /* set mode */
277 pic_decr
= 1; /* decr = 1 */
278 t
= pic_time
[r
] * intv
; /* interval */
279 if (t
== 1) t
++; /* for diagn */
281 sim_activate (&pic_unit
, t
); /* activate */
285 /* Read (interpolated) current interval */
287 uint32
pic_rd_cic (void)
289 if (sim_is_active (&pic_unit
) && pic_cnti
) { /* running, one shot? */
290 uint32 delta
= sim_grtime () - pic_save
; /* interval */
291 uint32 tm
= pic_time
[pic_map
[GET_RATE (pic_ric
)]]; /* ticks/intv */
292 delta
= delta
/ tm
; /* ticks elapsed */
293 if (delta
>= ((uint32
) pic_cic
)) return 0; /* cap value */
294 return pic_cic
- delta
;
301 t_stat
pic_reset (DEVICE
*dptr
)
303 sim_cancel (&pic_unit
); /* cancel unit */
304 pic_ric
= pic_cic
= 0;
306 pic_ovf
= 0; /* clear state */
309 pic_rdp
= pic_wdp
= 0;
310 CLR_INT (v_PIC
); /* clear int */
311 CLR_ENB (v_PIC
); /* disable int */
312 pic_arm
= 0; /* disarm int */
316 /* Line clock: IO routine */
318 uint32
lfc (uint32 dev
, uint32 op
, uint32 dat
)
320 switch (op
) { /* case IO op */
322 case IO_ADR
: /* select */
323 return BY
; /* byte only */
325 case IO_OC
: /* command */
326 lfc_arm
= int_chg (v_LFC
, dat
, lfc_arm
); /* upd int ctrl */
334 t_stat
lfc_svc (UNIT
*uptr
)
336 lfc_poll
= sim_rtcn_calb (lfc_tps
, TMR_LFC
); /* calibrate */
337 sim_activate (uptr
, lfc_poll
); /* reactivate */
338 if (lfc_arm
) { /* armed? */
339 SET_INT (v_LFC
); /* req intr */
346 t_stat
lfc_reset (DEVICE
*dptr
)
348 lfc_poll
= sim_rtcn_init (lfc_unit
.wait
, TMR_LFC
);
349 sim_activate_abs (&lfc_unit
, lfc_poll
); /* init clock */
350 CLR_INT (v_LFC
); /* clear int */
351 CLR_ENB (v_LFC
); /* disable int */
352 lfc_arm
= 0; /* disarm int */
358 t_stat
lfc_set_freq (UNIT
*uptr
, int32 val
, char *cptr
, void *desc
)
360 if (cptr
) return SCPE_ARG
;
361 if ((val
!= 100) && (val
!= 120)) return SCPE_IERR
;
368 t_stat
lfc_show_freq (FILE *st
, UNIT
*uptr
, int32 val
, void *desc
)
370 fprintf (st
, (lfc_tps
== 100)? "50Hz": "60Hz");