; CPU_TIME.INC
;*************************************************************************
;*                                                                       *
;* Author...: Oli(ver Sellke)                 D-65199 Wiesbaden          *
;* auf AS umgestellt von Alfred Arnold, Oktober 1993                     *
;* die Low-Level-Ausgaberoutinen sind nach CONOUT.INC verlagert          *
;* Date.....: 14 Okt 1993                     Version..: 1.0             *
;* Target...: TLCS900-Family (TOSHIBA)        Compiler.: AS      V1.39p1 *
;* Project..: General Purpose / e.g. TMP96C141F / Watt Ihr Volt          *
;*                                                                       *
;* Function.: Mit dieser Routine kann man die Ausfuehrungszeit die       *
;*            ein Programm(teil) benoetigt ermitteln.                    *
;*            Die Zeit wird mit Timer4 und CAP1 davon gemessen, d.h.     *
;*            dieser darf innerhalb des gemessenen Programm(teil)s       *
;*            nicht (!) benutzt werden.                                  *
;*            !!! Alle Zeiten beziehen sich auf einen 14,7456MHz Quarz!! *
;*            Zur Ausgabe des Messwertes werden Monitor-Routinen benutzt,*
;*            deshalb kann es auch nur unter Anwendung von diesem zur    *
;*            Ausfuehrung gebracht werden.                               *
;*            Wenn ein Programm(teil) getestet wird, dessen Ausfuehrungs-*
;*            zeit unbekannt ist, sollte man die 8,681us Aufloesung waehlen *
;*            um einen Overrun des Counters zu verhindern. Wenn der Wert *
;*            entsprechend klein ist ( <0FFF ), kann man die 0,543us Auf-*
;*            loesung waehlen um genauere Werte zu bekommen.             *
;*            Ausserdem ist die Ermittlung der 16 groessten und 16 kleinsten *
;*            Werte die bei mehreren Durchlaeufen erzielt wurden moeglich! *
;*            Man kann so einige 1000 Durchlaeufe fahren mit immer unter- *
;*            schiedlichen Randbedingungen auf die der zu testende Pro-  *
;*            teil entsprechend reagiert und auch Zeit benoetigt.        *
;*            So hat man sicher die minimale und maximale Laufzeit.      *
;*                                                                       *
;*            Bei allgemeiner Verwendung:                                *
;*            Max.Meáwert=0FFFFH =  35.585us bei 0,543us Aufloesung      *
;*            Max.Meáwert=0FFFFH = 568.909us bei 8,681us Aufloesung      *
;*                                                                       *
;* Hardware.: getested auf Micro-ICE TLCS900 mit 14,7456MHz Quarz !!!!   *
;*                                                                       *
;*  Routine      Funktion           Ausgabe             Stack            *
;*                                                                       *
;*  CPU_TI_INI   Initialisierung    ------              6 Byte           *
;*  CPU_TIME     Uhr starten        ------              0 Byte           *
;*  CPU_STOP     Uhr stoppen        Zeit+Statistik      8 Byte           *
;*                                                                       *
;*  - Der Prozessor muss sich im Maximum-Modus befinden                  *
;*  - Symbol BigTime definieren fuer groessere Aufloesung                *
;*  - Da die Routinen lokale Labels verwenden, ist mindestens AS 1.39    *
;*    erforderlich                                                       *
;*  - MACROS.INC muss vorher, CONOUT.INC irgendwo eingebunden werden     *
;*************************************************************************

;-------------------------------------------------------------------------
; gemeinsamer Anfang, Definitionen

                section Timer

TRUN            EQU   020H
CAP1L           EQU   034H
CAP1H           EQU   035H
T4MOD           EQU   038H

CR              EQU    0DH
LF              EQU    0AH

                ifdef  BigTime
Overhead         equ    1               ; Eigenverbrauch Start/Stop
                elseif
Overhead         equ    9
                endif

CPU_TI_FAA      db    40h dup (?)       ; FeldAnfangsAdresse, ab hier wer-
                                        ; den 40H (64) RAM-Zellen benoetigt
                                        ; gleich 2 * 16 Worte
CPU_TI_CR       dd    ?                 ; CPU_TIME-Control-Register,
                                        ; wird noch nicht benoetigt!!!

