Page Numbers: Yes X: 520 Y: -.5" First Page: 133
Heading:
Dorado Hardware ManualOther IO and Event Counters14 September 1981
Other IO and Event Counters
In addition to the disk, ethernet, and display controllers discussed in earlier chapters, Dorado contains a general input/output interface and a junk task wakeup located on the IFU board; the two registers used in this interface may alternatively be used as event counters in performance monitoring, and that use is also discussed here.
Since the IFU board is not interfaced to the IOB, it cannot use the slow io system to control these features, so functions are used instead.
Junk Task Wakeup
The IFU board contains a circuit which wakes up the junk task (task 1) every 32 ms. The wakeup is dismissed by the AckJunkTW←B function; this function interprets B[15] as follows: a 1 enables wakeups; a 0 disables them; B[0:14] are ignored. The junk task can dismiss the wakeup by doing IFUTest←B with any value on B (but B[15] must be 0 to reenable the wakeup at the next 32 ms tick).
Junk task microcode will, among other things, maintain a Real Time clock.
General IO
A 16-bit register called GenIn (synonym EventCntA) is used for general input; it can be read with the B←GenIn (synonym B←EventCntA) function but cannot be written by firmware. When used for general input, GenIn is written with information that is TTL-to-ECL converted from the backpanel.
A 16-bit register called GenOut (synonym EventCntB) is used for general output; it can be either read with the B←GenOut (synonym B←EventCntB) function or written with the GenOut←B (synonym EventCntB←B) function. GenOut is connected to the backpanel through ECL-to-TTL converters.
The plan is that devices such as Diablo printers can be connected to the GenIn and/or GenOut signals via backpanel connectors.
The choice of using one of these registers for general io or for event counting is determined by the InsSetOrEvent←B function discussed below.
Event Counters
The GenIn and GenOut registers can alternatively be used as event counters. They cannot, of course, be used simultaneously for general io. The registers are setup for either io or event counting by the InsSetOrEvent←B function, where B[0:15] are interpreted as follows:
If B[0] is 1, then InsSet[0:1] are loaded as discussed in the "Instruction Fetch Unit" chapter. If B[0] is 0, then its the general io/event counters as follows:
B[4] enables counting of EventCntA
B[5] enables counting of EventCntB
B[8:10] select the event type to be counted by EventCntA as follows:
0True (i.e., every cycle)
1
Hold
2
Processor memory reference (not held)
3
Good IFUJump (i.e., not held and not an exception)
4
Miss
5-7
Backpanel events A, C, and E, respectively
B[12:14] select the event type to be counted by EventCntB as follows:
0True
1
Hold
2
Successful IFU memory reference
3
IFUJump that wasn’t ready
4
Miss
5-7
Backpanel events B, C, and D, respectively
B[15] causes the event to be counted for all cycles if 1 or only for emulator or fault task cycles if 0.
To use the event counters, you first stop them counting and read their current values; then you tell them what to count and start them counting and your system running. Note that they never get reset, but just keep counting from wherever they are—it’s up to the user to worry about counter turnover.
The expected mode of operation is that the junk task will detect counter overflow and update double or triple-precision vectors in RM that count events; even if the counter is counting once per 60 ns cycle, counter wraparound only occurs every 3.93 ms, so a double-precision vector could count for at least 255 seconds and triple-precision for 228 days. Sample microcode for maintaining a double-precision counter is given in the example below:
*The double-precision vector consisting of two RM locations, CountHi and CountLo
*is initialized such that CountHi eq 0 and CountLo contains minus the value in
*the event counter, and another RM location called CountFlag is initialized to 0.
*The microcode below increments CountHi whenever the event counter cycles.
*At any instant, the high part of the total count is in CountHi and the low part
*is CountLo+event counter; CountHi has to be incremented by 1 if the counter
*just overflowed.
(CountLo) - (EventCntB’) - 1;*CountLo + event counter
Pd←CountFlag, Branch[.+2,alu>=0];
CountFlag←T-T-1, Branch[.+3];
*Set CountFlag to -1 in 2nd half of the counter cycle.
CountFlag←T-T, Branch[.+2,alu>=0];
*Set CountFlag to 0 in 1st half of the counter cycle,
CountHi←(CountHi)+1;
*and increment CountHi, if we were in the 2nd half
. . .
*of the counter cycle last time.
The microcode for reading the counter when it is updated like this is as folows:
*Return to caller high part of event count in T, low part in Q.
TaskingOff, Pd←CountFlag;
T←(CountLo) - (EventCntB’) - 1, Branch[.+3,alu>=0];
*CountLo + event counter = low part of result
TaskingOn, Branch[.+3,alu<0];
*Low part ovf iff CountFlag<0 and low sum >=0
T←(CountHi)+1, Q←T, Return;
*High part of result = CountHi+1
TaskingOn;
*High part of result = CountHi
T←CountHi, Q←T, Return;
. . .