; Copyright 2003 Tematic Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
;==============================================================================
;
; Macro definitions
; =================
;
;------------------------------------------------------------------------------
;
        MACRO
        MySWI   $swiname
        ASSERT  SCSI_SWIbase+(.-SCSI_SWItable)/4 = $swiname
        B       SWI_$swiname
        MEND
;
;
;------------------------------------------------------------------------------
;
        MACRO
        MyEntry $entryname
;        ASSERT  SCSI_SWIbase+(.-SCSI_SWItable)/4 = $swiname
        B       Entry_$swiname
        MEND
;
;
;------------------------------------------------------------------------------
;
        MACRO
        AddressCard
        ASSERT (:INDEX:PODULEptr)=4
        ASSERT (:INDEX:DMACptr)=8

        BL DoAddressCard
       ;LDMIB WsPtr,{rPODULEptr,rDMACptr}       ;>>>do this here???
        MEND
;
;
;------------------------------------------------------------------------------
;
        MACRO
        ForEachCard $routinename
        mess ,"ForEachCard - Entry", NL
        ADRL R6,$routinename
        BL DoForEachCard
        mess ,"ForEachCard - Exit", NL
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro rdSBIC - read contents of a SBIC register
; eg rdSBIC R0,SR_Control
;
        MACRO
$label  rdSBIC   $arm, $sbic, $cc
$label  MOV$cc   $arm, #$sbic
        STR$cc.B $arm, SBICaddress
        LDR$cc.B $arm, SBICindirect
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro wrSBIC - write to SBIC register
; eg wrSBIC R0,SR_OwnID
;
; N.B. corrupts R14 (Link)
;
        MACRO
$label  wrSBIC   $arm, $sbic, $cc
$label  MOV$cc   R14,  #$sbic
        STR$cc.B R14,  SBICaddress
        STR$cc.B $arm, SBICindirect
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro rdSBIC24 - read 24bits from SBIC
; eg rdSBIC24 R0,SR_Count
;
; N.B. corrupts R14 (Link)
;
        MACRO
$label  rdSBIC24 $arm, $sbic, $cc
$label  MOV$cc   R14, #$sbic.Hi
        STR$cc.B R14, SBICaddress
        LDR$cc.B $arm, SBICindirect
        LDR$cc.B R14, SBICindirect
        ORR$cc $arm,R14,$arm,LSL #8     ;0000HHMM
        LDR$cc.B R14, SBICindirect
        ORR$cc $arm,R14,$arm,LSL #8     ;00HHMMLL
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro wrSBIC24 - write 24bits to SBIC
; eg wrSBIC24 R0,SR_Count       ;Write to SR_CountHi,SR_CountMd,SR_CountLo
;
; N.B. corrupts R14 (Link)
;
        MACRO
$label  wrSBIC24   $arm, $sbic, $cc
$label  MOV$cc   R14,  #$sbic.Hi
        STR$cc.B R14,  SBICaddress
        MOV$cc $arm,$arm,ROR #16        ;xxHHmmll->mmllxxHH
        STR$cc.B $arm, SBICindirect
        MOV$cc $arm,$arm,ROR #24        ;MMllxxhh->llxxhhMM
        STR$cc.B $arm, SBICindirect
        MOV$cc $arm,$arm,ROR #24        ;LLxxhhmm->xxhhmmLL
        STR$cc.B $arm, SBICindirect
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro wrDMAC - write to DMAC register
; eg wrDMAC R0,DR_Channel, VC
;
        MACRO
$label  wrDMAC $arm, $dmac, $cc
$label  STR$cc.B $arm, $dmac
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro rdDMAC - read contents of a DMAC register
; eg rdDMAC R0,DR_Channel, VC
;
        MACRO
$label  rdDMAC $arm, $dmac, $cc
$label  LDR$cc.B $arm, $dmac
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro wrPageReg - write to page register (& soft copy)
;
        MACRO
$label  wrPageReg $arm, $cc
$label  STR$cc.B $arm,PR_PageReg
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro JoinHWords
;
        MACRO
$label  InitJoinMask $mask
$label  MOV $mask,      #&00FF0000
        ORR $mask,$mask,#&FF000000
        MEND

        MACRO
$label  JoinHWords $dst,$lo,$hi,$mask
 [ "$mask"=""
$label  BIC $lo,$lo,#&00FF0000
        BIC $lo,$lo,#&FF000000
 |
$label  BIC $lo,$lo,$mask
 ]
        ORR $dst,$lo,$hi,LSL #16
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro SplitWord
;
        MACRO
