| /* nova_clk.c: NOVA real-time clock simulator | |
| Copyright (c) 1993-2008, Robert M. Supnik | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of Robert M Supnik shall not be | |
| used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from Robert M Supnik. | |
| clk real-time clock | |
| 04-Jul-07 BKR DEV_SET/CLR macros now used, | |
| changed CLK name to RTC for DG compatiblity, | |
| device may now bw DISABLED | |
| 01-Mar-03 RMS Added SET/SHOW CLK FREQ support | |
| 03-Oct-02 RMS Added DIB | |
| 17-Sep-01 RMS Added terminal multiplexor support | |
| 17-Mar-01 RMS Moved function prototype | |
| 05-Mar-01 RMS Added clock calibration | |
| 24-Sep-97 RMS Fixed bug in unit service (found by Charles Owen) | |
| */ | |
| #include "nova_defs.h" | |
| extern int32 int_req, dev_busy, dev_done, dev_disable ; | |
| int32 clk_sel = 0; /* selected freq */ | |
| int32 clk_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */ | |
| int32 clk_tps[4] = { 60, 10, 100, 1000 }; /* ticks per sec */ | |
| int32 clk_adj[4] = { 1, -5, 2, 20 }; /* tmxr adjust */ | |
| int32 tmxr_poll = 16000; /* tmxr poll */ | |
| int32 clk (int32 pulse, int32 code, int32 AC); | |
| t_stat clk_svc (UNIT *uptr); | |
| t_stat clk_reset (DEVICE *dptr); | |
| t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); | |
| t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); | |
| /* CLK data structures | |
| clk_dev CLK device descriptor | |
| clk_unit CLK unit descriptor | |
| clk_reg CLK register list | |
| */ | |
| DIB clk_dib = { DEV_CLK, INT_CLK, PI_CLK, &clk }; | |
| UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; | |
| REG clk_reg[] = { | |
| { ORDATA (SELECT, clk_sel, 2) }, | |
| { FLDATA (BUSY, dev_busy, INT_V_CLK) }, | |
| { FLDATA (DONE, dev_done, INT_V_CLK) }, | |
| { FLDATA (DISABLE, dev_disable, INT_V_CLK) }, | |
| { FLDATA (INT, int_req, INT_V_CLK) }, | |
| { DRDATA (TIME0, clk_time[0], 24), REG_NZ + PV_LEFT }, | |
| { DRDATA (TIME1, clk_time[1], 24), REG_NZ + PV_LEFT }, | |
| { DRDATA (TIME2, clk_time[2], 24), REG_NZ + PV_LEFT }, | |
| { DRDATA (TIME3, clk_time[3], 24), REG_NZ + PV_LEFT }, | |
| { DRDATA (TPS0, clk_tps[0], 6), PV_LEFT + REG_HRO }, | |
| { NULL } | |
| }; | |
| MTAB clk_mod[] = { | |
| { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ", | |
| &clk_set_freq, NULL, NULL }, | |
| { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ", | |
| &clk_set_freq, NULL, NULL }, | |
| { MTAB_XTD|MTAB_VDV, 0, "LINE", NULL, | |
| NULL, &clk_show_freq, NULL }, | |
| { 0 } | |
| }; | |
| DEVICE clk_dev = { | |
| "RTC", &clk_unit, clk_reg, clk_mod, | |
| 1, 0, 0, 0, 0, 0, | |
| NULL, NULL, &clk_reset, | |
| NULL, NULL, NULL, | |
| &clk_dib, DEV_DISABLE | |
| }; | |
| /* IOT routine */ | |
| int32 clk (int32 pulse, int32 code, int32 AC) | |
| { | |
| if (code == ioDOA) { /* DOA */ | |
| clk_sel = AC & 3; /* save select */ | |
| sim_rtc_init (clk_time[clk_sel]); /* init calibr */ | |
| } | |
| switch (pulse) { /* decode IR<8:9> */ | |
| case iopS: /* start */ | |
| DEV_SET_BUSY( INT_CLK ) ; | |
| DEV_CLR_DONE( INT_CLK ) ; | |
| DEV_UPDATE_INTR ; | |
| if (!sim_is_active (&clk_unit)) /* not running? */ | |
| sim_activate (&clk_unit, /* activate */ | |
| sim_rtc_init (clk_time[clk_sel])); /* init calibr */ | |
| break; | |
| case iopC: /* clear */ | |
| DEV_CLR_BUSY( INT_CLK ) ; | |
| DEV_CLR_DONE( INT_CLK ) ; | |
| DEV_UPDATE_INTR ; | |
| sim_cancel (&clk_unit); /* deactivate unit */ | |
| break; | |
| } /* end switch */ | |
| return 0; | |
| } | |
| /* Unit service */ | |
| t_stat clk_svc (UNIT *uptr) | |
| { | |
| int32 t; | |
| if ( DEV_IS_BUSY(INT_CLK) ) | |
| { | |
| DEV_CLR_BUSY( INT_CLK ) ; | |
| DEV_SET_DONE( INT_CLK ) ; | |
| DEV_UPDATE_INTR ; | |
| } | |
| t = sim_rtc_calb (clk_tps[clk_sel]); /* calibrate delay */ | |
| sim_activate (&clk_unit, t); /* reactivate unit */ | |
| if (clk_adj[clk_sel] > 0) /* clk >= 60Hz? */ | |
| tmxr_poll = t * clk_adj[clk_sel]; /* poll is longer */ | |
| else | |
| tmxr_poll = t / (-clk_adj[clk_sel]); /* poll is shorter */ | |
| return SCPE_OK; | |
| } | |
| /* Reset routine */ | |
| t_stat clk_reset (DEVICE *dptr) | |
| { | |
| clk_sel = 0; | |
| DEV_CLR_BUSY( INT_CLK ) ; | |
| DEV_CLR_DONE( INT_CLK ) ; | |
| DEV_UPDATE_INTR ; | |
| sim_cancel (&clk_unit); /* deactivate unit */ | |
| tmxr_poll = clk_time[0]; /* poll is default */ | |
| return SCPE_OK; | |
| } | |
| /* Set line frequency */ | |
| t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc) | |
| { | |
| if (cptr) | |
| return SCPE_ARG; | |
| if ((val != 50) && (val != 60)) | |
| return SCPE_IERR; | |
| clk_tps[0] = val; | |
| return SCPE_OK; | |
| } | |
| /* Show line frequency */ | |
| t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc) | |
| { | |
| fprintf (st, (clk_tps[0] == 50)? "50Hz": "60Hz"); | |
| return SCPE_OK; | |
| } |