1#!/bin/bash
2#
3# SPDX-License-Identifier: BSD-3-Clause
4#
5# Copyright © 2019 Keith Packard
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10#
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13#
14# 2. Redistributions in binary form must reproduce the above
15#    copyright notice, this list of conditions and the following
16#    disclaimer in the documentation and/or other materials provided
17#    with the distribution.
18#
19# 3. Neither the name of the copyright holder nor the names of its
20#    contributors may be used to endorse or promote products derived
21#    from this software without specific prior written permission.
22#
23# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34# OF THE POSSIBILITY OF SUCH DAMAGE.
35#
36
37qemu="qemu-system-arm"
38
39# select the program
40elf="$1"
41shift
42
43cpu=unknown
44machine=unknown
45memory=
46
47#
48# Map ELF information to required core type
49#
50
51cpu_arch=`arm-none-eabi-readelf -A "$elf" | awk '/Tag_CPU_arch:/ { print $2 }'`
52cpu_profile=`arm-none-eabi-readelf -A "$elf" | awk '/Tag_CPU_arch_profile:/ { print $2 }'`
53fp_arch=`arm-none-eabi-readelf -A "$elf" | awk '/Tag_FP_arch/ { print $2 }'`
54fp_use=`arm-none-eabi-readelf -A "$elf" | awk '/Tag_ABI_HardFP_use/ { print $2 }'`
55ram_addr=`arm-none-eabi-readelf -l "$elf" | awk '/LOAD.*RW/ { if (min_va == 0 || $3 < min_va) min_va = $3; } END { print(min_va); }'`
56
57case "$cpu_arch"/"$cpu_profile" in
58    v4T/)
59        cpu=ti925t
60        ;;
61    v5TE/)
62        cpu=arm926
63        ;;
64    v6S-M/Microcontroller)
65        cpu=cortex-m0
66        ;;
67    v7/Application|v7/)
68        case "$fp_arch" in
69            VFPv3)
70                cpu=cortex-a9
71                ;;
72            VFPv3-D16)
73                cpu=cortex-a8
74                ;;
75            *)
76                cpu=cortex-a7
77                ;;
78        esac
79        ;;
80    v7/Microcontroller)
81        cpu=cortex-m3
82        ;;
83    v7/Realtime)
84        cpu=cortex-r5f
85        ;;
86    v7E-M/Microcontroller)
87        cpu=cortex-m7
88        case "$fp_arch" in
89            FPv5/FP-D16)
90                case "$fp_use" in
91                    SP)
92                        cpu=cortex-m4
93                        ;;
94                esac
95                ;;
96            *)
97                cpu=cortex-m4
98                ;;
99        esac
100        ;;
101
102    v8-M.*/Microcontroller)
103        case "$fp_arch" in
104            FPv5/FP-D16)
105                case "$fp_use" in
106                    SP)
107                        cpu=cortex-m33
108                        ;;
109                    *)
110                        cpu=cortex-m55
111                        ;;
112                esac
113                ;;
114            *)
115                cpu=cortex-m33
116                ;;
117        esac
118        ;;
119    v8.1-M.mainline/Microcontroller)
120        cpu=cortex-m55
121        ;;
122    v8/Application)
123        cpu=cortex-a57
124        ;;
125esac
126
127#
128# Select a QEMU machine based on the CPU
129#
130case $cpu in
131
132    cortex-m0)
133        machine=microbit
134        memory="-global nrf51-soc.sram-size=2097152 -global nrf51-soc.flash-size=4194304"
135        ;;
136
137    # mps2-an385 offers a cortex-m3 processor
138    cortex-m3)
139	machine=mps2-an385
140	;;
141
142    # mps2-an386 offers a cortex-m4 processor
143    cortex-m4)
144        machine=mps2-an386
145        ;;
146
147    # mps2-an500 offers a cortex-m7 processor
148    cortex-m7)
149        machine=mps2-an500
150        ;;
151
152    # mps2-an505 offers a cortex-m33 processor
153    cortex-m33)
154        machine=mps2-an505
155        ;;
156
157    # mps3-an547 offers a cortex-m55 processor
158    cortex-m55)
159        machine=mps3-an547
160        ;;
161
162    cortex-a57)
163        machine=none
164        cpu=max
165	memory="-m 1G"
166        ;;
167
168    cortex-a?)
169        case "$ram_addr" in
170            0x48*)
171                machine=vexpress-a9
172                cpu=cortex-a9
173                ;;
174            *)
175	        machine=none
176                ;;
177        esac
178	memory="-m 1G"
179        ;;
180
181    # The 'none' machine supports many non-M
182    # processors
183    ti925t|arm*|cortex-a*|cortex-r*)
184	machine=none
185	memory="-m 1G"
186	;;
187
188esac
189
190#
191# Make sure the target machine and cpu is supported by qemu
192#
193if $qemu -machine help | grep -q "^$machine "; then
194    if $qemu -machine $machine -cpu help | grep -q "^ *$cpu"; then
195        :
196    else
197        echo "Skipping $elf: unsupported cpu on $machine"
198        exit 77
199    fi
200else
201    echo "Skipping $elf: unsupported machine"
202    exit 77
203fi
204
205# Map stdio to a multiplexed character device so we can use it
206# for the monitor and semihosting output
207
208chardev=stdio,mux=on,id=stdio0
209
210# Point the semihosting driver at our new chardev
211
212cmdline="program-name"
213input=""
214done=0
215
216while [ "$done" != "1" ]; do
217    case "$1" in
218        --)
219            shift
220            done=1
221            ;;
222        -s|"")
223            done=1
224            ;;
225        *)
226            cmdline="$cmdline $1"
227            case "$input" in
228                "")
229                    input="$1"
230                    ;;
231                *)
232                    input="$input $1"
233                    ;;
234            esac
235            shift
236            ;;
237    esac
238done
239
240semi=enable=on,chardev=stdio0,arg="$cmdline"
241
242# Disable monitor
243
244mon=none
245
246# Disable serial
247
248serial=none
249
250export QEMU_AUDIO_DRV=none
251
252input_file=`mktemp`
253trap 'rm "$input_file"' 0
254echo "$input" > "$input_file"
255
256"$qemu" $memory \
257      -chardev "$chardev" \
258      -semihosting-config "$semi" \
259      -monitor "$mon" \
260      -serial "$serial" \
261      -machine "$machine",accel=tcg \
262      -cpu "$cpu" \
263      -device loader,file="$elf",cpu-num=0 \
264      -nographic \
265      "$@" < $input_file
266
267result=$?
268
269if [ $result != 0 ]; then
270    case $cpu in
271	# Cortex-a8 qemu has minor floating point errors
272	# when run on i686 processors
273	cortex-a8)
274	    test="$(uname -m)-$elf"
275	    case "$test" in
276		i?86-*math_test|i?86-*math_test_?|i?86-*math_test_??)
277		    echo "fp imprecise for $cpu on" "$(uname -m)"
278		    result=77
279		    ;;
280	    esac
281	    ;;
282    esac
283fi
284exit $result
285