Index: /trunk/Assembly_Library/Inc/AssemblyLibrary.inc
===================================================================
--- /trunk/Assembly_Library/Inc/AssemblyLibrary.inc	(revision 255)
+++ /trunk/Assembly_Library/Inc/AssemblyLibrary.inc	(revision 256)
@@ -16,4 +16,6 @@
 %include "Math.inc"
 %include "Registers.inc"
+%include "SystemTimer.inc"
+
 
 ; Library dependencies
Index: /trunk/Assembly_Library/Inc/SystemTimer.inc
===================================================================
--- /trunk/Assembly_Library/Inc/SystemTimer.inc	(revision 256)
+++ /trunk/Assembly_Library/Inc/SystemTimer.inc	(revision 256)
@@ -0,0 +1,183 @@
+; Project name	:	Assembly Library
+; Description	:	System Timer (8254) relates equates and macros.
+%ifndef SYSTEMTIMER_INC
+%define SYSTEMTIMER_INC
+
+; Timer/Counter to program
+TIMER_0									EQU	(0<<6)
+TIMER_1									EQU	(1<<6)
+TIMER_2									EQU	(2<<6)
+
+; Counter commands
+LATCH									EQU	(0<<4)	; Counter Latch Command (latches the count for reading)
+READ_OR_WRITE_LSB_ONLY					EQU	(1<<4)	; MSB is always zero
+READ_OR_WRITE_MSB_ONLY					EQU	(2<<4)	; LSB is always zero
+READ_OR_WRITE_LSB_THEN_MSB				EQU	(3<<4)
+
+; Timer modes
+MODE_0_SINGLE_TIMEOUT					EQU	(0<<1)	; Interrupt on Terminal Count
+MODE_1_ONE_SHOT							EQU	(1<<1)	; Hardware Retriggerable One-Shot
+MODE_2_RATE_GENERATOR					EQU	(2<<1)
+MODE_3_SQUARE_WAVE_MODE					EQU	(3<<1)
+MODE_4_SOFTWARE_TRIGGERED_STROBE		EQU	(4<<1)
+MODE_5_HARDWARE_RETRIGGERABLE_STROBE	EQU	(5<<1)
+
+; Binary / BCD Mode
+BINARY_COUNTER							EQU	0
+BCD_COUNTER								EQU	1
+
+
+; Ports
+COUNT_REGISTER_0						EQU	40h		; Timer 0 Count Register (System Timer Ticks)
+COUNT_REGISTER_1						EQU	41h		; Timer 1 Count Register (DRAM Refresh)
+COUNT_REGISTER_2						EQU	42h		; Timer 2 Count Register (General Use)
+CONTROL_WORD_REGISTER_out				EQU	43h
+
+; Timer 2 is Connected to PC Speaker that can be controller from port 61h.
+SPEAKER_CONTROL_REGISTER				EQU	61h
+FLG_TIMER_2_OUTPUT_in					EQU	(1<<5)	; AT+ only
+FLG_SPEAKER_DATA_ENABLED				EQU	(1<<1)
+FLG_SPEAKER_GATE_TIMER_2_ON				EQU	(1<<0)
+
+
+; The duration of one tick
+TIMER_CYCLE_TIME						EQU	838		; nanosecs
+
+
+
+
+;--------------------------------------------------------------------
+; OUTPUT_COUNTER_COMMAND_TO
+;	Parameters:
+;		%1:		TIMER_0, TIMER_1 or TIMER_2
+;		%2:		Command to counter
+;		%3:		Timer mode
+;		%4:		BINARY_COUNTER or BCD_COUNTER
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+%macro OUTPUT_COUNTER_COMMAND_TO 4
+	mov		al, %1 | %2 | %3 | %4
+	out		CONTROL_WORD_REGISTER_out, al
+%endmacro
+
+
+;--------------------------------------------------------------------
+; WRITE_COUNT_FROM_AL_TO
+; WRITE_COUNT_FROM_AX_TO
+;	Parameters:
+;		%1:		TIMER_0, TIMER_1 or TIMER_2
+;		AX:		Count to write to timer
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AL (WRITE_COUNT_FROM_AX_TO only)
+;--------------------------------------------------------------------
+%macro WRITE_COUNT_FROM_AL_TO 1
+	%ifidni %1, TIMER_0
+		out		COUNT_REGISTER_0, al
+	%elifidni %1, TIMER_1
+		out		COUNT_REGISTER_1, al
+	%elifidni %1, TIMER_2
+		out		COUNT_REGISTER_2, al
+	%else
+		%error "Invalid timer name passed to WRITE_COUNT_FROM_AL_TO"
+	%endif
+%endmacro
+
+%macro WRITE_COUNT_FROM_AX_TO 1
+	%ifidni %1, TIMER_0
+		out		COUNT_REGISTER_0, al
+		mov		al, ah
+		out		COUNT_REGISTER_0, al
+	%elifidni %1, TIMER_1
+		out		COUNT_REGISTER_1, al
+		mov		al, ah
+		out		COUNT_REGISTER_1, al
+	%elifidni %1, TIMER_2
+		out		COUNT_REGISTER_2, al
+		mov		al, ah
+		out		COUNT_REGISTER_2, al
+	%else
+		%error "Invalid timer name passed to WRITE_COUNT_FROM_AX_TO"
+	%endif
+%endmacro
+
+
+;--------------------------------------------------------------------
+; READ_COUNT_TO_AL_FROM
+; READ_COUNT_TO_AX_FROM
+;	Parameters:
+;		%1:		TIMER_0, TIMER_1 or TIMER_2
+;	Returns:
+;		AL/AX:	Counter value
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+%macro READ_COUNT_TO_AL_FROM 1
+	%ifidni %1, TIMER_0
+		in		al, COUNT_REGISTER_0
+	%elifidni %1, TIMER_1
+		in		al, COUNT_REGISTER_1
+	%elifidni %1, TIMER_2
+		in		al, COUNT_REGISTER_2
+	%else
+		%error "Invalid timer name passed to READ_COUNT_TO_AL_FROM"
+	%endif
+%endmacro
+
+%macro READ_COUNT_TO_AX_FROM 1
+	%ifidni %1, TIMER_0
+		in		al, COUNT_REGISTER_0
+		mov		ah, al
+		in		al, COUNT_REGISTER_0
+	%elifidni %1, TIMER_1
+		in		al, COUNT_REGISTER_1
+		mov		ah, al
+		in		al, COUNT_REGISTER_1
+	%elifidni %1, TIMER_2
+		in		al, COUNT_REGISTER_2
+		mov		ah, al
+		in		al, COUNT_REGISTER_2
+	%else
+		%error "Invalid timer name passed to READ_COUNT_TO_AX_FROM"
+	%endif
+		xchg	al, ah
+%endmacro
+
+
+;--------------------------------------------------------------------
+; START_PRECISE_EVENT_TIMER
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+%macro START_PRECISE_EVENT_TIMER 0
+	in		al, SPEAKER_CONTROL_REGISTER
+	or		al, FLG_SPEAKER_GATE_TIMER_2_ON
+	out		SPEAKER_CONTROL_REGISTER, al
+%endmacro
+
+
+;--------------------------------------------------------------------
+; STOP_PRECISE_EVENT_TIMER
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AL
+;--------------------------------------------------------------------
+%macro STOP_PRECISE_EVENT_TIMER 0
+	in		al, SPEAKER_CONTROL_REGISTER
+	and		al, ~(FLG_SPEAKER_DATA_ENABLED | FLG_SPEAKER_GATE_TIMER_2_ON)
+	out		SPEAKER_CONTROL_REGISTER, al
+%endmacro
+
+
+%endif ; SYSTEMTIMER_INC
Index: /trunk/Assembly_Library/Src/AssemblyLibrary.asm
===================================================================
--- /trunk/Assembly_Library/Src/AssemblyLibrary.asm	(revision 255)
+++ /trunk/Assembly_Library/Src/AssemblyLibrary.asm	(revision 256)
@@ -71,4 +71,5 @@
 	%ifndef EXCLUDE_FROM_XTIDE_UNIVERSAL_BIOS
 		%include "Delay.asm"
