; asmloops.s   02/08/23

; Copyright (c) 1991, 2002 Allegro Consultants, Inc.
; This source may be freely used only as part of the MIPSTEST program.
; For other uses, please contact info@allegro.com

      .SPACE  $TEXT$
      .SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
      .SUBSPA $CODE$

  .VERSION "asmloops.s  02/08/23"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; int32 asmloops_measure_blink (void);     /* returns # of ticks */

asmloops_measure_blink

      .PROC
      .ENTRY
      .EXPORT asmloops_measure_blink, ENTRY

         ; wait until we see a BIG delta in ITMR values...

      LDI         1000, 31             ; value we want to see > than
      LDI         0, 29
      MFCTL       16, 25               ; old_ITMR = itmr
L$0
      ADDI        1, 29, 29
      MFCTL       16, 1                ; get new_ITMR
      SUB         1, 25, 28            ; subtract old_ITMR
      COMB,>      31, 28, L$0          ; if 1000 > delta, loop
      COPY        1, 25                ; old_ITMR = new_ITMR

      BV          0 (2)
      NOP

      .CALLINFO
      .EXIT
      .PROCEND
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; int32 asmloops_measure_burp (void);     /* returns # of ticks */

asmloops_measure_burp

      .PROC
      .ENTRY
      .EXPORT asmloops_measure_burp, ENTRY

         ; wait until we see a BIG delta in ITMR values...

      LDI         1000, 31             ; value we want to see > than
      LDI         0, 29
      MFCTL       16, 25               ; old_ITMR = itmr
L$8
      MFCTL       16, 1                ; get new_ITMR
      SUB         1, 25, 28            ; subtract old_ITMR
      COMB,>      31, 28, L$8          ; if 1000 > delta, loop
      COPY        1, 25                ; old_ITMR = new_ITMR

         ; ok, we're at start of a burp...loop until we hit
         ; a blink, then return delta between ITMR right now
         ; (end-of-blink/start-of-burp and the ITMR
         ; at the start of the blink)

      COPY        1, 24       ; save start-of-burp ITMR in r24

L$9
      MFCTL       16, 1                ; get new_ITMR
      ADDI        1, 29, 29
      SUB         1, 25, 28            ; subtract old_ITMR
      COMB,>,N    31, 28, L$9          ; if 1000 > delta, loop
      COPY        1, 25                ; old_ITMR = new_ITMR

      BV          0 (2)
      SUB         25, 24, 28

      .CALLINFO
      .EXIT
      .PROCEND

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; double procedure asmloops (numloops);
;      value   numloops;
;      double  numloops;
;
; At entry, r26 = # instructions to execute (approx)
;    exit,  r28 = # instructions executed
;
; Goal: minimal loop, no consideraton of parallelism

asmloops
      .PROC
      .ENTRY
      .EXPORT asmloops,ENTRY

      LDI         4, 28                ; initialize # instructions done
      ADDI        -4, 26, 26           ; account for the extra instructions
L$1
      ADDIB,>     -2, 26, L$1
      ADDI        2, 28, 28            ; we've done 2 more instructions

      BV          0 (2)
      NOP

      .CALLINFO
      .EXIT
      .PROCEND
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; double procedure asmloops_nopar (numloops);
;      value   numloops;
;      double  numloops;
;
; At entry, r26 = # instructions to execute (approx)
;    exit,  r28 = # instructions executed
;
; Goal: do some instructions that can't be done in parallel
;
; Caller is expected to check ITMR before and after.
;
; This routine is structured in an manner designed to make the
; code be highly UN-parallelizable.  The goal is to execute
; one instruction per clock tick.
; Note: some CPUs manage to get execute about 16 instructions
; in 15 clock ticks when doing the loop below multiple times.

asmloops_nopar
      .PROC
      .ENTRY
      .EXPORT asmloops_nopar,ENTRY

      LDI         4, 28                ; initialize # instructions done
      ADDI        -4, 26, 26           ; account for the extra instructions
L$2                                    ; instruction count, approx
      ADDI,SV     1,28,28              ; 1
      ADDI,SV     1,28,28              ; 2
      ADDI,SV     1,28,28              ; 3
      ADDI,SV     1,28,28              ; 4
      ADDI,SV     1,28,28              ; 5
      ADDI,SV     1,28,28              ; 6
      ADDI,SV     1,28,28              ; 7
      ADDI,SV     1,28,28              ; 8
      ADDI,SV     1,28,28              ; 9
      ADDI,SV     1,28,28              ; 10
      ADDI,SV     1,28,28              ; 11
      ADDI,SV     1,28,28              ; 12
      ADDI,SV     1,28,28              ; 13
      ADDI,SV     1,28,28              ; 14
      ADDIB,>     -16, 26, L$2         ; 15
      ADDI,SV     2,28,28              ; 16  bundled with above ADDIB

      BV          0 (2)
      NOP

      .CALLINFO
      .EXIT
      .PROCEND
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; double procedure asmloops_nopar2 (numloops);
;      value   numloops;
;      double  numloops;
;
; At entry, r26 = # instructions to execute (approx)
;    exit,  r28 = # instructions executed
;
; Goal: do some instructions that can't be done in parallel

asmloops_nopar2
      .PROC
      .ENTRY
      .EXPORT asmloops_nopar2,ENTRY

      ADDI        4, 26, 28            ; initialize # instructions done
      ADDI        -4, 26, 26           ; account for the extra instructions
L$5
      B           .+4         ; 1 & 2
      B           .+4         ; 3 & 4
      B           .+4         ; 5 & 6
      NOP                     ; 7
      ADDIB,>     -9, 26, L$5 ; 8 & 9
      NOP

      BV          0 (2)
      NOP

      .CALLINFO
      .EXIT
      .PROCEND
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; double procedure asmloops_par (numloops);
;      value   numloops;
;      double  numloops;
;
; At entry, r26 = # instructions to execute (approx)
;    exit,  r28 = # instructions executed
;
; Goal: do some instructions that can be done in parallel

asmloops_par
      .PROC
      .ENTRY
      .EXPORT asmloops_par,ENTRY

      LDI         4, 28                ; initialize # instructions done
      ADDI        -4, 26, 26           ; account for the extra instructions
L$3
      ADD         1, 31, 1             ; 1
      ADDI        1, 28, 25            ; 2
      ADDI        2, 28, 24            ; 3
      ADDI        3, 28, 23            ; 4
      ADDI        1, 28, 25            ; 5
      ADDI        2, 28, 24            ; 6
      ADDI        3, 28, 23            ; 7
      ADDI        1, 28, 25            ; 8
      ADDIB,>     -10, 26, L$3         ; 9
      ADDI        10, 28, 28           ; 10;  we've done 10 instructions

      BV          0 (2)
      NOP

      .CALLINFO
      .EXIT
      .PROCEND
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

      .END
