TMS570 exception - Page 1
Forum section: electronics / general

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 10:03:49 am
content: Hii'm using TMS570 and i'm managing how to return from exception. I saw the documentation of arm cortex r5 and tms570.Firt question:i have these exceptions:1) undef instr2) data abort3) abort prefetch4) sw inti able to simulate exceptions 2) and 3), but not the others. Can you help me how can i do this ?Second question:In the doc i see that to recover the system from exception i ha to save the last PC value from the specific reg of the exception.Infact for "Data abort" i did this without problem.For "ABORT PREFETCH" i follow the same steps but i don't be able to recover the value of PC.In particular in the same point of DATA ABORT ,in which i save the value of PC, for the ABORT PREFETCH i have a value of PC equal to entry point.in the docs the steps are the same for all of exceptions.Can ypu help me ?Thank you

author: rsjsouza
author_rank: Super Contributor
timestamp: July 09, 2022, 11:12:05 am
content: For 1) above, if the code branches to a data section you can get this to be triggered. The details escape me but, if you are using C, you can try to force using inline assembly to LDR a data address to the PC.I assume you already know the app note below, right? If not, it might give you some ideas:Interrupt and Exception Handling on Hercules™ ARM® Cortex®-R4/5-Based Microcontrollers

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 09, 2022, 11:24:44 am
content: To trigger the sw int (number 4 on your list) you have to use the software interrupt assembler instruction. (swi)Go to the ARM developer sight for more info:https://developer.arm.com/documentation/ddi0460/d/I43209To trigger the undef instr (number 1 on your list) you have to make up a 32 bit code, that is not recognized as an instruction.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 11:31:56 am
content: Hii'm using Assembler C to save PC value.i'm reading the doc."The processor takes the undefined instruction exception when it encounters an instructionthat is undefined in the appropriate version of the ARM instruction set, orwhich is for the VFP when the VFP isdisabled. The undefined instruction exception can be used to emulate undefined instructions, or simply to handle fault situations"i don't understand the meaning of bold expression.Thank you very much

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 11:34:20 am
content: Quote from: pcprogrammer on July 09, 2022, 11:24:44 amhi and thank you.ok now i see the link.Can you explain me what do you mean with "you have to make up a 32 bit code" ?thank you.

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 09, 2022, 11:47:03 am
content: When you look at how the ARM instruction set is coded in binary, you can see that there are specific fields, like the conditional execution bits, etc. Within the 32 bits available there are combinations that do not decode into a valid instruction for the processor. It is these codes that trigger the undefined instruction interrupt.For the cortex R5 it depends on which ARM version it is based on which instructions are valid. Be it v5, v6, v7, etc. That is what they mean with the first bold section of what you wrote. The second bit points to the Vector Floating Point processor that can be present and then take instructions specific for this processor. If it is disabled these specific instructions also trigger the undefined instruction interrupt.This makes it possible to handle these instructions in software.So what I meant with the make up a 32 bit code, is that you have to find a code that is not mapped to a known instruction and then embed it in your code. When the instruction fetch system reads this unknown code it triggers the undefined instruction interrupt.

