; -> VTest-Head
;***************** ARM test software header file ****************
;
; For use with 32-bit Async ARMs 

 AREA ARMtest,READONLY,CODE

 OPT 2

CR    * 13
LF    * 10
TIMEC *  5
CTRLD *  4
PLING * 33
MAXINTR * &80000000

R0 RN 0
R1 RN 1
R2 RN 2
R3 RN 3
R4 RN 4
R5 RN 5
R6 RN 6
R7 RN 7
R8 RN 8
R9 RN 9
R10 RN 10
R11 RN 11
R12 RN 12
R13 RN 13
R14 RN 14
R15 RN 15
PC RN R15
PS RN R15

TubeAd * &C000 ; Address of Asim Tube model
IntrAd * &E000 ; Address of Asim Interrupter model

; Macro definition for PSR Transfer operations
;
; format of instances of this macro should be in the following form
;
;  MVP CPSR_all, R10
;  MVP CPSR_all, R10, LSL#, 10
;  MVP CPSR_all, R10, LSL, R10
;  MVP CPSR_all, #, 15
;  MVP CPSR_all, #, 15, ROR#, 10       
;  MVP R0, CPSR
;
; Note - CPSRall/CPSR_all, CPSRflg/CPSR_flg, CPSRctl/CPSR_ctl
;        are all acceptable as the destination register, and
;        similarly for SPSR variants                    
;      - CPSR and SPSR are the valid sources in the last example
;      - LSL#, LSR#, ASR#, ROR# indicate immediate shifts
;      - LSL, LSR, ASR, ROR indicate register specified shifts 
;      - the rotation amount specified in eg.5 _is_ divided by 2
;        before being put into the shift field.

 MACRO
$L MVP $dest, $src1, $src2, $src3, $src4
 [ (:LEN:"$dest") < 4
  [ ("$src1":LEFT:4 = "SPSR")
$L & (&E14F0000 :OR: ($dest:SHL:12))
   MEXIT   
  |
$L & (&E10F0000 :OR: ($dest:SHL:12))
   MEXIT
  ]
 |
  [ ("$dest":LEFT:4 /= "CPSR") :LAND: ("$dest":LEFT:4 /= "SPSR")
; The destination is a register
   [ ("$src1":LEFT:4 = "SPSR")
$L & (&E14F0000 :OR: ($dest:SHL:12))
    MEXIT   
   |
$L & (&E10F0000 :OR: ($dest:SHL:12))
    MEXIT
   ]
  ]
 ]
; The destination is CPSR or SPSR
 LCLA destbits
 [ ("$dest":LEFT:4 = "SPSR")
destbits SETA &00400000  ; destination is SPSR
 |
destbits SETA &00000000  ; destination is CPSR
 ]
 [ ("$dest":RIGHT:3 = "flg")
destbits SETA (destbits :OR: &00080000) ; set flags write enable
 |
  [ ("$dest":RIGHT:3 = "ctl")
destbits SETA (destbits :OR: &00010000) ; set ctrl write enable
  |
destbits SETA (destbits :OR: &00090000) ; set both write enables
  ]
 ]
; Have now dealt with the destination field
 LCLA op2bits
 [ "$src1" = "#"         ; Is it an immediate operand ?
  [ "$src4" = ""         ; No shift specified => 0 shift
op2bits SETA (&02000000 :OR: ($src2 :AND: 255))
  |
op2bits SETA (&02000000 :OR: ($src2 :AND: 255) :OR: ((($src4 /2) :AND: 15):SHL:8))
  ]
 |                       ; Its a register based operand
op2bits SETA $src1        ; Stuff in the source register
  [ "$src2" = ""         ; Not specified => LSL
op2bits SETA (op2bits :OR: &00000000)
  |
   [ "$src2":LEFT:3 = "LSL"
op2bits SETA (op2bits :OR: &00000000)
   |
    [ "$src2":LEFT:3 = "LSR"
op2bits SETA (op2bits :OR: &00000020)
    |
     [ "$src2":LEFT:3 = "ASR"
op2bits SETA (op2bits :OR: &00000040)
     |
op2bits SETA (op2bits :OR: &00000060)
     ]
    ]
   ]
  ]                      ; Now the shift type bits are in place
  [ "$src2" = ""         ; No shift amount => 0 shift
op2bits SETA (op2bits :OR: &000)
  |
   [ "$src2":RIGHT:1 = "#"
op2bits SETA (op2bits :OR: &000 :OR: (($src3 :AND: 31) :SHL: 7))
   |
op2bits SETA (op2bits :OR: &010 :OR: (($src3 :AND: 15) :SHL: 8))
   ]                     ; Now all the operand bits are in place
  ]
 ]
; All operand bits are now in place
$L & (&E120F000 :OR: destbits :OR: op2bits)
 MEND

 OPT 1+128

RESET   B MAIN
UNDEF   B TRAP2
SWI     B SWI_handler
ABORTA  B TRAP4
ABORTD  B TRAP5
ADDEX   B TRAP6
IRQ     B TRAP7
FIQ     B TRAP8

; Routine which prints string following calling instruction and returns
;          ***** Note: Condition codes NOT preserved *****
; Uses SWI 0 to print a ch. Not intended for use in SVC mode !
;
; On entry: R14 points to start of string
;
VSTRNG ROUT
 STR R1, R1temp
 BIC R1, R14, #&FC000003  ; Get rid of top bits (may not be necessary)
                          ; & move R14 to a safe register to allow SWI
                          ; from SVC mode
