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

22
Using the 8254 Timer- Counter Understanding the role of the system’s 8254 programmable Interval- Timer/Counter
  • date post

    19-Dec-2015
  • Category

    Documents

  • view

    229
  • download

    2

Transcript of Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable...

Page 1: 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

Page 2: 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– 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

Page 3: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

Where’s the ‘tick’ counter?

main memory

Interrupt Vector Table(for real-mode)

ROM-BIOS DATA AREA

tick_count0040:006C

0x00000

0x00400

0x00500

Number of timer-tick interrupts so far today (longword at 0x0046C)

Page 4: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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 0x046C (it’s in the ROM-BIOS DATA AREA)

• In real-mode, we can get it like this:

xor %ax, %ax # address segment zeromov %ax, %fs # using FS registermov %fs:0x046C, %eax # copy tick-count to EAXmov %eax, total_ticks # save in a local variable

segment-override prefix (segment used would be %ds)

Page 5: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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

Page 6: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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

Page 7: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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

Page 8: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

Three timer/counter ‘channels’

Channel 0

Channel 1

Channel 2

8254 PIT

8284PCLK

+5 V

CLK0

CLK1

CLK2

GATE0

GATE1

GATE2

OUT0

OUT1

OUT2

Interrupt IRQ0

DRAM refresh

speaker

Port 0x61, bit #0

Port 0x61, bit #1

AND

Port 0x61, bit #5

Port 0x61, bit #4

1193182 Hz

Page 9: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

Counter decrements when pulsed

OUT

CLK

GATE

LSB

STATUS

MSB

LSBMSB

LATCH REGISTER

COUNT REGISTER

TIMER/COUNTER CHANNEL

Page 10: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

8254 Command-Port

Channel-ID 00 = chn 0 01 = chn 1 10 = chn 2

Command-ID 00 = Latch 01 = LSB r/w 10 = MSB r/w 11 = LSB-MSB r/w

Output Mode 000 = one-shot level 001 = retriggerable 010 = rate-generator 011 = square-wave 100 = software strobe 101 = hardware strobe

Counting Mode 0 = binary 1 = BCD

7 6 5 4 3 2 1 0

CHANNEL OUTPUT MODECOMMANDbinary/ BCD

Commands are sent to the 8254 via io/port 0x43

Page 11: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

Programming a PIT channel

• Step 1: send command to PIT (port 0x43)

• Step 2: read or write the channel’s Latch – via port 0x40 for channel 0– via port 0x41 for channel 1– via port 0x42 for channel 2

Page 12: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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)

Page 13: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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)

Page 14: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

How ‘MUL’ works

EAX

reg (or mem)

EDX EAX

64-bit product

multiplicand (32-bits)

multiplier (32-bits)

Before executing the MUL instruction…

32-bit operands

After executing the MUL instruction…

product (64-bits)

mull reg_or_mem Here’s the instruction…

Page 15: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

How ‘DIV’ works

EDX EAX

64-bit dividend

Before executing the DIV instruction…

dividend (64-bits)

reg (or mem) divisor (32-bits)

32-bit operand

divl reg_or_mem Here’s the instruction…

EDX EAX

32-bit remainder

After executing the DIV instruction…

two results (32-bits)

32-bit quotient

Page 16: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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 total_ticks, %eaxmov $FREQ_DIVISOR, %ecxmul %ecxmov $PULSES_PER_SEC, %ecxdiv %ecxmov %eax, total_seconds

# Now integer-quotient is in EAX, and integer-remainder is in EDX

Page 17: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

‘Time-Of-Day’ Format

HH:MM:SS am/pm

hours

minutes

seconds morning or afternoon

So we need to compute four numerical values from the ‘total_seconds’ integer

Page 18: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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;

Page 19: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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

Page 20: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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!)

Page 21: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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 remaindersub %ecx, %edx # computes: 2*quotient – divisor # now carry-flag is clear in case 2*quotient >= divisorcmc # complement the carry-flag bit# now carry-flag is set in case 2*quotient >= divisoradc $0, %eax # add the carry-flag to the quotient

# So this achieves the same effect as the ‘rounding rule’, but wit no jump!

Page 22: Using the 8254 Timer-Counter Understanding the role of the system’s 8254 programmable Interval-Timer/Counter.

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-0x16 keyboard service to ‘peek’ into the keyboard-queue, and omit the ‘\n’ (newline) control-code from the ‘report’ message-string