author: brucehoult
author_rank: Super Contributor
timestamp: July 09, 2022, 12:01:13 pm
content: Quote from: lorenrus on July 09, 2022, 11:34:20 amAre you running in ARM mode, or in Thumb2 mode?In, for example, ARM mode all instructions are 32 bits in size. There are 2^32 = 4294967296 possible instructions, but not all have been defined. The manual (Cortex-R5F, ARMv7-R) lists the opcodes that are defined. All other opcodes are undefined.One easy way to find one would be to look for a new instruction defined by ARMv8-R, and try to use it.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 02:01:24 pm
content: okok, clear.i'm reading R5 RM.for undef instruction for example i could do "divide by zero" with UDIV or SDIV instructions.- i have to set DZ bit of SCTLR equals to 1 to generate a fault undef instr by the processor, right ? Because if DZ is equal to zero the result of divide by zero operation is equal to zero, right ?after i see this:Code:addr = R14_undef - 2instr = Memory[addr,2]if (instr >> 11) > 28 { /* 32-bit instruction */instr = (instr << 16) | Memory[addr+2,2]if (emulating, so return after instruction wanted) }R14_undef += 2 //} //}After this, instr holds the instruction (in the range 0x0000-0xE7FF for a 16-bit instruction,0xE8000000-0xFFFFFFFF for a 32-bit instruction), and the exception can be returned fromusing a MOVS PC, R14 to return after it.For R14_undef i think that i can write an assembler function that returns this value, but what would theMemoryvariable be if I wanted to represent it in C ? It would appear to be a matrix.Which is the meaning ofemulating, so return after instruction wanted?in my debug configuration i see that is set Mixed ARM thumb, but i think that i'll read the thumb bit in the Program Status Register.Also i see this:There are special cases for reading R15:• reading the address of the current instruction plus, either:— 4 in Thumb state— 8 in ARM state.• reading 0x00000000 (zero). --> this is the case that i found when i try to recover the system for prefetch abort ?Thank you

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 02:15:15 pm
content: Quote from: brucehoult on July 09, 2022, 12:01:13 pmOkcan i use this expressione to generate the undef instr described in attached file ?MCR p15, #0, Rt, c7, c0, #0Thank you

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 09, 2022, 03:48:03 pm
content: Quote from: lorenrus on July 09, 2022, 02:15:15 pmI don't think so. The MCR instruction is a valid instruction and addressing the control co-processor with it is normal use. Sending the wrong data to the control co-processor might result in undetermined behavior. But I might be wrong.Why are you so focused on these exceptions?When doing basic bare metal work on an ARM CPU these exceptions will most likely never happen. And when you are using a RTOS it will handle them and you don't need to write code for it.

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 09, 2022, 04:05:56 pm
content: Quote from: lorenrus on July 09, 2022, 02:01:24 pmI don't know about the divide by zero causing an undefined instruction interrupt.The bit about the 32 bits instruction range being 0xE8000000 - 0xFFFFFFFF feels wrong. The top 4 bits are the condition field bits, and can be different from 0xE.The pseudo code you posted shows how to determine if the data read from before the return instruction (the data that caused the interrupt) is a 32 bit ARM instruction or a 16 bit THUMB(2) instruction. The "if" part is where you put your own code to handle "emulate" the undefined instruction.Did not know that trick of shifting and checking against being > 28.The Memory bit used in the pseudo code is just a referral to the system memory, which in some way is a big array of bytes.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 05:23:27 pm
content: I have to realize a doc with all exceptions, describe in the first post, and analyze their behaviour, simulate them and understand how to recover the system.Do you think that is possible to recover the system from all exceptions ?Thank you

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 05:27:51 pm
content: Quote from: pcprogrammer on July 09, 2022, 04:05:56 pmIn R5 RM:"Undefined Instruction exceptions also occur when a UDIV or SDIV instruction is executed, the value in Rm is zero, and the DZ bit in the SCTLR is set."In the ARMv7-R profile, the SCTLR.DZ bit enables divide by zero fault detection:SCTLR.DZ == 0Divide-by-zero returns a zero result.SCTLR.DZ == 1SDIV and UDIV generate an Undefined Instruction exception on a divide-by-zero.The SCTLR.DZ bit is cleared to zero on reset.

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 09, 2022, 05:35:25 pm
content: To some extend yes a system can recover from all exceptions as long as it is not a hardware failure.In case of a glitch in the memory the processor might encounter an undefined instruction interrupt (exception) and the software could recover from this by resetting and reloading the code. If on the other hand a bit in memory is corrupt on a hardware level, resetting and reloading won't help.So it all depends on how the system is setup to handle these exceptions.Quite often these exceptions are implemented with just an endless loop, causing a system to hang when such an exception occurs. Then a hard reset is needed. (Power down and up again, or press an actual reset button)This because in normal operation these exceptions won't occur.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 09, 2022, 06:35:14 pm
content: Okhow i said in my first post for now i able to recover only from DATA ABORT and simulate only DATA ABORT and PREFETCH ABORT.I reported that in PREFETCH ABORT when i try to read PC value i see that it' s value is zero instead in DATA ABORT i have the correct value of next instruction.This behaviour is correct ?Do you know how can i recover and simulate the other exceptions ?Thank you

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 09, 2022, 07:23:09 pm
content: I have not looked at the exceptions in depth, but think the prefetch abort can only be recovered with a reset. Probably the reason why R14 holds zero as a return address.Recovering from exceptions depends on what you want the system to do. If it is ok to just fall into an endless loop than that is perfect "recovery" from the exception.Using a watchdog timer can also be a recovery mechanism. It will reset the system on a time out.Study the guide about the ARM CPU further and you will find the answers about the exceptions.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 11, 2022, 12:05:01 pm
content: I able to generate an undef istr with:asm(“ .word 0xFFFFFFFF”);But i don’t understand why?What does this Line of code do ?

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 11, 2022, 12:56:26 pm
content: Here is a page from an older ARM architecture reference manual.It shows how the instructions are coded. You can see that the top 4 bits form the condition field. When you look at the last row you see "Unconditional instructions" and a referral to Figure A3-6, which is shown below.When you look again at the last line you can see that all instructions with 0xFF in the top 8 bits are undefined. So every word ranging from 0xFF000000 to 0xFFFFFFFF is going to trigger the undefined instruction. This applies to the ARM versions this document is written for. (Up to ARMv6)Edit: Increased the font size to make it more clear

