Using the 8254 TimerCounter Understanding the role of

  • Slides: 22
Download presentation
Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter

Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter

Displaying ‘Time-Of-Day’ • Algorithm steps: – Get the count of timer-interrupts so far today

Displaying ‘Time-Of-Day’ • Algorithm steps: – Get the count of timer-interrupts so far today – Convert these ‘timer-ticks’ into seconds – Breakdown the total number of seconds today into Hours, Minutes, Seconds, and AM/PM – Convert numerical values into digit-strings – Output these results to the video terminal

Where’s the ‘tick’ counter? main memory 0 x 00500 0040: 006 C 0 x

Where’s the ‘tick’ counter? main memory 0 x 00500 0040: 006 C 0 x 00400 tick_count ROM-BIOS DATA AREA Interrupt Vector Table (for real-mode) 0 x 00000 Number of timer-tick interrupts so far today (longword at 0 x 0046 C)

Getting the ‘tick’ count • The ROM-BIOS interrupt-handler for the timer interrupt stores the

Getting the ‘tick’ count • The ROM-BIOS interrupt-handler for the timer interrupt stores the tick-count as a 32 -bit integer located at address 0 x 046 C (it’s in the ROM-BIOS DATA AREA) • In real-mode, we can get it like this: xor mov mov %ax, %fs: 0 x 046 C, %eax, total_ticks # address segment zero # using FS register # copy tick-count to EAX # save in a local variable segment-override prefix (segment used would be %ds)

Converting ‘ticks’ to seconds total_seconds_today = total_ticks_today number of ticks-per-second The number of ‘ticks-per-second’

Converting ‘ticks’ to seconds total_seconds_today = total_ticks_today number of ticks-per-second The number of ‘ticks-per-second’ is based upon the way the PC’s timing hardware has been programmed

The 8254 PIT • The 8254 Programmable Interval-timer is used by the PC system

The 8254 PIT • The 8254 Programmable Interval-timer is used by the PC system for (1) generating timer-tick interrupts (rate is 18. 2 per sec), (2) performing dynamic memory-refresh (reads ram once every 15 microseconds), and (3) generates ‘beeps’ of PC speaker • When the speaker-function isn’t needed, the 8254 is available for other purposes

Input/Output frequencies • The input-pulses to each Timer-channel is a long established PC standard,

Input/Output frequencies • The input-pulses to each Timer-channel is a long established PC standard, based on the design of the chrystal oscillator chip: 1, 193, 182 pulses-per-second (Hertz) • The frequency of the output-pulses from any Timer-channel is determined by how that channel’s Latch was programmed

Three timer/counter ‘channels’ 8284 PCLK 1193182 Hz CLK 0 GATE 0 Channel 1 Port

Three timer/counter ‘channels’ 8284 PCLK 1193182 Hz CLK 0 GATE 0 Channel 1 Port 0 x 61, bit #0 +5 V OUT 1 DRAM refresh Port 0 x 61, bit #5 CLK 2 GATE 2 Interrupt IRQ 0 Port 0 x 61, bit #4 CLK 1 GATE 1 OUT 0 Channel 2 8254 PIT Port 0 x 61, bit #1 OUT 2 AND speaker

Counter decrements when pulsed COUNT REGISTER CLK MSB LSB LATCH REGISTER GATE STATUS TIMER/COUNTER

Counter decrements when pulsed COUNT REGISTER CLK MSB LSB LATCH REGISTER GATE STATUS TIMER/COUNTER CHANNEL OUT

8254 Command-Port 7 6 CHANNEL Channel-ID 00 = chn 0 01 = chn 1

8254 Command-Port 7 6 CHANNEL Channel-ID 00 = chn 0 01 = chn 1 10 = chn 2 5 4 COMMAND 3 2 OUTPUT MODE 1 0 binary / BCD Output Mode Counting Mode Command-ID 000 = one-shot level 0 = binary 00 = Latch 001 = retriggerable 1 = BCD 01 = LSB r/w 010 = rate-generator 10 = MSB r/w 11 = LSB-MSB r/w 011 = square-wave 100 = software strobe 101 = hardware strobe Commands are sent to the 8254 via io/port 0 x 43