+		%include "SystemTimer.asm"
 	%endif
 	%include "TimerTicks.asm"
Index: /trunk/Assembly_Library/Src/Time/SystemTimer.asm
===================================================================
--- /trunk/Assembly_Library/Src/Time/SystemTimer.asm	(revision 256)
+++ /trunk/Assembly_Library/Src/Time/SystemTimer.asm	(revision 256)
@@ -0,0 +1,48 @@
+; Project name	:	Assembly Library
+; Description	:	Functions to operate with
+;					8254 Programmable Interval Timer.
+
+; Section containing code
+SECTION .text
+
+;--------------------------------------------------------------------
+; SystemTimer_IntializePreciseEventTimer
+;	Parameters:
+;		Nothing
+;	Returns:
+;		Nothing
+;	Corrupts registers:
+;		AX
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SystemTimer_IntializePreciseEventTimer:
+	STOP_PRECISE_EVENT_TIMER
+	OUTPUT_COUNTER_COMMAND_TO TIMER_2, READ_OR_WRITE_LSB_THEN_MSB, MODE_0_SINGLE_TIMEOUT, BINARY_COUNTER
+	xor		ax, ax
+	WRITE_COUNT_FROM_AX_TO TIMER_2
+	ret
+
+
+;--------------------------------------------------------------------
+; This is how to use precise event timer:
+; 1. Call SystemTimer_IntializePreciseEventTimer
+; 2. Use START_PRECISE_EVENT_TIMER macro to start timer
+; 3. Use STOP_PRECISE_EVENT_TIMER to stop timer (optional)
+; 4. Call SystemTimer_ReadNanosecsToDXAXfromPreciseEventTimer to get event duration
+;
+; SystemTimer_ReadNanosecsToDXAXfromPreciseEventTimer
+;	Parameters:
+;		Nothing
+;	Returns:
+;		DX:AX:	Event duration in nanosecs
+;	Corrupts registers:
+;		Nothing
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+SystemTimer_ReadNanosecsToDXAXfromPreciseEventTimer:
+	OUTPUT_COUNTER_COMMAND_TO TIMER_2, LATCH, MODE_0_SINGLE_TIMEOUT, BINARY_COUNTER
+	READ_COUNT_TO_AX_FROM TIMER_2
+	neg		ax					; 0 - count (Mode 0 counts toward zero)
+	mov		dx, TIMER_CYCLE_TIME
+	mul		dx
+	ret
Index: /trunk/Assembly_Library/Src/TimerTest.asm
===================================================================
--- /trunk/Assembly_Library/Src/TimerTest.asm	(revision 256)
+++ /trunk/Assembly_Library/Src/TimerTest.asm	(revision 256)
@@ -0,0 +1,70 @@
+; Project name	:	Assembly Library
+; Description	:	Tests for Assembly Library.
+
+; Include .inc files
+%define INCLUDE_DISPLAY_LIBRARY
+%define INCLUDE_TIME_LIBRARY
+%include "AssemblyLibrary.inc"	; Assembly Library. Must be included first!
+
+
+; Section containing code
+SECTION .text
+
+; Program first instruction.
+ORG	100h						; Code starts at offset 100h (DOS .COM)
+Start:
+	jmp		TimerTest_Start
+
+; Include library sources
+%include "AssemblyLibrary.asm"
+
+
+;--------------------------------------------------------------------
+; Program start
+;--------------------------------------------------------------------
+ALIGN JUMP_ALIGN
+TimerTest_Start:	
+	CALL_DISPLAY_LIBRARY InitializeDisplayContext
+
+	call	SystemTimer_IntializePreciseEventTimer
+
+	START_PRECISE_EVENT_TIMER
+	mov		ax, MICROSECONDS_TO_WAIT
+	call	Delay_MicrosecondsFromAX
+	STOP_PRECISE_EVENT_TIMER
+
+	call	SystemTimer_ReadNanosecsToDXAXfromPreciseEventTimer
+	call	PrintNanosecsFromDXAX
+
+	; Exit to DOS
+	mov 	ax, 4C00h			; Exit to DOS
+	int 	21h
+
+
+ALIGN JUMP_ALIGN
+PrintNanosecsFromDXAX:
+	mov		cx, 1000
+	div		cx					; AX = us waited
+	
+	mov		bp, sp
+	ePUSH_T	cx, MICROSECONDS_TO_WAIT
+	push	ax
+	mov		si, g_szMicrosecsWaited
+	CALL_DISPLAY_LIBRARY FormatNullTerminatedStringFromCSSI
+	ret
+
+
+
+; Section containing initialized data
+SECTION .data
+
+MICROSECONDS_TO_WAIT		EQU		7000
+
+g_szMicrosecsWaited:
+	db	"Was supposed to wait %u us but actually waited %u us.",LF,CR,NULL
+g_szDashForZero:		db		"- ",NULL
+
+
+
+; Section containing uninitialized data
+SECTION .bss
Index: /trunk/Assembly_Library/makefile
===================================================================
--- /trunk/Assembly_Library/makefile	(revision 255)
+++ /trunk/Assembly_Library/makefile	(revision 256)
@@ -19,5 +19,6 @@
 
 # Assembly source code file (*.asm):
-SRC_ASM = Src/LibraryTests.asm
+#SRC_ASM = Src/LibraryTests.asm
+SRC_ASM = Src/TimerTest.asm
 #SRC_ASM = Src/LibSizeCheck.asm
 
