Download presentation

1
**Using the 8254 Timer-Counter**

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

2
**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

3
**Where’s the ‘tick’ counter?**

main memory Number of timer-tick interrupts so far today (longword at 0x0046C) 0x00500 ROM-BIOS DATA AREA 0040:006C tick_count 0x00400 Interrupt Vector Table (for real-mode) 0x00000

4
**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 zero mov %ax, %fs # using FS register mov %fs:0x046C, %eax # copy tick-count to EAX mov %eax, total_ticks # save in a local variable segment-override prefix (segment used would be %ds)

5
**Converting ‘ticks’ to seconds**

total_ticks_today total_seconds_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

6
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

7
**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

8
**Three timer/counter ‘channels’**

8284 PCLK Hz CLK0 Channel 0 OUT0 Interrupt IRQ0 GATE0 Port 0x61, bit #4 CLK1 Channel 1 OUT1 DRAM refresh GATE1 Port 0x61, bit #5 CLK2 Channel 2 OUT2 GATE2 AND speaker Port 0x61, bit #0 8254 PIT +5 V Port 0x61, bit #1

9
**Counter decrements when pulsed**

COUNT REGISTER CLK MSB LSB OUT MSB LSB LATCH REGISTER GATE STATUS TIMER/COUNTER CHANNEL

10
**8254 Command-Port Commands are sent to the 8254 via io/port 0x43**

CHANNEL COMMAND OUTPUT MODE binary / BCD 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 Commands are sent to the 8254 via io/port 0x43

11
**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

12
**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 = / (approximately 18.2)

13
**Consequently… To compute ‘total_seconds’ from ‘total_ticks’:**

total_seconds = total_ticks / ticks_per_second = total_ticks / ( / 65536) = ( total_ticks * ) / We can use the Pentium’s integer-arithmetic instructions MUL (multiply) and DIV (divide)

14
**How ‘MUL’ works mull reg_or_mem Before executing the MUL instruction…**

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

15
**How ‘DIV’ works divl reg_or_mem Before executing the DIV instruction…**

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

16
**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, %eax mov $FREQ_DIVISOR, %ecx mul %ecx mov $PULSES_PER_SEC, %ecx div %ecx mov %eax, total_seconds # Now integer-quotient is in EAX, and integer-remainder is in EDX

17
**‘Time-Of-Day’ Format HH:MM:SS am/pm hours seconds morning or afternoon**

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

18
**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;

19
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

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

21
**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!

22
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

Similar presentations

© 2021 SlidePlayer.com Inc.

All rights reserved.

To make this website work, we log user data and share it with processors. To use this website, you must agree to our Privacy Policy, including cookie policy.

Ads by Google