3b2: Improve TOD calculation
This commit is contained in:
parent
7df0468b75
commit
22b8e211c6
4 changed files with 44 additions and 198 deletions
|
@ -292,13 +292,10 @@ noret __libc_longjmp (jmp_buf buf, int val);
|
||||||
|
|
||||||
/* Timer definitions */
|
/* Timer definitions */
|
||||||
|
|
||||||
#define TMR_CLK 0 /* The clock responsible for IPL 15 interrupts */
|
#define TMR_CLK 0 /* The clock responsible for IPL 15 interrupts */
|
||||||
#define TMR_TOD 1 /* The Time-of-Day clock */
|
#define TPS_CLK 100 /* 100 ticks per second */
|
||||||
|
|
||||||
#define CLK_MIN_TICKS 500 /* No fewer than 500 sim steps between ticks */
|
#define CLK_MIN_TICKS 500 /* No fewer than 500 sim steps between ticks */
|
||||||
|
|
||||||
#define TPS_CLK 100 /* 100 ticks per second */
|
|
||||||
#define TPS_TOD 10 /* 10 ticks per second */
|
|
||||||
|
|
||||||
|
|
||||||
/* TIMING SECTION */
|
/* TIMING SECTION */
|
||||||
|
|
195
3B2/3b2_sysdev.c
195
3B2/3b2_sysdev.c
|
@ -671,20 +671,17 @@ void timer_write(uint32 pa, uint32 val, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MM58174A Real-Time-Clock
|
* MM58174A Time Of Day Clock
|
||||||
|
*
|
||||||
|
* Despite its name, this device is not used by the 3B2 as a clock. It
|
||||||
|
* is only used to store the current date and time between boots. It
|
||||||
|
* is set when an operator changes the date and time. Is is read at
|
||||||
|
* boot time. Therefore, we do not need to treat it as a clock or
|
||||||
|
* timer device here.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The year is NOT stored in the TOD clock. However, it does store an
|
|
||||||
* integer indicating which year in a 4-year Leap-Year cycle the
|
|
||||||
* current year is. To simplify converting from seconds into a TOD
|
|
||||||
* structure, we will map this into the range 1985...1988, for
|
|
||||||
* internal purposes only.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int tod_years[4] = {85, 86, 87, 88};
|
|
||||||
|
|
||||||
UNIT tod_unit = {
|
UNIT tod_unit = {
|
||||||
UDATA(&tod_svc, UNIT_IDLE+UNIT_FIX+UNIT_BINK, sizeof(TOD_DATA))
|
UDATA(NULL, UNIT_FIX+UNIT_BINK, sizeof(TOD_DATA))
|
||||||
};
|
};
|
||||||
|
|
||||||
DEVICE tod_dev = {
|
DEVICE tod_dev = {
|
||||||
|
@ -692,18 +689,13 @@ DEVICE tod_dev = {
|
||||||
1, 16, 8, 4, 16, 32,
|
1, 16, 8, 4, 16, 32,
|
||||||
NULL, NULL, &tod_reset,
|
NULL, NULL, &tod_reset,
|
||||||
NULL, &tod_attach, &tod_detach,
|
NULL, &tod_attach, &tod_detach,
|
||||||
NULL, DEV_DEBUG, 0, sys_deb_tab, NULL, NULL,
|
NULL, 0, 0, sys_deb_tab, NULL, NULL,
|
||||||
&tod_help, NULL, NULL,
|
&tod_help, NULL, NULL,
|
||||||
&tod_description
|
&tod_description
|
||||||
};
|
};
|
||||||
|
|
||||||
t_stat tod_reset(DEVICE *dptr)
|
t_stat tod_reset(DEVICE *dptr)
|
||||||
{
|
{
|
||||||
int32 t;
|
|
||||||
|
|
||||||
t = sim_rtcn_init_unit(&tod_unit, TPS_TOD, TMR_TOD);
|
|
||||||
sim_activate_after(&tod_unit, 1000000 / TPS_TOD);
|
|
||||||
|
|
||||||
if (tod_unit.filebuf == NULL) {
|
if (tod_unit.filebuf == NULL) {
|
||||||
tod_unit.filebuf = calloc(sizeof(TOD_DATA), 1);
|
tod_unit.filebuf = calloc(sizeof(TOD_DATA), 1);
|
||||||
if (tod_unit.filebuf == NULL) {
|
if (tod_unit.filebuf == NULL) {
|
||||||
|
@ -717,7 +709,6 @@ t_stat tod_reset(DEVICE *dptr)
|
||||||
t_stat tod_attach(UNIT *uptr, CONST char *cptr)
|
t_stat tod_attach(UNIT *uptr, CONST char *cptr)
|
||||||
{
|
{
|
||||||
t_stat r;
|
t_stat r;
|
||||||
TOD_DATA *td = (TOD_DATA *)uptr->filebuf;
|
|
||||||
|
|
||||||
uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE);
|
uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE);
|
||||||
|
|
||||||
|
@ -727,12 +718,6 @@ t_stat tod_attach(UNIT *uptr, CONST char *cptr)
|
||||||
uptr->flags = uptr->flags & (uint32) ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
uptr->flags = uptr->flags & (uint32) ~(UNIT_ATTABLE | UNIT_BUFABLE);
|
||||||
} else {
|
} else {
|
||||||
uptr->hwmark = (uint32) uptr->capac;
|
uptr->hwmark = (uint32) uptr->capac;
|
||||||
if (!td->ssec) {
|
|
||||||
tod_init_time();
|
|
||||||
} else {
|
|
||||||
tod_sync();
|
|
||||||
}
|
|
||||||
tod_update_tdata();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -741,10 +726,6 @@ t_stat tod_attach(UNIT *uptr, CONST char *cptr)
|
||||||
t_stat tod_detach(UNIT *uptr)
|
t_stat tod_detach(UNIT *uptr)
|
||||||
{
|
{
|
||||||
t_stat r;
|
t_stat r;
|
||||||
TOD_DATA *td = (TOD_DATA *)uptr->filebuf;
|
|
||||||
|
|
||||||
/* We're about to detach, so update the current tod clock */
|
|
||||||
tod_update_tdata();
|
|
||||||
|
|
||||||
r = detach_unit(uptr);
|
r = detach_unit(uptr);
|
||||||
|
|
||||||
|
@ -756,33 +737,17 @@ t_stat tod_detach(UNIT *uptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If no time is set in the system clock, grab it from the
|
* Re-set the tod_data registers based on the current simulated time.
|
||||||
* real wall clock.
|
|
||||||
*/
|
*/
|
||||||
void tod_init_time()
|
void tod_resync()
|
||||||
{
|
{
|
||||||
TOD_DATA *td = (TOD_DATA *)tod_unit.filebuf;
|
|
||||||
int result;
|
|
||||||
struct timespec now;
|
|
||||||
sim_rtcn_get_time(&now, TMR_TOD);
|
|
||||||
td->rsec = (time_t)now.tv_sec;
|
|
||||||
td->ssec = (t_uint64)now.tv_sec * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Re-set the tod_data registers based on the current value of ssec
|
|
||||||
*/
|
|
||||||
void tod_update_tdata()
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
struct timespec now;
|
struct timespec now;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
|
time_t sec;
|
||||||
TOD_DATA *td = (TOD_DATA *)tod_unit.filebuf;
|
TOD_DATA *td = (TOD_DATA *)tod_unit.filebuf;
|
||||||
time_t sec = td->ssec / 10;
|
|
||||||
|
|
||||||
sim_debug(EXECUTE_MSG, &tod_dev,
|
sim_rtcn_get_time(&now, TMR_CLK);
|
||||||
">>> Epoch time from tod_update_tdata() = %lu\n",
|
sec = now.tv_sec - td->delta;
|
||||||
sec);
|
|
||||||
|
|
||||||
/* Populate the tm struct based on current sim_time */
|
/* Populate the tm struct based on current sim_time */
|
||||||
localtime_r(&sec, &tm);
|
localtime_r(&sec, &tm);
|
||||||
|
@ -800,38 +765,20 @@ void tod_update_tdata()
|
||||||
td->unit_day = tm.tm_mday % 10;
|
td->unit_day = tm.tm_mday % 10;
|
||||||
td->ten_day = tm.tm_mday / 10;
|
td->ten_day = tm.tm_mday / 10;
|
||||||
td->year = 1 << ((tm.tm_year - 1) % 4);
|
td->year = 1 << ((tm.tm_year - 1) % 4);
|
||||||
sim_rtcn_get_time(&now, TMR_TOD);
|
|
||||||
sim_debug(EXECUTE_MSG, &tod_dev,
|
|
||||||
">>> Updated rsec to %lu\n",
|
|
||||||
now.tv_sec);
|
|
||||||
td->rsec = now.tv_sec;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tod_sync()
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
struct timespec now;
|
|
||||||
TOD_DATA *td = (TOD_DATA *)tod_unit.filebuf;
|
|
||||||
sim_rtcn_get_time(&now, TMR_TOD);
|
|
||||||
sim_debug(EXECUTE_MSG, &tod_dev,
|
|
||||||
">>> Syncing clock. Clock gained %lu seconds\n",
|
|
||||||
now.tv_sec - td->rsec);
|
|
||||||
td->ssec += ((time_t)now.tv_sec - td->rsec) * (t_uint64)10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Re-set the value of ssec based on the current values of the
|
* Re-calculate the delta between real time and simulated time
|
||||||
* tod_data registers.
|
|
||||||
*/
|
*/
|
||||||
void tod_update_ssec()
|
void tod_update_delta()
|
||||||
{
|
{
|
||||||
|
struct timespec now;
|
||||||
struct tm tm = {0};
|
struct tm tm = {0};
|
||||||
time_t simtime = 0;
|
time_t ssec;
|
||||||
TOD_DATA *td = (TOD_DATA *)tod_unit.filebuf;
|
TOD_DATA *td = (TOD_DATA *)tod_unit.filebuf;
|
||||||
|
sim_rtcn_get_time(&now, TMR_CLK);
|
||||||
|
|
||||||
/* We've been asked to re-set the TOD register values based on the
|
/* Compute the simulated seconds value */
|
||||||
* current 1/10th seconds since the epoch (ssec) */
|
|
||||||
|
|
||||||
tm.tm_sec = (td->ten_sec * 10) + td->unit_sec;
|
tm.tm_sec = (td->ten_sec * 10) + td->unit_sec;
|
||||||
tm.tm_min = (td->ten_min * 10) + td->unit_min;
|
tm.tm_min = (td->ten_min * 10) + td->unit_min;
|
||||||
tm.tm_hour = (td->ten_hour * 10) + td->unit_hour;
|
tm.tm_hour = (td->ten_hour * 10) + td->unit_hour;
|
||||||
|
@ -848,26 +795,9 @@ void tod_update_ssec()
|
||||||
case 8: /* Leap Year */
|
case 8: /* Leap Year */
|
||||||
tm.tm_year = 88;
|
tm.tm_year = 88;
|
||||||
}
|
}
|
||||||
|
|
||||||
tm.tm_isdst = 0;
|
tm.tm_isdst = 0;
|
||||||
simtime = mktime(&tm);
|
ssec = mktime(&tm);
|
||||||
sim_debug(EXECUTE_MSG, &tod_dev,
|
td->delta = now.tv_sec - ssec;
|
||||||
">>> Epoch time from tod_update_ssec() = %lu\n",
|
|
||||||
simtime);
|
|
||||||
td->ssec = (t_uint64)simtime * 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
t_stat tod_svc(UNIT *uptr)
|
|
||||||
{
|
|
||||||
int32 t;
|
|
||||||
TOD_DATA *td = (TOD_DATA *)(uptr->filebuf);
|
|
||||||
|
|
||||||
td->ssec++;
|
|
||||||
|
|
||||||
t = sim_rtcn_calb(TPS_TOD, TMR_TOD);
|
|
||||||
sim_activate_after(&tod_unit, (uint32) (1000000 / TPS_TOD));
|
|
||||||
|
|
||||||
return SCPE_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 tod_read(uint32 pa, size_t size)
|
uint32 tod_read(uint32 pa, size_t size)
|
||||||
|
@ -875,70 +805,36 @@ uint32 tod_read(uint32 pa, size_t size)
|
||||||
uint8 reg;
|
uint8 reg;
|
||||||
TOD_DATA *td = (TOD_DATA *)(tod_unit.filebuf);
|
TOD_DATA *td = (TOD_DATA *)(tod_unit.filebuf);
|
||||||
|
|
||||||
|
tod_resync();
|
||||||
|
|
||||||
reg = pa - TODBASE;
|
reg = pa - TODBASE;
|
||||||
|
|
||||||
switch(reg) {
|
switch(reg) {
|
||||||
case 0x04: /* 1/10 Sec */
|
case 0x04: /* 1/10 Sec */
|
||||||
return td->tsec;
|
return td->tsec;
|
||||||
case 0x08: /* 1 Sec */
|
case 0x08: /* 1 Sec */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->unit_sec=%d\n",
|
|
||||||
td->unit_sec);
|
|
||||||
return td->unit_sec;
|
return td->unit_sec;
|
||||||
case 0x0c: /* 10 Sec */
|
case 0x0c: /* 10 Sec */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->ten_sec=%d\n",
|
|
||||||
td->ten_sec);
|
|
||||||
return td->ten_sec;
|
return td->ten_sec;
|
||||||
case 0x10: /* 1 Min */
|
case 0x10: /* 1 Min */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->unit_min=%d\n",
|
|
||||||
td->unit_min);
|
|
||||||
return td->unit_min;
|
return td->unit_min;
|
||||||
case 0x14: /* 10 Min */
|
case 0x14: /* 10 Min */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->ten_min=%d\n",
|
|
||||||
td->ten_min);
|
|
||||||
return td->ten_min;
|
return td->ten_min;
|
||||||
case 0x18: /* 1 Hour */
|
case 0x18: /* 1 Hour */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->unit_hour=%d\n",
|
|
||||||
td->unit_hour);
|
|
||||||
return td->unit_hour;
|
return td->unit_hour;
|
||||||
case 0x1c: /* 10 Hour */
|
case 0x1c: /* 10 Hour */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->ten_hour=%d\n",
|
|
||||||
td->ten_hour);
|
|
||||||
return td->ten_hour;
|
return td->ten_hour;
|
||||||
case 0x20: /* 1 Day */
|
case 0x20: /* 1 Day */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->unit_day=%d\n",
|
|
||||||
td->unit_day);
|
|
||||||
return td->unit_day;
|
return td->unit_day;
|
||||||
case 0x24: /* 10 Day */
|
case 0x24: /* 10 Day */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->ten_day=%d\n",
|
|
||||||
td->ten_day);
|
|
||||||
return td->ten_day;
|
return td->ten_day;
|
||||||
case 0x28: /* Day of Week */
|
case 0x28: /* Day of Week */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->wday=%d\n",
|
|
||||||
td->wday);
|
|
||||||
return td->wday;
|
return td->wday;
|
||||||
case 0x2c: /* 1 Month */
|
case 0x2c: /* 1 Month */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->unit_mon=%d\n",
|
|
||||||
td->unit_mon);
|
|
||||||
return td->unit_mon;
|
return td->unit_mon;
|
||||||
case 0x30: /* 10 Month */
|
case 0x30: /* 10 Month */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->ten_mon=%d\n",
|
|
||||||
td->ten_mon);
|
|
||||||
return td->ten_mon;
|
return td->ten_mon;
|
||||||
case 0x34: /* Year */
|
case 0x34: /* Year */
|
||||||
sim_debug(READ_MSG, &tod_dev,
|
|
||||||
"READ TOD: td->year=%d\n",
|
|
||||||
td->year);
|
|
||||||
return td->year;
|
return td->year;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -960,83 +856,42 @@ void tod_write(uint32 pa, uint32 val, size_t size)
|
||||||
break;
|
break;
|
||||||
case 0x08: /* 1 Sec */
|
case 0x08: /* 1 Sec */
|
||||||
td->unit_sec = (uint8) val;
|
td->unit_sec = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->unit_sec=%d\n",
|
|
||||||
td->unit_sec);
|
|
||||||
break;
|
break;
|
||||||
case 0x0c: /* 10 Sec */
|
case 0x0c: /* 10 Sec */
|
||||||
td->ten_sec = (uint8) val;
|
td->ten_sec = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->ten_sec=%d\n",
|
|
||||||
td->ten_sec);
|
|
||||||
break;
|
break;
|
||||||
case 0x10: /* 1 Min */
|
case 0x10: /* 1 Min */
|
||||||
td->unit_min = (uint8) val;
|
td->unit_min = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->unit_min=%d\n",
|
|
||||||
td->unit_min);
|
|
||||||
break;
|
break;
|
||||||
case 0x14: /* 10 Min */
|
case 0x14: /* 10 Min */
|
||||||
td->ten_min = (uint8) val;
|
td->ten_min = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->ten_min=%d\n",
|
|
||||||
td->ten_min);
|
|
||||||
break;
|
break;
|
||||||
case 0x18: /* 1 Hour */
|
case 0x18: /* 1 Hour */
|
||||||
td->unit_hour = (uint8) val;
|
td->unit_hour = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->unit_hour=%d\n",
|
|
||||||
td->unit_hour);
|
|
||||||
break;
|
break;
|
||||||
case 0x1c: /* 10 Hour */
|
case 0x1c: /* 10 Hour */
|
||||||
td->ten_hour = (uint8) val;
|
td->ten_hour = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->ten_hour=%d\n",
|
|
||||||
td->ten_hour);
|
|
||||||
break;
|
break;
|
||||||
case 0x20: /* 1 Day */
|
case 0x20: /* 1 Day */
|
||||||
td->unit_day = (uint8) val;
|
td->unit_day = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->unit_day=%d\n",
|
|
||||||
td->unit_day);
|
|
||||||
break;
|
break;
|
||||||
case 0x24: /* 10 Day */
|
case 0x24: /* 10 Day */
|
||||||
td->ten_day = (uint8) val;
|
td->ten_day = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->ten_day=%d\n",
|
|
||||||
td->ten_day);
|
|
||||||
break;
|
break;
|
||||||
case 0x28: /* Day of Week */
|
case 0x28: /* Day of Week */
|
||||||
td->wday = (uint8) val;
|
td->wday = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->wday=%d\n",
|
|
||||||
td->wday);
|
|
||||||
break;
|
break;
|
||||||
case 0x2c: /* 1 Month */
|
case 0x2c: /* 1 Month */
|
||||||
td->unit_mon = (uint8) val;
|
td->unit_mon = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->unit_mon=%d\n",
|
|
||||||
td->unit_mon);
|
|
||||||
break;
|
break;
|
||||||
case 0x30: /* 10 Month */
|
case 0x30: /* 10 Month */
|
||||||
td->ten_mon = (uint8) val;
|
td->ten_mon = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->ten_mon=%d\n",
|
|
||||||
td->ten_mon);
|
|
||||||
break;
|
break;
|
||||||
case 0x34: /* Year */
|
case 0x34: /* Year */
|
||||||
td->year = (uint8) val;
|
td->year = (uint8) val;
|
||||||
sim_debug(WRITE_MSG, &tod_dev,
|
|
||||||
"WRITE TOD: td->year=%d\n",
|
|
||||||
td->year);
|
|
||||||
case 0x38:
|
case 0x38:
|
||||||
if (val & 1) {
|
if (val & 1) {
|
||||||
/* Start the clock */
|
tod_update_delta();
|
||||||
sim_debug(WRITE_MSG, &tod_dev, "Start the clock and resync TOD registers.\n");
|
|
||||||
tod_update_ssec();
|
|
||||||
} else {
|
|
||||||
/* Stop the clock */
|
|
||||||
sim_debug(WRITE_MSG, &tod_dev, "Stop the clock\n");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -80,14 +80,8 @@ void csr_write(uint32 pa, uint32 val, size_t size);
|
||||||
|
|
||||||
/* TOD */
|
/* TOD */
|
||||||
|
|
||||||
typedef enum tod_action {
|
|
||||||
TOD_SAVE,
|
|
||||||
TOD_RESTORE
|
|
||||||
} TOD_ACTION;
|
|
||||||
|
|
||||||
typedef struct tod_data {
|
typedef struct tod_data {
|
||||||
time_t rsec; /* Real clock time from the host */
|
int32 delta; /* Delta between simulated time and real time (sec.) */
|
||||||
t_uint64 ssec; /* Simulated time in 1/10th second since the epoch */
|
|
||||||
uint8 tsec; /* 1/10 seconds */
|
uint8 tsec; /* 1/10 seconds */
|
||||||
uint8 unit_sec; /* 1's column seconds */
|
uint8 unit_sec; /* 1's column seconds */
|
||||||
uint8 ten_sec; /* 10's column seconds */
|
uint8 ten_sec; /* 10's column seconds */
|
||||||
|
@ -104,11 +98,8 @@ typedef struct tod_data {
|
||||||
uint8 pad[3]; /* Padding to 32 bytes */
|
uint8 pad[3]; /* Padding to 32 bytes */
|
||||||
} TOD_DATA;
|
} TOD_DATA;
|
||||||
|
|
||||||
void tod_init_time();
|
void tod_resync();
|
||||||
void tod_update_tdata();
|
void tod_update_delta();
|
||||||
void tod_update_ssec();
|
|
||||||
void tod_sync();
|
|
||||||
t_stat tod_svc(UNIT *uptr);
|
|
||||||
t_stat tod_reset(DEVICE *dptr);
|
t_stat tod_reset(DEVICE *dptr);
|
||||||
t_stat tod_attach(UNIT *uptr, CONST char *cptr);
|
t_stat tod_attach(UNIT *uptr, CONST char *cptr);
|
||||||
t_stat tod_detach(UNIT *uptr);
|
t_stat tod_detach(UNIT *uptr);
|
||||||
|
|
|
@ -3,9 +3,6 @@ AT&T 3B2 Simulator
|
||||||
|
|
||||||
This module contains a simulator for the AT&T 3B2 Model 400 microcomputer.
|
This module contains a simulator for the AT&T 3B2 Model 400 microcomputer.
|
||||||
|
|
||||||
*CAUTION*: The simulator is under active and heavy development. It is
|
|
||||||
usable today, but please consider this emulator to be a beta.
|
|
||||||
|
|
||||||
Devices
|
Devices
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -20,6 +17,7 @@ devices are given in parentheses:
|
||||||
- SCN2681A Integrated DUART (IU)
|
- SCN2681A Integrated DUART (IU)
|
||||||
- TMS2793 Integrated Floppy Controller (IF)
|
- TMS2793 Integrated Floppy Controller (IF)
|
||||||
- uPD7261A Integrated MFM Fixed Disk Controller (ID)
|
- uPD7261A Integrated MFM Fixed Disk Controller (ID)
|
||||||
|
- MM58174A Time Of Day Clock (TOD)
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
@ -39,11 +37,14 @@ You will be greeted with the message:
|
||||||
|
|
||||||
SYSTEM FAILURE: CONSULT YOUR SYSTEM ADMINISTRATION UTILITIES GUIDE
|
SYSTEM FAILURE: CONSULT YOUR SYSTEM ADMINISTRATION UTILITIES GUIDE
|
||||||
|
|
||||||
NVRAM can be saved between boots by attaching it to a file.
|
NVRAM and Time of Day can be saved between boots by attaching both
|
||||||
|
devices to files.
|
||||||
|
|
||||||
sim> ATTACH NVRAM <file>
|
sim> ATTACH NVRAM <nvram-file>
|
||||||
|
sim> ATTACH TOD <tod-file>
|
||||||
|
|
||||||
On subsequent boots, you will instead see the message
|
If you have no operating system installed on the hard drive, on
|
||||||
|
subsequent boots you will instead see the message
|
||||||
|
|
||||||
SELF-CHECK
|
SELF-CHECK
|
||||||
|
|
||||||
|
@ -68,10 +69,11 @@ of available firmware programs.
|
||||||
Booting UNIX SVR3
|
Booting UNIX SVR3
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
UNIX SVR3 for the 3B2 partially boots. To boot UNIX, attach the first
|
UNIX SVR3 is the only operating system available for the 3B2. To boot
|
||||||
disk image from the 3B2 "Essential Utilities" distribution.
|
UNIX, attach the first disk image from the 3B2 "Essential Utilities"
|
||||||
|
distribution.
|
||||||
|
|
||||||
sim> ATTACH IF <disk-image>
|
sim> ATTACH IF <floppy-image>
|
||||||
sim> BOOT CPU
|
sim> BOOT CPU
|
||||||
|
|
||||||
Once you reach the `SYSTEM FAILURE` message, type `mcp` to enter
|
Once you reach the `SYSTEM FAILURE` message, type `mcp` to enter
|
||||||
|
@ -92,8 +94,9 @@ Installing SVR3
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
To install SVR3 to the first hard disk, first, attach a new image
|
To install SVR3 to the first hard disk, first, attach a new image
|
||||||
|
to the ID0 device:
|
||||||
|
|
||||||
sim> ATTACH ID0 <disk-image>
|
sim> ATTACH ID0 <hd-image>
|
||||||
|
|
||||||
Then, boot the file `idtools` from the "3B2 Maintenance Utilities -
|
Then, boot the file `idtools` from the "3B2 Maintenance Utilities -
|
||||||
Issue 4.0" floppy diskette.
|
Issue 4.0" floppy diskette.
|
||||||
|
|
Loading…
Add table
Reference in a new issue