;*************************************************************************
;Dieser Aufruf gehoert in den Initialisierungsbereich des zu testenden
;Programmabschnittes!!

                proc    CPU_TI_INI

;Hier werden die Feldwerte initialisiert..

                PUSH    XDE             ;Wird gleich benutzt
                PUSH    BC              ;Wird gleich benutzt
                LD      B,10H           ;16 Woerter fuer Max.Werte werden gebraucht
                LD      XDE,CPU_TI_FAA  ;FeldAnfangsAdresse laden
CPU_TI_INI1:    LDW     (XDE),00000H    ;Feldzelle fuer Max.Werte initalisieren
                INC     2,XDE           ;naechste Max.Wert-Feldzelle
                                        ;adressieren
                DJNZ    CPU_TI_INI1     ;Alle Max.Werte initialisiert?
                LD      B,10H           ;16 Woerter fuer Min.Werte werden gebraucht
CPU_TI_INI2:    LDW     (XDE),0FFFFH    ;Feldzelle fuer Min.Werte initalisieren
                INC     2,XDE           ;naechste Max.Wert-Feldzelle
                                        ;adressieren
                DJNZ    CPU_TI_INI2     ;Alle Min.Werte initialisiert?
                POP     BC              ;Und wieder restaurieren
                POP     XDE             ;hier auch...
                RET                     ;Zurueck zum Aufruf!
                endp

;*************************************************************************
; Uhr starten

                proc    CPU_TIME

                                          ;Timer4 CPU-Time-Messung vorbereiten
                RES     4,(TRUN)          ;Timer4 stop and clear !
                ifdef   BigTime
                 LD      (T4MOD),00100011B ;Bit 0+1:Source-Clock: 8,681æs
                elseif
                 LD      (T4MOD),00100001B ;Bit 0+1:Source-Clock: 0,543æs
                endif
                                          ;Bit 2  :clear from TREG5 disabled
                                          ;Bit 3+4:INT-Capture disabled
                                          ;Bit 5  :No Sw. capture now
                SET     4,(TRUN)          ;Timer4 start and count !
                RET
                endp

;*************************************************************************

                proc    CPU_STOP

                RES     5,(T4MOD)         ;Capture1 grabs count
                CALL    CPU_TI_SOUT       ;Einzelausgabe des gemessenen Wertes
                CALL    CPU_TI_SOR        ;gemessenen Wert ins Feld sortieren
                RET                       ;Zurueck zum Aufruf!
                endp

;*************************************************************************
;Hier wird der gerade gemessene Wert ausgegeben. Diese Ausgabe ist 
;ausreichend um Laufzeitwerte von statischen Programmabschnitten
;zu ermitteln (keine Verzweigungen im Programmabschnitt).

CPU_TI_SOUT:    PUSH    A                 ; needed little later
                PUSH    F                 ; needed little later
                push    bc                ; needed little later
                ld      wa,(cap1l)        ; gemessener Wert
                call    WriteTime
                pop     bc                ; back to the roots ...
                POP     F 
                POP     A
                RET                       ; Zurueck zum Aufruf!

;*************************************************************************
;Hier werden die ermittelten Werte sortiert abgelegt!
;Jeweils am Feldanfang steht der groesste und der kleinste Wert.
;Falls ein Wert einem anderen im Feld entspricht (gleicher Messwert)
;wird dieser nicht nochmal eingetragen!!!! 
;!!Achtung diese Routine benoetigt max. 145æs (14,7456MHz Quarz) 
;  im worst case!! Aber nur wenn Daten und Code 16Bit breit sind 
;  und keine Waitstates zugeschaltet sind (Micro-ICE TLCS900 default RAM)!

CPU_TI_SOR:     PUSH    HL              ;Wird gleich benutzt
                PUSH    BC              ;Wird gleich benutzt
                PUSH    XDE             ;Wird gleich benutzt
                                        ;Max.Werte sortiert ablegen!!!
                LD      B,10H           ;16 Woerter enthaelt Max.Wert-Feld
                LD      HL,(CAP1L)      ;gemessenen Wert aus Capture-Reg. holen
                LD      XDE,CPU_TI_FAA  ;erste Max.Wert-Feldzelle adressieren