$label  SplitWord $lo,$hi
$label  MOV $lo,$hi,LSL #16
        MOV $hi,$hi,LSR #16
        ORR $lo,$lo,$lo,ROR #16
        ORR $hi,$hi,$hi,ROR #16
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro RevBytes - reverse the bytes in a register
;
        MACRO
$label  RevBytes $arm, $t1,$t2, $succ
 [ "$label" <> "" :LOR: "$succ" = ""
$label  MVN $t1,#&FF00          ;a3=&FFFF00FF
 ]
        EOR $t2,$arm,$arm,ROR #16
        AND $t2,$t1,$t2,LSR #8
        EOR $arm,$t2,$arm,ROR #8
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro EnableIRQs - enable IRQ's
;
; User is in SVC_mode with IRQs (en/dis)abled or in IRQ_mode with IRQs disabled
;
        MACRO
$label  EnableIRQs
 [ No32bitCode
$label  BIC Link,Link,#I_bit
        TEQP PC,Link            ;Preserve SVC_mode/IRQ_mode, enable IRQs
        NOP
 |
$label  EnableIRQs2 Link
 ]
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro DisableIRQs - disable IRQ's
;
; User is in SVC_mode with IRQs (en/dis)abled or in IRQ_mode with IRQs disabled
;
        MACRO
$label  DisableIRQs
 [ No32bitCode
$label  ORR Link,Link,#I_bit
        TEQP PC,Link            ;Preserve SVC_mode/IRQ_mode, disable IRQs
        NOP
 |
$label  EnableIRQs2 Link
 ]
        MEND
;
;
;------------------------------------------------------------------------------


;------------------------------------------------------------------------------
;
; Macro EnableIRQs2 - enable IRQs
;
; User is in SVC_mode or IRQ_mode
;
        MACRO
$label  EnableIRQs2 $t1
 [ No32bitCode
$label  MOV $t1,PC
        BIC $t1,$t1,#I_bit
        TEQP PC,$t1             ;Preserve SVC_mode/IRQ_mode, enable IRQs
        NOP
 |
$label  MRS $t1,CPSR
        BIC $t1,$t1,#I32_bit
        MSR CPSR_c,$t1
 ]
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macro DisableIRQs2 - disable IRQs
;
; User is in SVC_mode or IRQ_mode
;
        MACRO
$label  DisableIRQs2 $t1
 [ No32bitCode
$label  MOV $t1,PC
        ORR $t1,$t1,#I_bit
        TEQP PC,$t1             ;Preserve SVC_mode/IRQ_mode, disable IRQs
        NOP
 |
$label  MRS $t1,CPSR
        ORR $t1,$t1,#I32_bit
        MSR CPSR_c,$t1
 ]
        MEND
;
;
;------------------------------------------------------------------------------
;
; Macros to handle either returning error pointers or error numbers

        MACRO
        XSCSIError $err
 [ soft
        MOV     R0, #ErrorNumber_$err-SCSI_ErrorBase
        SETV
 |
        XError  $err
 ]
        MEND

        MACRO
        MakeSCSIErrorBlock $err
 [ :LNOT:soft
        MakeErrorBlock $err
 ]
        MEND

        MACRO
        SCSIError $err, $cond, $l
 [ soft
        MOV$cond R0, #ErrorNumber_$err-SCSI_ErrorBase
 |
        ADR$cond.$l R0, ErrorBlock_$err
 ]
        MEND

;------------------------------------------------------------------------------


;===========================================================================

; Macro to separate a 32-bit value in a register into its two 16-bit halves.

        MACRO
$label  Split16 $resh,$resl,$src
        ASSERT  $resh <> $src
$label  MOV     $resh,$src,LSR #16
        BIC     $resl,$src,$resh,LSL #16
        MEND

;===========================================================================

