First Commit of my working state
[simh.git] / PDP10 / pdp10_tim.c
CommitLineData
196ba1fc
PH
1/* pdp10_tim.c: PDP-10 tim subsystem simulator\r
2\r
3 Copyright (c) 1993-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 tim timer subsystem\r
27\r
28 18-Jun-07 RMS Added UNIT_IDLE flag\r
29 03-Nov-06 RMS Rewritten to support idling\r
30 29-Oct-06 RMS Added clock coscheduling function\r
31 02-Feb-04 RMS Exported variables needed by Ethernet simulator\r
32 29-Jan-02 RMS New data structures\r
33 06-Jan-02 RMS Added enable/disable support\r
34 02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy)\r
35 31-Aug-01 RMS Changed int64 to t_int64 for Windoze\r
36 17-Jul-01 RMS Moved function prototype\r
37 04-Jul-01 RMS Added DZ11 support\r
38*/\r
39\r
40#include "pdp10_defs.h"\r
41#include <time.h>\r
42\r
43/* Invariants */\r
44\r
45#define TIM_HW_FREQ 4100000 /* 4.1Mhz */\r
46#define TIM_HWRE_MASK 07777\r
47#define UNIT_V_Y2K (UNIT_V_UF + 0) /* Y2K compliant OS */\r
48#define UNIT_Y2K (1u << UNIT_V_Y2K)\r
49\r
50/* Clock mode TOPS-10/ITS */\r
51\r
52#define TIM_TPS_T10 60\r
53#define TIM_WAIT_T10 8000\r
54#define TIM_MULT_T10 1\r
55#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10)\r
56\r
57/* Clock mode TOPS-20/KLAD */\r
58\r
59#define TIM_TPS_T20 1001\r
60#define TIM_WAIT_T20 500\r
61#define TIM_MULT_T20 16\r
62\r
63/* Probability function for TOPS-20 idlelock */\r
64\r
65#define PROB(x) (((rand() * 100) / RAND_MAX) >= (x))\r
66\r
67d10 tim_base[2] = { 0, 0 }; /* 71b timebase */\r
68d10 tim_ttg = 0; /* time to go */\r
69d10 tim_period = 0; /* period */\r
70d10 quant = 0; /* ITS quantum */\r
71int32 tim_mult = TIM_MULT_T10; /* tmxr poll mult */\r
72int32 tim_t20_prob = 33; /* TOPS-20 prob */\r
73\r
74/* Exported variables */\r
75\r
76int32 clk_tps = TIM_TPS_T10; /* clock ticks/sec */\r
77int32 tmr_poll = TIM_WAIT_T10; /* clock poll */\r
78int32 tmxr_poll = TIM_WAIT_T10 * TIM_MULT_T10; /* term mux poll */\r
79\r
80extern int32 apr_flg, pi_act;\r
81extern UNIT cpu_unit;\r
82extern d10 pcst;\r
83extern a10 pager_PC;\r
84extern int32 t20_idlelock;\r
85\r
86DEVICE tim_dev;\r
87t_stat tcu_rd (int32 *data, int32 PA, int32 access);\r
88t_stat tim_svc (UNIT *uptr);\r
89t_stat tim_reset (DEVICE *dptr);\r
90void tim_incr_base (d10 *base, d10 incr);\r
91\r
92extern d10 Read (a10 ea, int32 prv);\r
93extern d10 ReadM (a10 ea, int32 prv);\r
94extern void Write (a10 ea, d10 val, int32 prv);\r
95extern void WriteP (a10 ea, d10 val);\r
96extern int32 pi_eval (void);\r
97extern t_stat wr_nop (int32 data, int32 PA, int32 access);\r
98\r
99/* TIM data structures\r
100\r
101 tim_dev TIM device descriptor\r
102 tim_unit TIM unit descriptor\r
103 tim_reg TIM register list\r
104*/\r
105\r
106DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 };\r
107\r
108UNIT tim_unit = { UDATA (&tim_svc, UNIT_IDLE, 0), TIM_WAIT_T10 };\r
109\r
110REG tim_reg[] = {\r
111 { BRDATA (TIMEBASE, tim_base, 8, 36, 2) },\r
112 { ORDATA (TTG, tim_ttg, 36) },\r
113 { ORDATA (PERIOD, tim_period, 36) },\r
114 { ORDATA (QUANT, quant, 36) },\r
115 { DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT },\r
116 { DRDATA (PROB, tim_t20_prob, 6), REG_NZ + PV_LEFT + REG_HIDDEN },\r
117 { DRDATA (POLL, tmr_poll, 32), REG_HRO + PV_LEFT },\r
118 { DRDATA (MUXPOLL, tmxr_poll, 32), REG_HRO + PV_LEFT },\r
119 { DRDATA (MULT, tim_mult, 6), REG_HRO + PV_LEFT },\r
120 { DRDATA (TPS, clk_tps, 12), REG_HRO + PV_LEFT },\r
121 { NULL }\r
122 };\r
123\r
124MTAB tim_mod[] = {\r
125 { UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL },\r
126 { UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL },\r
127 { MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL,\r
128 NULL, &show_addr, NULL },\r
129 { 0 }\r
130 };\r
131\r
132DEVICE tim_dev = {\r
133 "TIM", &tim_unit, tim_reg, tim_mod,\r
134 1, 0, 0, 0, 0, 0,\r
135 NULL, NULL, &tim_reset,\r
136 NULL, NULL, NULL,\r
137 &tcu_dib, DEV_UBUS\r
138 };\r
139\r
140/* Timer instructions */\r
141\r
142/* Timer - if the timer is running at less than hardware frequency,\r
143 need to interpolate the value by calculating how much of the current\r
144 clock tick has elapsed, and what that equates to in msec. */\r
145\r
146t_bool rdtim (a10 ea, int32 prv)\r
147{\r
148d10 tempbase[2];\r
149\r
150ReadM (INCA (ea), prv); /* check 2nd word */\r
151tempbase[0] = tim_base[0]; /* copy time base */\r
152tempbase[1] = tim_base[1];\r
153if (tim_mult != TIM_MULT_T20) { /* interpolate? */\r
154 int32 used;\r
155 d10 incr;\r
156 used = tmr_poll - (sim_is_active (&tim_unit) - 1);\r
157 incr = (d10) (((double) used * TIM_HW_FREQ) /\r
158 ((double) tmr_poll * (double) clk_tps));\r
159 tim_incr_base (tempbase, incr);\r
160 }\r
161tempbase[0] = tempbase[0] & ~((d10) TIM_HWRE_MASK); /* clear low 12b */\r
162Write (ea, tempbase[0], prv);\r
163Write (INCA(ea), tempbase[1], prv);\r
164return FALSE;\r
165}\r
166\r
167t_bool wrtim (a10 ea, int32 prv)\r
168{\r
169tim_base[0] = Read (ea, prv);\r
170tim_base[1] = CLRS (Read (INCA (ea), prv));\r
171return FALSE;\r
172}\r
173\r
174t_bool rdint (a10 ea, int32 prv)\r
175{\r
176Write (ea, tim_period, prv);\r
177return FALSE;\r
178}\r
179\r
180t_bool wrint (a10 ea, int32 prv)\r
181{\r
182tim_period = Read (ea, prv);\r
183tim_ttg = tim_period;\r
184return FALSE;\r
185}\r
186\r
187/* Timer service - the timer is only serviced when the 'ttg' register\r
188 has reached 0 based on the expected frequency of clock interrupts. */\r
189\r
190t_stat tim_svc (UNIT *uptr)\r
191{\r
192if (cpu_unit.flags & UNIT_KLAD) /* diags? */\r
193 tmr_poll = uptr->wait; /* fixed clock */\r
194else tmr_poll = sim_rtc_calb (clk_tps); /* else calibrate */\r
195sim_activate (uptr, tmr_poll); /* reactivate unit */\r
196tmxr_poll = tmr_poll * tim_mult; /* set mux poll */\r
197tim_incr_base (tim_base, tim_period); /* incr time base */\r
198tim_ttg = tim_period; /* reload */\r
199apr_flg = apr_flg | APRF_TIM; /* request interrupt */\r
200if (Q_ITS) { /* ITS? */\r
201 if (pi_act == 0)\r
202 quant = (quant + TIM_ITS_QUANT) & DMASK;\r
203 if (TSTS (pcst)) { /* PC sampling? */\r
204 WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */\r
205 pcst = AOB (pcst); /* add 1,,1 */\r
206 }\r
207 } /* end ITS */\r
208else if (t20_idlelock && PROB (100 - tim_t20_prob))\r
209 t20_idlelock = 0;\r
210return SCPE_OK;\r
211}\r
212\r
213/* Clock coscheduling routine */\r
214\r
215int32 clk_cosched (int32 wait)\r
216{\r
217int32 t;\r
218\r
219if (tim_mult == TIM_MULT_T20) return wait;\r
220t = sim_is_active (&tim_unit);\r
221return (t? t - 1: wait);\r
222}\r
223\r
224void tim_incr_base (d10 *base, d10 incr)\r
225{\r
226base[1] = base[1] + incr; /* add on incr */\r
227base[0] = base[0] + (base[1] >> 35); /* carry to high */\r
228base[0] = base[0] & DMASK; /* mask high */\r
229base[1] = base[1] & MMASK; /* mask low */\r
230return;\r
231}\r
232\r
233/* Timer reset */\r
234\r
235t_stat tim_reset (DEVICE *dptr)\r
236{\r
237tim_period = 0; /* clear timer */\r
238tim_ttg = 0;\r
239apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */\r
240tmr_poll = sim_rtc_init (tim_unit.wait); /* init timer */\r
241sim_activate_abs (&tim_unit, tmr_poll); /* activate unit */\r
242tmxr_poll = tmr_poll * tim_mult; /* set mux poll */\r
243return SCPE_OK;\r
244}\r
245\r
246/* Set timer parameters from CPU model */\r
247\r
248t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc)\r
249{\r
250if (val & (UNIT_T20|UNIT_KLAD)) {\r
251 clk_tps = TIM_TPS_T20;\r
252 uptr->wait = TIM_WAIT_T20;\r
253 tmr_poll = TIM_WAIT_T20;\r
254 tim_mult = TIM_MULT_T20;\r
255 uptr->flags = uptr->flags | UNIT_Y2K;\r
256 }\r
257else {\r
258 clk_tps = TIM_TPS_T10;\r
259 uptr->wait = TIM_WAIT_T10;\r
260 tmr_poll = TIM_WAIT_T10;\r
261 tim_mult = TIM_MULT_T10;\r
262 if (Q_ITS) uptr->flags = uptr->flags | UNIT_Y2K;\r
263 else uptr->flags = uptr->flags & ~UNIT_Y2K;\r
264 }\r
265tmxr_poll = tmr_poll * tim_mult;\r
266return SCPE_OK;\r
267}\r
268\r
269/* Time of year clock */\r
270\r
271t_stat tcu_rd (int32 *data, int32 PA, int32 access)\r
272{\r
273time_t curtim;\r
274struct tm *tptr;\r
275\r
276curtim = time (NULL); /* get time */\r
277tptr = localtime (&curtim); /* decompose */\r
278if (tptr == NULL) return SCPE_NXM; /* Y2K prob? */\r
279if ((tptr->tm_year > 99) && !(tim_unit.flags & UNIT_Y2K))\r
280 tptr->tm_year = 99; \r
281\r
282switch ((PA >> 1) & 03) { /* decode PA<3:1> */\r
283\r
284 case 0: /* year/month/day */\r
285 *data = (((tptr->tm_year) & 0177) << 9) |\r
286 (((tptr->tm_mon + 1) & 017) << 5) |\r
287 ((tptr->tm_mday) & 037);\r
288 return SCPE_OK;\r
289\r
290 case 1: /* hour/minute */\r
291 *data = (((tptr->tm_hour) & 037) << 8) |\r
292 ((tptr->tm_min) & 077);\r
293 return SCPE_OK;\r
294\r
295 case 2: /* second */\r
296 *data = (tptr->tm_sec) & 077;\r
297 return SCPE_OK;\r
298\r
299 case 3: /* status */\r
300 *data = CSR_DONE;\r
301 return SCPE_OK;\r
302 }\r
303\r
304return SCPE_NXM; /* can't get here */\r
305}\r