author: lorenrus
author_rank: Regular Contributor
timestamp: July 11, 2022, 01:17:14 pm
content: Oh yes this part is clear. I mean the assembler line .word followed by value, in this case 0xFFFFFFFF, what does it do? Is like a pointer to the value 0xFFFFFFFF?Thank you

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 11, 2022, 01:42:25 pm
content: Ok, guess I did not read your post properly.What that line does is add 0xFFFFFFFF into the code stream.When you write in assembler there are the instructions like ADD, LDR, etc. These are translated by the assembler to binary codes. But there are also directives like .word that allow you to put constants into the code stream.Here is a screenshot of output from Ghidra, which is a disassembler. In assembler the first two columns are not filled. In the first column you would put labels that you can use to jump to. The third shows the opcode, and the fourth the operand. Here they use the directive ddw to insert a 32 bit value instead of .word. It just depends on the assembler which directives can be used.In C you use the "asm ();" directive to insert assembler instructions or directives.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 11, 2022, 08:43:05 pm
content: okok clear thank you very much.today i able to generate undef and recover the system through the PC value saved in R14 related to the exceptions.I tried again to recover from abort prefetch but i think that is not possible, because:i can cause abort prefetch exception jumping in unmapped address or reserved address, if i say jump it means that i have to modify the current PC value. With this considerations i think that shoudn't be possibile ? What do you think ?Tomorrow i have to study SW int exception. Do you have any idea ?For divide by zero exception:in R5 Ref Man is reported that is possible to generate this but today i was reading as functions of TI lib and i see that by default TI set: "DIVIDED BY ZERO RETURN ZERO".But is possible to modify this how is written in the head of the asm file.If i would like to modify, how can i say in assembler that i want to generate an exception ?I also did a test, knowing it couldn't be done like this, by doing:modified section (pseudo cod):Code:#define UNDEF_EXCETION_ADDR 0x00000004uint32 PC;if (divide_by_zero)PC = ((uint32*)UNDEF_EXCETION_ADDR);all pseudo cod done in assembler.But as I expected the jump to that instruction was there but no real exception was thrown.At this point I wonder how to tell him to activate the exception in assembler.Thank you very much

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 12, 2022, 05:15:20 am
content: QuoteI have not read up on prefetch abort exception, but you basically answered your own question. When the processor tries to fetch an instruction from non existing memory, the change that the data on the next location would be valid is practically none. So it makes no sense to jump back to that location.The only option to recover would then be to reset the system.QuoteThe software interrupt exception is mostly used for task switching in an RTOS. In C there is the "sleep" function. In a multi tasking environment this could use the software interrupt (SWI instruction) to return control to the OS. This way the system is able to change the privilege level from "user" back to "system" when I'm not mistaken. Do not have much experience with this.QuoteI'm not familiar with the TMS570 and the libraries that come with it, so you are on your own there.QuoteJumping to an exception handler is indeed not the same as when the exception is actually triggered. You already looked into the divide by zero yourself.The "SCTLR.DZ" has to be set to enable the undefined instruction exception when a divide by zero is detected by the processor. (Have not looked at the documentation if this is true)So to get it working you have to set this bit before using the divide instructions.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 13, 2022, 01:47:00 pm
content: I have a news for divider by zero.For others exceptions is all ok.I see in the code of TI lib that by default return 0.But if you want you can edit this file.I try to do in the main: c=1/0.I edit this file and i modify the cpsr for undef i salve the cpsr to spsr_undef i save the last value of PC. And i able to restore the system.But there is a problem beacause if i have a div operation in a nested function how can i have the correct value of pc?Example:Void func1(){Func2();}Void func2(){1/0;}Main(){Func1();Func3();}So the the pc that is important for me is generate from func1 in the LR reg. but when i switch to func2 i loose the correct pc.How can i do this ?Thank you

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 13, 2022, 02:23:36 pm
content: Well for that the arn cpu has register banks, and there is the use of stack.ARM does not have what other cpu's might have and that is a direct copying to stack of the instruction pointer. Instead when a sub routine is called the return address is loaded into R14. To allow for interrupts to still be possible they incorporated the register banks. In the case of an interrupt or exception the cpu first switches to the bank related to the interrupt or exception. Then it loads the return address into that banks R14, leaving R14 in the other bank in tact.So at the end of the interrupt or exception, the PC can be loaded from R14, which causes it to return to the instruction right after where it left of. In the process the cpu also switches back to the register bank that was set before the interrupt or exception. In this bank R14 holds the address just after the call of the sub routine. The ARM developer manuals contain information about this. Search for "return from interrupt" or "return from exception".My recollection of the workings is a bit vague. I wrote an emulator for armv5 last year where I handled this stuff, but when working with C the compiler takes care of all these things and I forgot the actual inner workings. (The code can be found here:https://github.com/pecostm32/FNIRSI-1013D-1014D-Hack/tree/main/Test%20code/Scope_emulator)But back to your example, there the exception will occur in "func2" and your handler should return to the point right after the divide instruction. The code will then continue and return to "func1" and then back to "Main"In the code generated by the compiler there will be bits that copy the address in R14 onto the stack to allow for nested sub routines.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 13, 2022, 03:59:19 pm
content: Yes i do extactly what are you saying.I found the problem, but i don’t know where is my error.I able to resume correctly from exception infact the return address is the addr of brackets immediately following func2().Func1(){Func2();} <———————here !!!!! I put here a break poi t. Here i see the disassembly and i see that will be execute pop {r1, r2, r3, pc} . This is necessary to restore the address of previous nested function.I go on step by step i see the fail because the System gode to entry func at addr 0x00000000 and pop {r1, r2, r3, pc} fails. But is caused by the operation that i added.In particoular i change mode from System to undef, so i work on cpsr. I save cpsr in spsr_undef.These operations could generate it ?

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 13, 2022, 04:34:07 pm
content: Yes saving the current cpsr into spsr_undef is not the way to do it. On exception or interrupt the cpsr is automatically stored to spsr in the bank belonging to the exception or interrupt. Then the cpu sets the needed register bank in the cpsr.This means that when you do this saving again in the exception handler you will overwrite the cpsr data from before the exception.Code://Check interrupt on enabled and activeif((core->status->flags.I == 0) && (core->irq == 1)){//Handle the interrupt//Load exception r14 with current pc plus 4. The manual states for entering and returning from interrupt sub r14, r14, #4; stmfd sp!, {r14}; ...; ldmfd sp!, {pc}^*core->registers = *core->program_counter + 4;//Load exception spsr with current psr*core->registers = core->status->word;//Switch to irq exception modecore->status->flags.M = ARM_MODE_IRQ;//Return to arm execution statecore->status->flags.T = 0;core->status->flags.J = 0;//Disable interruptscore->status->flags.I = 1;//Clear the interrupt flag to signal it has been handledcore->irq = 0;//Load endianness from cp15 (not implemented here since it is not used in the scope)//Switch the current bank to the irq bankcore->current_bank = ARM_REG_BANK_IRQ;//Set the internal mode to irq modecore->current_mode = ARM_MODE_IRQ;//Load pc with the irq vector address. Depending om cp15 it could also be 0xFFFF0018, but not implemented here.*core->program_counter = 0x00000018;}This piece of code is the irq handling in my emulator. For the undefined instruction exception the actions are similar, but with a different register bank.You can see that R14 of the IRQ register bank is loaded with the current program counter + 4. Then the SPSR of the IRQ register bank is loaded with the current CPSR.Then the flags in the CPSR are set to what they need to be. The last thing done is to load the PC with the IRQ vector address.I wrote this emulator for the reverse engineering of the FNIRSI-1013D so left out things that I knew not being used. But writing it did teach me how the cpu works to some extend.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 13, 2022, 06:29:10 pm
content: “ Yes saving the current cpsr into spsr_undef is not the way to do it. On exception or interrupt the cpsr is automatically stored to spsr in the bank belonging to the exception or interrupt. Then the cpu sets the needed register bank in the cpsr. “Yes, but this, if I'm not mistaken, only happens if the processor provides an exception for a certain event. In fact, what you say happens to me when I generate a given abortion for example. But here the situation is different because for the division by zero the processor of the TMS570 does not provide for the activation of any exception in fact, as I said in previous posts, in the asm files that manage the divisions it is explicitly reported that the division by zero simply returns zero. Then always in these files there is a note in which if you want to activate an exception, instead of returning zero, you have to edit the file. I made these changes and they would be what I told you in the previous post and they are as follows. So when I make these changes I’m not yet in a handler but I’m still within the split function. What I do is this:When divider by zero raises i want to generate an undef exception so i have to save actual cpsr to spsr_undef and actual PC to R14_undef.To do this i have to:Inside division function- save PC- switch to undef mode- save cpsr to spsr_undef- save pc to R14 undef- mov pc, #addr_undef_exceptionAFTER inside isr i restore the System.This behaviour works good when inside main i Write directly a/b, i able to restore the System and go to nextfunc():Int main(){Uint32 a=1;Uint32 b=0;Uint32 c=0;C=a/b;<———Nextfunc();}My problem is Only when my divison is inside a nested function.

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 13, 2022, 07:24:24 pm
content: It is getting a bit fuzzy.What are you using to do the coding and debugging?You are talking about inside the division function, but before you mentioned the specific arm instructions UDIV and SDIV. These are not functions you can add code to, so what is it that you are doing. Keep in mind I don't know anything about the TMS570. Everything I wrote here is general ARM knowledge.The thing you have to remember is that the program counter (R15) does not point to the next instruction, but multiple bytes further in memory. Not sure if it is 4 or 8. And it also depends on the state the cpu is in. ARM or THUMB. So copying it to R14 and then returning from exception with the intended instructions might not be correct. See the comment line in the code bit I posted. (5th line in the code section) Try to find information about this in the programmers manual.To me it feels you are doing things that are not normal usage of the cpu.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 13, 2022, 08:17:34 pm
content: Before i mentioned udiv sdiv, but AFTER i see, in the division file .asm , that TI use udiv and SDIV only when we are not in the case of divided by zero.Yes the return pc has an offset depending on exception.Today i also tried to use udiv also in case divided by zero and if i select DZ bit, that i mentioned in previous post, the exception raises automatically.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 13, 2022, 08:18:34 pm
content: Before i mentioned udiv sdiv, but AFTER i see, in the division file .asm , that TI use udiv and SDIV only when we are not in the case of divided by zero.Yes the return pc has an offset depending on exception.Today i also tried to use udiv also in case divided by zero and if i select DZ bit, that i mentioned in previous post, the exception raises automatically.Today i’ll show you this code.

author: lorenrus
author_rank: Regular Contributor
timestamp: July 14, 2022, 06:39:58 am
content: Good morningfile udiv_32.asm and div0.asm.As you can see TI use UDIV only whene we are not in the case of divided by zero operation.At line 209 the system goes to that function that is located in the second file attached divide by zero. In div_0.asm, as you can see, there is nothing. And in their head there is written:"The functions can be overridden to implement system specific implementations like returning a fixed value or raising an exception"The are also two files in wich there are my lines added.Thank you

author: pcprogrammer
author_rank: Super Contributor
timestamp: July 14, 2022, 08:12:55 am
content: Sorry, but that is to deep into things.Even if it is study, I don't see the gain in figuring this out. It is not normal usage of a cpu.If you need some information about the division being by zero it is much easier to just check the input parameter before calling the division operation and call an assert function to take action on it. Not try to do something out of the ordinary where things don't work as expected because you don't know the full ins and outs of the processor.