; Macro to do a (16,16)x32 -> 64 multiplication. Done by breaking it up into
; four 16x16 multiplications and recombining the pieces. (N.B. The trick
; described in Knuth section 4.3.3 for reducing the four multiplications to
; three plus some additions and sign manipulations is not profitable at this
; size: it only becomes profitable when trying to synthesise a 64x64
; multiplication out of 32x32 multiplications.)
;   Also allows the flags to be set on the high word of the result and an
; optional addend to be added into the high word of the result: however,
; combining these does *not* result in the C flag being set correctly for
; the carry-out from the notional addition of the addend and the high word.
; Only the Z and N flags have meaningful values.
;   The operands are:
; $resh,$resl: Registers that will receive the 64-bit product;
; $op1h,$op1l: Registers containing the high and low 16 bits of the first
;              32-bit operand;
; $op2:        Register containing the second 32-bit operand;
; $add:        If present, register containing the addend;
; $s:          "S" to set the condition codes;
; $t1,$t2,$t3: Three temporary registers required during the calculation.
; The restrictions on which registers may be the same are complicated and
; are detailed in the ASSERT statements below.

        MACRO
$label  Mul64   $resh,$resl,$op1h,$op1l,$op2,$add,$s,$t1,$t2,$t3
        ASSERT  $resh <> $resl
        ASSERT  $resl <> $op1h
        ASSERT  $resl <> $t1
        ASSERT  $resl <> $t2
        ASSERT  $resl <> $t3
        ASSERT  $op1h <> $op1l
        ASSERT  $op1h <> $op2
        ASSERT  $op1h <> $t1
        ASSERT  $op1h <> $t2
        ASSERT  $op1h <> $t3
        ASSERT  $op1l <> $op2
        ASSERT  $op1l <> $t1
        ASSERT  $op1l <> $t2
        ASSERT  $op1l <> $t3
        ASSERT  $op2  <> $t1
        ASSERT  $t1   <> $t2
        ASSERT  $t1   <> $t3
        ASSERT  $t2   <> $t3
$label  Split16 $t1,$t2,$op2            ;t1 := op2h, t2 := op2l
        [ "$add" <> ""
          ASSERT  $add <> $op1h
          ASSERT  $add <> $op1l
          ASSERT  $add <> $op2
          ASSERT  $add <> $t1
          ASSERT  $add <> $t2
          MLA     $t3,$op1h,$t1,$add      ;t3 := op1h * op2h + add
        |
          MUL     $t3,$op1h,$t1           ;t3 := op1h * op2h
        ]
        MUL     $t1,$op1l,$t1           ;t1 := op1l * op2h
        MUL     $resl,$t2,$op1l         ;resl := op1l * op2l
        ADDS    $resl,$resl,$t1,LSL #16 ;Add op1l * op2h into (t3,resl)
        ADC     $t3,$t3,$t1,LSR #16
        MUL     $t2,$op1h,$t2           ;t2 := op1h * op2l
        ADDS    $resl,$resl,$t2,LSL #16 ;Add op1h * op2l into (t3,resl)
        ADC$s   $resh,$t3,$t2,LSR #16   ; to produce (resh,resl)
        MEND

;------------------------------------------------------------------------------
;
; Macro mess - print a debugging message
;
        MACRO
        mess    $cond,$s1,$s2,$s3,$s4,$s5
 [ trace
        B$cond  %F11
        BAL     %F21
11
        Push    "LR"
        SWI     OS_WriteS
 [ "$s1"="NL"
 = CR,LF
 |
 = "ScsiDriver: $s1"
 ]
 [ "$s2"=""
 |
  [ "$s2"="NL"
  = CR,LF
  |
  = "$s2"
  ]
  [ "$s3"=""
  |
   [ "$s3"="NL"
   = CR,LF
   |
   = "$s3"
   ]
   [ "$s4"=""
   |
    [ "$s4"="NL"
    = CR,LF
    |
    = "$s4"
    ]
    [ "$s5"=""
    |
     [ "$s5"="NL"
     = CR,LF
     |
     = "$s5"
     ]
    ]
   ]
  ]
 ]
        =       0
        ALIGN
        Pull    "LR"
21
 ]
        MEND


        MACRO
        traceswi $s1
        mess , "SWI_SCSI_$s1", NL
        MEND


        MACRO
        tracerc $s1
        mess , "   $s1", NL
        MEND

        MACRO
        trhex $reg
 [ trace
        Push    "R0-R2"
        MOV     R0, $reg
        ADR     R1, MyStringBuff2
        MOV     R2, #16
        SWI     OS_ConvertHex8
        SWI     OS_Write0
        Pull    "R0-R2"
 ]
        MEND

        MACRO
        trstr $str, $nl
 [ trace
        SWI     OS_WriteS
        = "$str", 0
        ALIGN
  [ "$nl" <> ""
        trnl
  ]
 ]
        MEND

        MACRO
        trnl
 [ trace
        SWI     OS_NewLine
 ]
        MEND

;
;
;==============================================================================

        END