CPU_TI_SOR1:    CP      HL,(XDE)        ;Wert mit Feldinhalt vergleichen
                JR      ULT,CPU_TI_SOR2 ;Ist Wert kleiner als Feldinhalt?
                JR      Z,CPU_TI_SOR3   ;Ist Wert gleich Feldinhalt? Abbrechen!
                EX      (XDE),HL        ;Nein-->Wert mit Feldinhalt tauschen!
CPU_TI_SOR2:    INC     2,XDE           ;naechste Feldzelle adressieren
                DJNZ    B,CPU_TI_SOR1   ;Alle 16 Max.Werte kontrolliert?
                                        ;Min.Werte sortiert ablegen!!!
CPU_TI_SOR3:    LD      B,10H           ;16 Woerter enthaelt Min.Wert-Feld
                LD      HL,(CAP1L)      ;gemessenen Wert aus Capture-Reg. holen
                LD      XDE,CPU_TI_FAA+20H ;erste Min.Wert-Feldzelle adressieren
CPU_TI_SOR4:    CP      HL,(XDE)        ;Wert mit Feldinhalt vergleichen
                JR      UGT,CPU_TI_SOR5 ;Ist Wert groesser als Feldinhalt?
                JR      Z,CPU_TI_SOR6   ;Ist Wert gleich Feldinhalt? Abbrechen!
                EX      (XDE),HL        ;Nein-->Wert mit Feldinhalt tauschen!
CPU_TI_SOR5:    INC     2,XDE           ;naechste Feldzelle adressieren
                DJNZ    B,CPU_TI_SOR4   ;Alle 16 Min.Werte kontrolliert?
CPU_TI_SOR6:    POP     XDE             ;Und wieder restaurieren
                POP     BC              ;wieder restaurieren
                POP     HL              ;hier auch...
                RET                     ;Zurueck zum Aufruf!

;*************************************************************************
;Hier werden die im Feld abgelegten Werte ausgeben. 

CPU_TI_MOUT:                            ;Muss noch geschrieben werden!
                RET                     ;Zurueck zum Aufruf!

;*************************************************************************
; eine Zeitdifferenz in WA umrechnen und ausgeben
; wegen der Aufloesung der Timer ist die letzte Stelle hinter dem Komma
; bei hoher Aufloesung mit Vorsicht zu geniessen

WriteTime:      push    xwa             ; Register retten
                push    bc
                sub     wa,Overhead     ; Zeit korrigieren
                ifdef   BigTime         ; Fall 1: niedrige Aufloesung
                 mul    xwa,8681        ; -->Nanos in XWA
                 add    xwa,5000        ; !!Rundung!!
                 div    xwa,10000       ; Nanos , einzelne Mikros wegschmeiáen
                 extz   xwa
                 div    xwa,100         ; Millisekunden in WA
                 ld     bc,2003h        ; ausgeben
                 call   WriteDec
                 ld     a,'.'
                 call   CONOUT
                 ld     wa,qwa          ; auf 10 us genau ausgeben
                 ld     bc,3002h
                 call   WriteDec
                 call   PSTR
                 db     " Milli",StrTerm
                elseif                  ; Fall 2: hohe Aufloesung
                 mul    xwa,543         ; -->Nanosekunden in XWA
                 div    xwa,1000        ; -->Nanos in QWA, Mikros in WA
                 ld     bc,2005h        ; Mikros 5-stellig mit Blanks
                 call   WriteDec
                 ld     a,'.'
                 call   CONOUT
                 ld     wa,qwa          ; Nanos einstellig
                 add    wa,50           ; Rundung
                 extz   xwa
                 div    xwa,100         ; Ergebnis 0..9
                 cp     wa,10
                 jr     ne,NoErr
                 ld     wa,9
NoErr:           ld     bc,3001h        ; einstellig ausgeben
                 call   WriteDec
                 call   PSTR
                 db     " Mikro",StrTerm
                endif
                call    PSTR
                db      "sekunden",StrTerm ; gemeinsamer Rest
                pop     bc              ; Register zurueck
                pop     xwa
                ret

;*************************************************************************
; gemeinsames Ende

                endsection