Programming a PIT channel • Step 1: send command to PIT (port 0 x

Programming a PIT channel • Step 1: send command to PIT (port 0 x 43) • Step 2: read or write the channel’s Latch – via port 0 x 40 for channel 0 – via port 0 x 41 for channel 1 – via port 0 x 42 for channel 2

Standard BIOS programming • For Channel 0 (the ‘timer-tick’ interrupt) the Latch is programmed

Standard BIOS programming • For Channel 0 (the ‘timer-tick’ interrupt) the Latch is programmed during system startup with a value of zero • But the Timer interprets zero as 65, 536 • So the frequency of the output-pulses from Timer-channel 0 is equal to this quotient: output-frequency = input-frequency / frequency-divisor = 1193182 / 65536 (approximately 18. 2)

Consequently… • To compute ‘total_seconds’ from ‘total_ticks’: total_seconds = total_ticks / ticks_per_second = total_ticks

Consequently… • To compute ‘total_seconds’ from ‘total_ticks’: total_seconds = total_ticks / ticks_per_second = total_ticks / (1193182 / 65536) = ( total_ticks * 65536 ) / 1193183 • We can use the Pentium’s integer-arithmetic instructions MUL (multiply) and DIV (divide)

How ‘MUL’ works Before executing the MUL instruction… EAX reg (or mem) multiplicand (32

How ‘MUL’ works Before executing the MUL instruction… EAX reg (or mem) multiplicand (32 -bits) multiplier (32 -bits) 32 -bit operands Here’s the instruction… mull reg_or_mem After executing the MUL instruction… EDX EAX 64 -bit product (64 -bits)

How ‘DIV’ works Before executing the DIV instruction… EDX EAX dividend (64 -bits) 64

How ‘DIV’ works Before executing the DIV instruction… EDX EAX dividend (64 -bits) 64 -bit dividend reg (or mem) divisor (32 -bits) 32 -bit operand Here’s the instruction… divl reg_or_mem After executing the DIV instruction… EDX EAX 32 -bit remainder 32 -bit quotient two results (32 -bits)

Implementing the conversion • So use MUL and DIV to convert ‘ticks’ into ‘seconds’,

Implementing the conversion • So use MUL and DIV to convert ‘ticks’ into ‘seconds’, like this: # total_seconds = ( total_ticks * FREQ_DIVISOR ) / PULSES_PER_SEC mov mul mov div mov total_ticks, %eax $FREQ_DIVISOR, %ecx $PULSES_PER_SEC, %ecx %eax, total_seconds # Now integer-quotient is in EAX, and integer-remainder is in EDX

‘Time-Of-Day’ Format HH: MM: SS am/pm hours seconds minutes morning or afternoon So we

‘Time-Of-Day’ Format HH: MM: SS am/pm hours seconds minutes morning or afternoon So we need to compute four numerical values from the ‘total_seconds’ integer

Our four time-parameters We use these arithmetical ideas: – total_minutes = ( total_seconds /

Our four time-parameters We use these arithmetical ideas: – total_minutes = ( total_seconds / 60 ); ss = ( total_seconds % 60 ); – total_hours = (total_minutes / 60 ); mm = ( total_minutes % 60 ); – total_halfdays = (total_hours / 12 ); hh = (total_hours % 12 ); – Total_days = ( total_halfdays / 2 ); xm = total_halfdays % 2;

A subtle refinement • Our ‘total_seconds’ value was gotten with an integer-division operation, so

A subtle refinement • Our ‘total_seconds’ value was gotten with an integer-division operation, so there’s likely to be some ‘round-off’ error • How can we be sure we use the ‘closest’ integer to the actual quotient? • We should remember the ‘rounding’ rule! • When ‘remainder’ is equal or greater than 1/2 of ‘divisor’, ‘quotient’ gets incremented

How to implement rounding? • There is more than one way to do it

How to implement rounding? • There is more than one way to do it – i. e. , the “amateur’s” way or the “expert’s” way • Knowledge of the Pentium’s architecture and instruction-set can assist • The ‘obvious’ method: • if ( 2 * remainder >= divisor ) ++quotient; • But this uses a multiply and a conditional jump-instruction (inefficient!)

Avoiding inefficiency… • Replace the ‘multiply’ with an ‘addition’ • Use ‘subtract’ and ‘add-with-carry’

Avoiding inefficiency… • Replace the ‘multiply’ with an ‘addition’ • Use ‘subtract’ and ‘add-with-carry’ instead of using ‘compare’ and ‘conditionally-jump’ # Recall: quotient was in EAX, remainder was in EDX, divisor was in ECX add %edx, %edx # doubles the remainder sub %ecx, %edx # computes: 2*quotient – divisor # now carry-flag is clear in case 2*quotient >= divisor cmc # complement the carry-flag bit # now carry-flag is set in case 2*quotient >= divisor adc $0, %eax # add the carry-flag to the quotient # So this achieves the same effect as the ‘rounding rule’, but wit no jump!

In-class exercise • Can you enhance our ‘timeoday. s’ demo to make it more

In-class exercise • Can you enhance our ‘timeoday. s’ demo to make it more dramatic (and later useful) by creating a loop within its ‘main’ routine, so it continues to read and display the time (until the user presses a key) • HINTS: Use an INT-0 x 16 keyboard service to ‘peek’ into the keyboard-queue, and omit the ‘n’ (newline) control-code from the ‘report’ message-string