Из вашего комментария вопрос: Как сгенерировать любое исключение.
Вот один из документации:
Encoding T1 All versions of the Thumb instruction set.
SVC<c> #<imm8>
...
Exceptions
SVCall.
Который я можно найти, выполнив поиск по SVCall.
Исключения хорошо задокументированы ARM, есть способы вызвать исключения, которые вы указали, без необходимости разрывать шину (требуя симулятора fpga или создания собственного кремния), вы уже знать условия поиска по документу, чтобы найти сбой шины и сбой использования.
Как ARM обрабатывает их (внутренне или нет), задокументировано. Внутренне в этом случае означает блокировку или нет, если вы посмотрите, в противном случае они выполняют обработчик ошибок (если, конечно, нет ошибки, вызывающей обработчик ошибок).
Большинство из них вы можете создать в C, не прибегая к инструкции на языке ассемблера, но вы должны быть осторожны, чтобы он генерировал то, что, по вашему мнению, генерирует:
void fun ( void )
{
int x = 3;
int y = 0;
int z = x / y;
}
Disassembly of section .text:
00000000 <fun>:
0: 4770 bx lr
Вместо этого вам нужно что-то, что фактически генерирует инструкцию, которая может вызвать ошибку:
int fun0 ( int x, int y )
{
return(x/y);
}
void fun1 ( void )
{
fun0(3,0);
}
00000000 <fun0>:
0: fb90 f0f1 sdiv r0, r0, r1
4: 4770 bx lr
6: bf00 nop
00000008 <fun1>:
8: 4770 bx lr
, но, как показано, вы должны быть осторожны с тем, где и как вы это называете. В этом случае вызов был выполнен в том же файле, поэтому оптимизатор мог видеть, что это теперь мертвый код, и оптимизировал его, поэтому такой тест не смог бы сгенерировать ошибку по нескольким причинам.
Вот почему OP должен предоставить полный минимальный пример, причина, по которой не обнаруживаются ошибки, не в процессоре. Но программное обеспечение и / или тестовый код.
Edit
Полный минимальный пример, все, что вам нужно, кроме набора инструментов GNU (нет. Это на синей таблетке stm32 и STM32F103 ...
fla sh .s
.cpu cortex-m3
.thumb
.thumb_func
.global _start
_start:
stacktop: .word 0x20001000
.word reset /* 1 Reset */
.word hang /* 2 NMI */
.word hang /* 3 HardFault */
.word hang /* 4 MemManage */
.word hang /* 5 BusFault */
.word usagefault /* 6 UsageFault */
.word hang /* 7 Reserved */
.word hang /* 8 Reserved */
.word hang /* 9 Reserved */
.word hang /*10 Reserved */
.word hang /*11 SVCall */
.word hang /*12 DebugMonitor */
.word hang /*13 Reserved */
.word hang /*14 PendSV */
.word hang /*15 SysTick */
.word hang /* External interrupt 1 */
.word hang /* External interrupt 2 */
.thumb_func
reset:
bl notmain
b hang
.thumb_func
hang: b .
.thumb_func
.globl PUT32
PUT32:
str r1,[r0]
bx lr
.thumb_func
.globl GET32
GET32:
ldr r0,[r0]
bx lr
.thumb_func
.globl dummy
dummy:
bx lr
.thumb_func
.globl dosvc
dosvc:
svc 1
.thumb_func
.globl hop
hop:
bx r0
fla sh .ld
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x1000
ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
fun. c
void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );
void hop ( unsigned int );
#define GPIOCBASE 0x40011000
#define RCCBASE 0x40021000
#define SHCSR 0xE000ED24
void usagefault ( void )
{
unsigned int ra;
while(1)
{
PUT32(GPIOCBASE+0x10,1<<(13+0));
for(ra=0;ra<100000;ra++) dummy(ra);
PUT32(GPIOCBASE+0x10,1<<(13+16));
for(ra=0;ra<100000;ra++) dummy(ra);
}
}
int notmain ( void )
{
unsigned int ra;
ra=GET32(SHCSR);
ra|=1<<18; //usagefault
PUT32(SHCSR,ra);
ra=GET32(RCCBASE+0x18);
ra|=1<<4; //enable port c
PUT32(RCCBASE+0x18,ra);
ra=GET32(GPIOCBASE+0x04);
ra&=(~(3<<20)); //PC13
ra|= (1<<20) ; //PC13
ra&=(~(3<<22)); //PC13
ra|= (0<<22) ; //PC13
PUT32(GPIOCBASE+0x04,ra);
PUT32(GPIOCBASE+0x10,1<<(13+0));
for(ra=0;ra<200000;ra++) dummy(ra);
PUT32(GPIOCBASE+0x10,1<<(13+16));
for(ra=0;ra<200000;ra++) dummy(ra);
ra=GET32(0x08000004);
ra&=(~1);
hop(ra);
return(0);
}
сборка
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m3 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m3 -mthumb -c so.c -o so.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o so.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy -O binary so.elf so.bin
Все эти параметры командной строки не требуются arm- linux -gnueabi- и другие разновидности инструментальных средств gnu отлично работают от нескольких версий до настоящего момента, поскольку я использую их в качестве компилятора, ассемблер и компоновщик и не связывайтесь с библиотекой или другими вещами, которые варьируются от одного аромата к другому.
UsageFault The UsageFault fault handles non-memory related faults
caused by instruction execution.
A number of different situations cause usage faults, including:
• Undefined Instruction.
• Invalid state on instruction execution.
• Error on exception return.
• Attempting to access a disabled or unavailable coprocessor.
The following can cause usage faults when the processor is configured to
report them:
• A word or halfword memory accesses to an unaligned address.
• Division by zero.
Software can disable this fault. If it does, a UsageFault escalates to HardFault. UsageFault has a configurable priority.
...
Instruction execution with EPSR.T set to 0 causes the invalid state UsageFault
Итак, здесь тест переходит в руку адрес вместо адреса большого пальца, и это вызывает ошибку использования. (Можно прочитать об инструкции BX, бит psr.t, как и когда он будет изменен, и c также в документации)
Резервное копирование этого это синяя таблетка stm32. На ПК13 есть светодиод, код включает ошибку использования, настраивает ПК13 как выход , мигает один раз, поэтому мы видим, что программа запущена, а затем, если она попадает в обработчик ошибок использования, она мигает вечно. вы видите, что это повторяется бесконечно.
Перед естественным запуском вы проверяете сборку, чтобы убедиться, что она работает:
Disassembly of section .text:
08000000 <_start>:
8000000: 20001000
8000004: 08000049
8000008: 0800004f
800000c: 0800004f
8000010: 0800004f
8000014: 0800004f
8000018: 08000061
800001c: 0800004f
8000020: 0800004f
8000024: 0800004f
8000028: 0800004f
800002c: 0800004f
8000030: 0800004f
8000034: 0800004f
8000038: 0800004f
800003c: 0800004f
8000040: 0800004f
8000044: 0800004f
08000048 <reset>:
8000048: f000 f82a bl 80000a0 <notmain>
800004c: e7ff b.n 800004e <hang>
0800004e <hang>:
800004e: e7fe b.n 800004e <hang>
...
08000060 <usagefault>:
8000060: b570 push {r4, r5, r6, lr}
Таблица векторов верна правые векторы указывают вправо мест.
0xE000ED28 CFSR RW 0x00000000
HFSR - это старшие биты CFSR
> halt
target halted due to debug-request, current mode: Handler UsageFault
xPSR: 0x81000006 pc: 0x0800008a msp: 0x20000fc0
> mdw 0xE000ED28
0xe000ed28: 00020000
И этот бит
INVSTATE, bit[1]
0 EPSR.T bit and EPSR.IT bits are valid for instruction execution.
1 Instruction executed with invalid EPSR.T or EPSR.IT field.
Теперь
Using the CCR, see Configuration and Control Register, CCR on page B3-604, software can enable or disable:
• Divide by zero faults, alignment faults and some features of processor operation.
• BusFaults at priority -1 and higher.
Значение сброса CCR ОПРЕДЕЛЕНО РЕАЛИЗАЦИЕЙ, поэтому он может быть включен для вас или нет, вероятно, придется посмотреть на Cortex-m3 TRM или просто прочитать его:
> mdw 0xE000ED14
0xe000ed14: 00000000
, так что его нули на моем .
Так добавьте веселья. c:
unsigned int fun ( unsigned int x, unsigned int y)
{
return(x/y);
}
Измените так. c:
void PUT32 ( unsigned int, unsigned int );
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );
unsigned int fun ( unsigned int, unsigned int);
#define GPIOCBASE 0x40011000
#define RCCBASE 0x40021000
#define SHCSR 0xE000ED24
#define CCR 0xE000ED14
void usagefault ( void )
{
unsigned int ra;
while(1)
{
PUT32(GPIOCBASE+0x10,1<<(13+0));
for(ra=0;ra<100000;ra++) dummy(ra);
PUT32(GPIOCBASE+0x10,1<<(13+16));
for(ra=0;ra<100000;ra++) dummy(ra);
}
}
int notmain ( void )
{
unsigned int ra;
ra=GET32(SHCSR);
ra|=1<<18; //usagefault
PUT32(SHCSR,ra);
ra=GET32(CCR);
ra|=1<<4; //div by zero
PUT32(CCR,ra);
ra=GET32(RCCBASE+0x18);
ra|=1<<4; //enable port c
PUT32(RCCBASE+0x18,ra);
ra=GET32(GPIOCBASE+0x04);
ra&=(~(3<<20)); //PC13
ra|= (1<<20) ; //PC13
ra&=(~(3<<22)); //PC13
ra|= (0<<22) ; //PC13
PUT32(GPIOCBASE+0x04,ra);
PUT32(GPIOCBASE+0x10,1<<(13+0));
for(ra=0;ra<200000;ra++) dummy(ra);
PUT32(GPIOCBASE+0x10,1<<(13+16));
for(ra=0;ra<200000;ra++) dummy(ra);
fun(3,0);
return(0);
}
build
arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m3 flash.s -o flash.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m3 -mthumb -c so.c -o so.o
arm-none-eabi-gcc -Wall -O2 -ffreestanding -mcpu=cortex-m3 -mthumb -c fun.c -o fun.o
arm-none-eabi-ld -nostdlib -nostartfiles -T flash.ld flash.o so.o fun.o -o so.elf
arm-none-eabi-objdump -D so.elf > so.list
arm-none-eabi-objcopy -O binary so.elf so.bin
подтвердите, что на самом деле существует инструкция разделения, которую мы собираемся нажать
800011e: 2100 movs r1, #0
8000120: 2003 movs r0, #3
8000122: f000 f80f bl 8000144 <fun>
...
08000144 <fun>:
8000144: fbb0 f0f1 udiv r0, r0, r1
8000148: 4770 bx lr
загрузить и запустить и th Вызывается обработчик e.
target halted due to debug-request, current mode: Handler UsageFault
xPSR: 0x81000006 pc: 0x08000086 msp: 0x20000fc0
> mdw 0xE000ED28
0xe000ed28: 02000000
и это означает, что это деление на ноль.
Итак, все, что вам нужно было знать / делать, действительно было в документации, в одном документе.
99,999% программирования на «голом железе» - это чтение или проведение экспериментов для проверки того, что было прочитано, почти ни одна из работ - это написание окончательного приложения, это лишь крошечная часть работы.
Перед вами Чтобы перейти к программированию на голом железе, вы должны освоить инструментальную цепочку, иначе ничего не будет работать. Освоение инструментальной цепочки может быть выполнено без какого-либо целевого оборудования с использованием бесплатных инструментов, так что достаточно просто сесть и сделать это.
Насколько вы пытаетесь сделать деление с плавающей запятой на ноль на ядро, которое не имеет аппаратного деления на ноль, вам нужно посмотреть на soft float, например libg cc:
ARM_FUNC_START divsf3
ARM_FUNC_ALIAS aeabi_fdiv divsf3
CFI_START_FUNCTION
@ Mask out exponents, trap any zero/denormal/INF/NAN.
mov ip, #0xff
ands r2, ip, r0, lsr #23
do_it ne, tt
COND(and,s,ne) r3, ip, r1, lsr #23
teqne r2, ip
teqne r3, ip
beq LSYM(Ldv_s)
LSYM(Ldv_x):
...
@ Division by 0x1p*: let''s shortcut a lot of code.
LSYM(Ldv_1):
and ip, ip, #0x80000000
orr r0, ip, r0, lsr #9
adds r2, r2, #127
do_it gt, tt
COND(rsb,s,gt) r3, r2, #255
and so on
, который должен был быть виден при разборке, я не отключаю- рука видит принудительное исключение (преднамеренная неопределенная инструкция, swi / sv c или что-то в этом роде). Это только одна из возможных библиотек, и теперь, когда я думаю об этом, это похоже на руку, а не на большой палец, поэтому пришлось бы go искать это, проще просто посмотреть на разборку.
На основе вашего комментария и если я снова прочитаю другой вопрос, я предполагаю, поскольку он не вызвал исключения, правильным результатом деления на ноль является правильно подписанная бесконечность. но если вы переключитесь на cortex-m4 или m7, вы можете вызвать аппаратное исключение, но ... прочтите документацию, чтобы узнать.
Edit 2
void fun ( void )
{
int a = 3;
int b = 0;
volatile int c = a/b;
}
fun.c:6:18: warning: unused variable ‘c’ [-Wunused-variable]
6 | volatile int c = a/b;
| ^
08000140 <fun>:
8000140: deff udf #255 ; 0xff
8000142: bf00 nop
> halt
target halted due to debug-request, current mode: Handler UsageFault
xPSR: 0x01000006 pc: 0x08000076 msp: 0x20000fc0
> mdw 0xE000ED28
0xe000ed28: 00010000
и этот бит означает
The processor has attempted to execute an undefined instruction
Таким образом, volatile не смог дать желаемый результат, используя g cc
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 10.1.0
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (Ubuntu/Linaro 7.5.0-3ubuntu1~18.04) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
, а также
Disassembly of section .text:
00000000 <fun>:
0: deff udf #255 ; 0xff
2: bf00 nop
(и вы можете прокладывать себе путь через других).
Да, произошла ошибка, и это была ошибка использования, но это был бы еще один вопрос о переполнении стека, почему я не получил деление на ноль. Слепое использование энергозависимости для принудительного разделения не работает.
Создание всех трех энергозависимых
void fun ( void )
{
volatile int a = 3;
volatile int b = 0;
volatile int c = a/b;
}
Disassembly of section .text:
00000000 <fun>:
0: 2203 movs r2, #3
2: 2300 movs r3, #0
4: b084 sub sp, #16
6: 9201 str r2, [sp, #4]
8: 9302 str r3, [sp, #8]
a: 9b01 ldr r3, [sp, #4]
c: 9a02 ldr r2, [sp, #8]
e: fb93 f3f2 sdiv r3, r3, r2
12: 9303 str r3, [sp, #12]
14: b004 add sp, #16
16: 4770 bx lr
вызовет желаемую ошибку.
и без оптимизации
00000000 <fun>:
0: b480 push {r7}
2: b085 sub sp, #20
4: af00 add r7, sp, #0
6: 2303 movs r3, #3
8: 60fb str r3, [r7, #12]
a: 2300 movs r3, #0
c: 60bb str r3, [r7, #8]
e: 68fa ldr r2, [r7, #12]
10: 68bb ldr r3, [r7, #8]
12: fb92 f3f3 sdiv r3, r2, r3
16: 607b str r3, [r7, #4]
18: bf00 nop
1a: 3714 adds r7, #20
1c: 46bd mov sp, r7
1e: bc80 pop {r7}
20: 4770 bx lr
также вызовет желаемую ошибку.
Итак, сначала освоите язык (чтение, чтение, чтение), затем освоите инструментальную цепочку, затем (чтение, чтение, чтение), а затем программирование с нуля (чтение, чтение, чтение). Все дело в чтении, а не в кодировании. Как показано выше, даже имея многолетний опыт работы на этом уровне, вы не можете полностью предсказать, что сгенерируют инструменты; вам нужно просто попробовать это, но самое главное, потому что вы разобрались с этим для одного инструмента один раз в один день на одной машине, нет причин для слишком широких предположений. Придется попробовать и изучить, что производит компилятор, повторять процесс до тех пор, пока не получите желаемый эффект. Pu sh приходит в голову, просто напишите несколько строк asm и покончите с этим.
Вы не видели ошибок, потому что вы не генерировали их и / или не улавливали их, или и то, и другое. Список возможных причин большой длины основан на предоставленном коде, но эти примеры, в которых у вас не должно возникнуть проблем с портированием на вашу платформу, также должны демонстрировать работу вашего оборудования, а затем вы можете разобраться, почему ваше программное обеспечение не работает, подключив точки между кодом, который делает, и кодом, который этого не делает. Все, что я сделал, - это следил за документацией и изучил вывод компилятора, как только я включил минимальное количество вещей, был вызван обработчик ошибок. Без них ошибка использования не запускалась.