10
 LDRB R0,[R1],#1 ;get first character with auto increment to next
 CMPS R0,#1 ;test for a zero or one terminating character
 SWIHI 0 ;print if not
 BHI %B10 ;carry on printing if not
 BEQ %F20 ; no crlf if 1-terminated
 MOV R0,#CR
 SWI 0
 MOV R0,#LF
 SWI 0
20
; now we must word align
 TSTS R1,#3     ;test for 0 in last 2 bits
 ADDNE R1,R1,#4 ;if not a zero increment by a word
 BICNE R1,R1,#3 ;       and clear the bottom 2 bits
 MOV   R14,R1
 LDR R1, R1temp
 MOV PC, R14    ;return

R1temp
 & 0        ; Temporary register storage

; Routine which prints string following calling instruction and stops
MSG ROUT
 BIC R1, R14, #&FC000003  ; Get rid of top bits - may not be necessary
10
 LDRB R0,[R1],#1
 TEQS R0,#0
 SWINE 0
 BNE %B10
 MOV R0,#CR
 SWI 0
 MOV R0,#LF
 SWI 0
 MOV R0,#CTRLD ; Print a Control-D to halt Asim simulation (using Tube model)
 SWI 0

TRAP2 
 MOV	R1,#TubeAd
 MOV	R0,#PLING
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]
 MOV	R0,#50		; trap number 2
 STRB	R0,[R1]
 B	ERROR

TRAP4 
 MOV	R1,#TubeAd
 MOV	R0,#PLING
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]
 MOV	R0,#52		; trap number 4
 STRB	R0,[R1]
 B	ERROR

TRAP5 
 MOV	R1,#TubeAd
 MOV	R0,#PLING
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]
 MOV	R0,#53		; trap number 5
 STRB	R0,[R1]
 B	ERROR

TRAP6 
 MOV	R1,#TubeAd
 MOV	R0,#PLING
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]
 MOV	R0,#54		; trap number 6
 STRB	R0,[R1]
 B	ERROR

irqtmp0  & 0			; Temporary register storage
irqtmp1  & 0			; Temporary register storage
irqtmp2  & 0			; Temporary register storage
TRAP7 
 STR	R0,irqtmp0
 STR	R1,irqtmp1
 STR	R2,irqtmp2
 MOV	R1,#TubeAd
 MOV	R0,#PLING
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]
 MOV	R0,#55		; trap number 7
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]

 LDR	R2,[R7]
 CMP	R2,#0		; [sp] = 0 (free) ?
 BNE	nosem
 MOV	R2,#1		; if sem free grab it!
 STR	R2,[R7]
 MOV	R0,#115
 STRB	R0,[R1]
 MOV	R0,#101
 STRB	R0,[R1]
 MOV	R0,#109
 STRB	R0,[R1]
nosem
 MOV	R0,#CR
 STRB	R0,[R1]
 MOV	R0,#LF
 STRB	R0,[R1]
 MOV	R1,#IntrAd
 MOV	R0,#0
 STR	R0,[R1]		; clear NIQ interrupt
 LDR	R0,irqtmp0
 LDR	R1,irqtmp1
 LDR	R2,irqtmp2
 SUBS	PC,R14,#4	; return from interrupt

fiqtmp0  & 0			; Temporary register storage
fiqtmp1  & 0			; Temporary register storage
fiqtmp2  & 0			; Temporary register storage
TRAP8 
 STR	R0,fiqtmp0
 STR	R1,fiqtmp1
 STR	R2,fiqtmp2
 MOV	R1,#TubeAd
 MOV	R0,#PLING
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]
 MOV	R0,#56		; trap number 8
 STRB	R0,[R1]
 MOV	R0,#32		; print a space
 STRB	R0,[R1]

 LDR	R2,[R7]
 CMP	R2,#0		; [sp] = 0 (free) ?
 BNE	nosemF
 MOV	R2,#1		; if sem free grab it!
 STR	R2,[R7]
 MOV	R0,#115
 STRB	R0,[R1]
 MOV	R0,#101
 STRB	R0,[R1]
 MOV	R0,#109
 STRB	R0,[R1]
nosemF
 MOV	R0,#CR
 STRB	R0,[R1]
 MOV	R0,#LF
 STRB	R0,[R1]
 MOV	R1,#IntrAd
 MOV	R0,#MAXINTR
 STR	R0,[R1]		; clear FIQ interrupt
 LDR	R0,fiqtmp0
 LDR	R1,fiqtmp1
 LDR	R2,fiqtmp2
 SUBS	PC,R14,#4	; return from interrupt


ERROR 
 MOV R0, #CTRLD ; Now prints out a Control D and then loops.
 SWI 0          ; This will halt simulation using the Tube Model
 B ERROR

;
; SWI's which use the default SWI handler (ie. this one) are either
;     SWI 0 with R0 != 0         prints a character
;     SWI Non 0 with R0 == 0     returns in SVC_32 mode
;
; This handler outputs the character via the Asim Tube Model
;     Non 0 SWI's use this code in both cases
;

SWI_handler
 ANDS  R0,R0,#&FF   ; IF (R0 & 0xFF) == 0
 MOVEQ PC,R14       ; THEN return in svc mode
 STR   R13, R13temp ; ELSE write byte out to data latch (preserving state)...
 MOV   R13, #TubeAd
 STRB  R0,[R13]
 LDR   R13, R13temp
 MOVS  PC,R14       ;      ...and return in original mode

R13temp
 & 0        ; Temporary register storage

;
; Program start
;
MAIN
 MOV R13, #TubeAd ; Load R13_svc with address of Asim Tube

;***************** ARM test software header file end ************


; **** ADD YOUR CODE HERE ****

 END
