First Commit of my working state
[simh.git] / Interdata / id_uvc.c
CommitLineData
196ba1fc
PH
1/* id_uvc.c: Interdata universal clock\r
2\r
3 Copyright (c) 2001-2007, Robert M. Supnik\r
4\r
5 Permission is hereby granted, free of charge, to any person obtaining a\r
6 copy of this software and associated documentation files (the "Software"),\r
7 to deal in the Software without restriction, including without limitation\r
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
9 and/or sell copies of the Software, and to permit persons to whom the\r
10 Software is furnished to do so, subject to the following conditions:\r
11\r
12 The above copyright notice and this permission notice shall be included in\r
13 all copies or substantial portions of the Software.\r
14\r
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
18 ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21\r
22 Except as contained in this notice, the name of Robert M Supnik shall not be\r
23 used in advertising or otherwise to promote the sale, use or other dealings\r
24 in this Software without prior written authorization from Robert M Supnik.\r
25\r
26 pic precision incremental clock\r
27 lfc line frequency clock\r
28\r
29 18-Jun-07 RMS Added UNIT_IDLE flag\r
30 18-Oct-06 RMS Changed LFC to be free running, export tmr_poll\r
31 23-Jul-05 RMS Fixed {} error in OC\r
32 01-Mar-03 RMS Added SET/SHOW LFC FREQ support\r
33 Changed precision clock algorithm for V7 UNIX\r
34*/\r
35\r
36#include "id_defs.h"\r
37#include <ctype.h>\r
38\r
39/* Device definitions */\r
40\r
41#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diag mode */\r
42#define UNIT_DIAG (1 << UNIT_V_DIAG)\r
43\r
44#define STA_OVF 0x08 /* PIC overflow */\r
45#define CMD_STRT 0x20 /* start */\r
46#define PIC_V_RATE 12 /* rate */\r
47#define PIC_M_RATE 0xF\r
48#define PIC_RATE (PIC_M_RATE << PIC_V_RATE)\r
49#define PIC_CTR 0x0FFF /* PIC counters */\r
50#define GET_RATE(x) (((x) >> PIC_V_RATE) & PIC_M_RATE)\r
51#define GET_CTR(x) ((x) & PIC_CTR)\r
52#define PIC_TPS 1000\r
53\r
54extern uint32 int_req[INTSZ], int_enb[INTSZ];\r
55\r
56int32 pic_db = 0; /* output buf */\r
57int32 pic_ric = 0; /* reset count */\r
58int32 pic_cic = 0; /* current count */\r
59uint32 pic_save = 0; /* saved time */\r
60uint32 pic_ovf = 0; /* overflow */\r
61uint32 pic_rdp = 0;\r
62uint32 pic_wdp = 0;\r
63uint32 pic_cnti = 0; /* instr/timer */\r
64uint32 pic_arm = 0; /* int arm */\r
65uint32 pic_decr = 1; /* decrement */\r
66uint16 pic_time[4] = { 1, 10, 100, 1000 }; /* delays */\r
67uint16 pic_usec[4] = { 1, 10, 100, 1000 }; /* usec per tick */\r
68static int32 pic_map[16] = { /* map rate to delay */\r
69 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0\r
70 };\r
71\r
72DEVICE pic_dev;\r
73uint32 pic (uint32 dev, uint32 op, uint32 dat);\r
74t_stat pic_svc (UNIT *uptr);\r
75t_stat pic_reset (DEVICE *dptr);\r
76void pic_sched (t_bool strt);\r
77uint32 pic_rd_cic (void);\r
78\r
79int32 lfc_tps = 120; /* ticks per */\r
80int32 lfc_poll = 8000;\r
81uint32 lfc_arm = 0; /* int arm */\r
82\r
83DEVICE lfc_dev;\r
84uint32 lfc (uint32 dev, uint32 op, uint32 dat);\r
85t_stat lfc_svc (UNIT *uptr);\r
86t_stat lfc_reset (DEVICE *dptr);\r
87t_stat lfc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc);\r
88t_stat lfc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc);\r
89\r
90/* PIC data structures\r
91\r
92 pic_dev PIC device descriptor\r
93 pic_unit PIC unit descriptor\r
94 pic_reg PIC register list\r
95*/\r
96\r
97DIB pic_dib = { d_PIC, -1, v_PIC, NULL, &pic, NULL };\r
98\r
99UNIT pic_unit = { UDATA (&pic_svc, UNIT_IDLE, 0), 1000 };\r
100\r
101REG pic_reg[] = {\r
102 { HRDATA (BUF, pic_db, 16) },\r
103 { HRDATA (RIC, pic_ric, 16) },\r
104 { HRDATA (CIC, pic_cic, 12) },\r
105 { FLDATA (RDP, pic_rdp, 0) },\r
106 { FLDATA (WDP, pic_wdp, 0) },\r
107 { FLDATA (OVF, pic_ovf, 0) },\r
108 { FLDATA (IREQ, int_req[l_PIC], i_PIC) },\r
109 { FLDATA (IENB, int_enb[l_PIC], i_PIC) },\r
110 { FLDATA (IARM, pic_arm, 0) },\r
111 { BRDATA (TIME, pic_time, 10, 16, 4), REG_NZ + PV_LEFT },\r
112 { DRDATA (SAVE, pic_save, 32), REG_HRO + PV_LEFT },\r
113 { DRDATA (DECR, pic_decr, 16), REG_HRO + PV_LEFT },\r
114 { FLDATA (MODE, pic_cnti, 0), REG_HRO },\r
115 { HRDATA (DEVNO, pic_dib.dno, 8), REG_HRO },\r
116 { NULL }\r
117 };\r
118\r
119MTAB pic_mod[] = {\r
120 { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL },\r
121 { UNIT_DIAG, 0, NULL, "NORMAL", NULL },\r
122 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r
123 &set_dev, &show_dev, NULL },\r
124 { 0 }\r
125 };\r
126\r
127DEVICE pic_dev = {\r
128 "PIC", &pic_unit, pic_reg, pic_mod,\r
129 1, 0, 0, 0, 0, 0,\r
130 NULL, NULL, &pic_reset,\r
131 NULL, NULL, NULL,\r
132 &pic_dib, DEV_DISABLE\r
133 };\r
134\r
135/* LFC data structures\r
136\r
137 lfc_dev LFC device descriptor\r
138 lfc_unit LFC unit descriptor\r
139 lfc_reg LFC register list\r
140*/\r
141\r
142DIB lfc_dib = { d_LFC, -1, v_LFC, NULL, &lfc, NULL };\r
143\r
144UNIT lfc_unit = { UDATA (&lfc_svc, UNIT_IDLE, 0), 8333 };\r
145\r
146REG lfc_reg[] = {\r
147 { FLDATA (IREQ, int_req[l_LFC], i_LFC) },\r
148 { FLDATA (IENB, int_enb[l_LFC], i_LFC) },\r
149 { FLDATA (IARM, lfc_arm, 0) },\r
150 { DRDATA (TIME, lfc_unit.wait, 24), REG_NZ + PV_LEFT },\r
151 { DRDATA (TPS, lfc_tps, 8), PV_LEFT + REG_HRO },\r
152 { HRDATA (DEVNO, lfc_dib.dno, 8), REG_HRO },\r
153 { NULL }\r
154 };\r
155\r
156MTAB lfc_mod[] = {\r
157 { MTAB_XTD|MTAB_VDV, 100, NULL, "50HZ",\r
158 &lfc_set_freq, NULL, NULL },\r
159 { MTAB_XTD|MTAB_VDV, 120, NULL, "60HZ",\r
160 &lfc_set_freq, NULL, NULL },\r
161 { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL,\r
162 NULL, &lfc_show_freq, NULL },\r
163 { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO",\r
164 &set_dev, &show_dev, NULL },\r
165 { 0 }\r
166 };\r
167\r
168DEVICE lfc_dev = {\r
169 "LFC", &lfc_unit, lfc_reg, lfc_mod,\r
170 1, 0, 0, 0, 0, 0,\r
171 NULL, NULL, &lfc_reset,\r
172 NULL, NULL, NULL,\r
173 &lfc_dib, DEV_DISABLE\r
174 };\r
175\r
176/* Precision clock: IO routine */\r
177\r
178uint32 pic (uint32 dev, uint32 op, uint32 dat)\r
179{\r
180int32 t;\r
181\r
182switch (op) { /* case IO op */\r
183\r
184 case IO_ADR: /* select */\r
185 return HW; /* HW capable */\r
186\r
187 case IO_RH: /* read halfword */\r
188 pic_rdp = 0; /* clr ptr */\r
189 return pic_rd_cic (); \r
190\r
191 case IO_RD: /* read */\r
192 t = pic_rd_cic (); /* get cic */\r
193 if (pic_rdp) t = t & DMASK8; /* 2nd? get lo */\r
194 else t = (t >> 8) & DMASK8; /* 1st? get hi */\r
195 pic_rdp = pic_rdp ^ 1; /* flip byte ptr */\r
196 return t;\r
197\r
198 case IO_WH: /* write halfword */\r
199 pic_wdp = 0; /* clr ptr */\r
200 pic_db = dat;\r
201 break;\r
202\r
203 case IO_WD: /* write */\r
204 if (pic_wdp) pic_db = (pic_db & 0xFF00) | dat;\r
205 else pic_db = (pic_db & 0xFF) | (dat << 8);\r
206 pic_wdp = pic_wdp ^ 1; /* flip byte ptr */\r
207 break;\r
208\r
209 case IO_SS: /* sense status */\r
210 if (pic_ovf) { /* overflow? */\r
211 pic_ovf = 0; /* clear flag */\r
212 CLR_INT (v_PIC); /* clear intr */\r
213 return STA_OVF;\r
214 }\r
215 return 0;\r
216\r
217 case IO_OC: /* output cmd */\r
218 pic_arm = int_chg (v_PIC, dat, pic_arm); /* upd int ctrl */\r
219 if (dat & CMD_STRT) { /* start? */\r
220 pic_ric = pic_db; /* new ric */\r
221 pic_cic = GET_CTR (pic_ric); /* new cic */\r
222 pic_ovf = 0; /* clear flag */\r
223 sim_cancel (&pic_unit); /* stop clock */\r
224 pic_rdp = pic_wdp = 0; /* init ptrs */\r
225 if (pic_ric & PIC_RATE) pic_sched (TRUE); /* any rate? */\r
226 } /* end if start */\r
227 break;\r
228 } /* end case */\r
229\r
230return 0;\r
231}\r
232\r
233/* Unit service */\r
234\r
235t_stat pic_svc (UNIT *uptr)\r
236{\r
237t_bool rate_chg = FALSE;\r
238\r
239if (pic_cnti) pic_cic = 0; /* one shot? */\r
240pic_cic = pic_cic - pic_decr; /* decrement */\r
241if (pic_cic <= 0) { /* overflow? */\r
242 if (pic_wdp) pic_ovf = 1; /* broken wr? set flag */\r
243 if (pic_arm) SET_INT (v_PIC); /* if armed, intr */\r
244 if (GET_RATE (pic_ric) != GET_RATE (pic_db)) /* rate change? */\r
245 rate_chg = TRUE;\r
246 pic_ric = pic_db; /* new ric */\r
247 pic_cic = GET_CTR (pic_ric); /* new cic */\r
248 if ((pic_ric & PIC_RATE) == 0) return SCPE_OK;\r
249 }\r
250pic_sched (rate_chg);\r
251return SCPE_OK;\r
252}\r
253\r
254/* Schedule next interval\r
255\r
256 If eff rate < 1ms, or diagnostic mode, count instructions\r
257 If eff rate = 1ms, and not diagnostic mode, use timer\r
258*/\r
259\r
260void pic_sched (t_bool strt)\r
261{\r
262int32 r, t, intv, intv_usec;\r
263\r
264pic_save = sim_grtime (); /* save start */\r
265r = pic_map[GET_RATE (pic_ric)]; /* get mapped rate */\r
266intv = pic_cic? pic_cic: 1; /* get cntr */\r
267intv_usec = intv * pic_usec[r]; /* cvt to usec */\r
268if (!(pic_unit.flags & UNIT_DIAG) && /* not diag? */\r
269 ((intv_usec % 1000) == 0)) { /* 1ms multiple? */\r
270 pic_cnti = 0; /* clr mode */\r
271 pic_decr = pic_usec[3 - r]; /* set decrement */\r
272 if (strt) t = sim_rtcn_init (pic_time[3], TMR_PIC); /* init or */\r
273 else t = sim_rtcn_calb (PIC_TPS, TMR_PIC); /* calibrate */\r
274 }\r
275else {\r
276 pic_cnti = 1; /* set mode */\r
277 pic_decr = 1; /* decr = 1 */\r
278 t = pic_time[r] * intv; /* interval */\r
279 if (t == 1) t++; /* for diagn */\r
280 }\r
281sim_activate (&pic_unit, t); /* activate */\r
282return;\r
283}\r
284 \r
285/* Read (interpolated) current interval */\r
286\r
287uint32 pic_rd_cic (void)\r
288{\r
289if (sim_is_active (&pic_unit) && pic_cnti) { /* running, one shot? */\r
290 uint32 delta = sim_grtime () - pic_save; /* interval */\r
291 uint32 tm = pic_time[pic_map[GET_RATE (pic_ric)]]; /* ticks/intv */\r
292 delta = delta / tm; /* ticks elapsed */\r
293 if (delta >= ((uint32) pic_cic)) return 0; /* cap value */\r
294 return pic_cic - delta;\r
295 }\r
296return pic_cic;\r
297}\r
298\r
299/* Reset routine */\r
300\r
301t_stat pic_reset (DEVICE *dptr)\r
302{\r
303sim_cancel (&pic_unit); /* cancel unit */\r
304pic_ric = pic_cic = 0;\r
305pic_db = 0;\r
306pic_ovf = 0; /* clear state */\r
307pic_cnti = 0;\r
308pic_decr = 1;\r
309pic_rdp = pic_wdp = 0;\r
310CLR_INT (v_PIC); /* clear int */\r
311CLR_ENB (v_PIC); /* disable int */\r
312pic_arm = 0; /* disarm int */\r
313return SCPE_OK;\r
314}\r
315\r
316/* Line clock: IO routine */\r
317\r
318uint32 lfc (uint32 dev, uint32 op, uint32 dat)\r
319{\r
320switch (op) { /* case IO op */\r
321\r
322 case IO_ADR: /* select */\r
323 return BY; /* byte only */\r
324\r
325 case IO_OC: /* command */\r
326 lfc_arm = int_chg (v_LFC, dat, lfc_arm); /* upd int ctrl */\r
327 break;\r
328 }\r
329return 0;\r
330}\r
331\r
332/* Unit service */\r
333\r
334t_stat lfc_svc (UNIT *uptr)\r
335{\r
336lfc_poll = sim_rtcn_calb (lfc_tps, TMR_LFC); /* calibrate */\r
337sim_activate (uptr, lfc_poll); /* reactivate */\r
338if (lfc_arm) { /* armed? */\r
339 SET_INT (v_LFC); /* req intr */\r
340 }\r
341return SCPE_OK;\r
342}\r
343\r
344/* Reset routine */\r
345\r
346t_stat lfc_reset (DEVICE *dptr)\r
347{\r
348lfc_poll = sim_rtcn_init (lfc_unit.wait, TMR_LFC);\r
349sim_activate_abs (&lfc_unit, lfc_poll); /* init clock */\r
350CLR_INT (v_LFC); /* clear int */\r
351CLR_ENB (v_LFC); /* disable int */\r
352lfc_arm = 0; /* disarm int */\r
353return SCPE_OK;\r
354}\r
355\r
356/* Set frequency */\r
357\r
358t_stat lfc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc)\r
359{\r
360if (cptr) return SCPE_ARG;\r
361if ((val != 100) && (val != 120)) return SCPE_IERR;\r
362lfc_tps = val;\r
363return SCPE_OK;\r
364}\r
365\r
366/* Show frequency */\r
367\r
368t_stat lfc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc)\r
369{\r
370fprintf (st, (lfc_tps == 100)? "50Hz": "60Hz");\r
371return SCPE_OK;\r
372}\r
373\r