Rick's b.log - 2017/08/17 |
|
It is the 21st of November 2024 You are 3.145.89.89, pleased to meet you! |
|
mailto:
blog -at- heyrick -dot- eu
After a bit of poking around, I discovered the following:
Now unfortunately I'm going to have to get geeky to explain what's wrong here. I've already said R13 is special, it's a stack pointer. If you are quick on the uptake you might wonder why the instruction mentions R13 twice. That part is okay, we're loading a replacement stack pointer from the memory pointed to by the old. This is okay, every single application has its own stack, and applications are free to muck around with their own stack as they wish. It is, actually, a naff but acceptable way of 'resetting' the stack at the end of a complex function. Because as you might have guessed, for everything put onto the stack, there must be a corresponding retrieval of that information. If one single item of data is missed, everythin gels ei nth estac kwil lb eoff ,whic hwil lconfus eeverything, as that sentence demonstrated.
No, the problem is because the instruction also specifies writeback (the '!'). Now writeback is a really useful thing. You see, if you write five registers to the stack, you - as a programmer - don't want to have to think that that's five times four bytes, then take R13 and subtract that. Why? It's the twenty-first century. Tell the processor to work it out for itself and push the updated address back into R13.
And here we have an epic logic problem. You have asked the processor to load R13 from memory, while at the same time asking it to write back the updated value of the original R13. Well What do you want? The new one or the updated old one? The ARMv7 specification aborts such instructions as being gibberish. Frankly I'm surprised that such code ever worked correctly, as the behaviour of this was "undefined" so one processor (say, the OMAP) could choose to write the loaded R13, while another (say, Pi1) could choose to write the updated old R13. Remember, R13 is the stack pointer. It's things like this that cause all sorts of obscure bugs.
I patched my MenuUtils module (it's a thing within TemplEd). You can download the patched module, copy the module from the archive into !TemplEd.
Alternatively, there is a slightly later version of the module within WimpWorks. Download the demo and rummage around inside, you'll find it...
Zap worked on the Pi 2.
I write all of my code on RISC OS using Zap. I have, for something ridiculous like a quarter century. And while StrongEd is good (<cough>and still supported</cough>), I'm one of the Zap faithful. And for what it is worth, I've not seen an editor on the PC that comes close to what either of these make easy...
Similar to the above problem, the faulty instruction was quickly identified as:
This was not an easier fix. I had to unpack the ZapMJE source from the mess that GitHub's CVS made of it, to find that objasm is quite happy to recognise UAL (modern ARM) instructions in non-UAL (legacy ARM) code, plus will not fault attempts to set a macro to the same name as an instruction... I caught the "SEV" macro because I thought that was an instruction, but I wasn't aware that PUSH was a UAL instruction, I thought it was a Thumb thing. Many thanks to Jeffrey Lee for pointing this out. Thanks also to Fred Graute for the help with StrongEd. Yup, I used StrongEd to fix Zap! ☺
So if your Zap crashes on the Pi 2 (or other ARMv7+) when you try to load some C or assembler source code, you will need my ZapMJE update. This goes inside !Zap.Modules.!ZapMJE.
I think I ought to put together a distribution of the latest Zap, as the current situation is a god-awful mess of "download this, then add this patch, then add this patch...".
Nothing obvious stands out in a disassembly of DiskSample (fetches the stream), and the only instruction that looks suspicious in AudioMPEG (plays the MP3) is
I have not, as yet, tested playing locally held MP3s to see if that makes any difference, or playing with Interrupts not enabled...
You may get an error with an "Undefined instruction at ...something..." or a nicer looking error with a "Describe" button. If possible (not with TemplEd, but yes with Zap) keep the program running. Use "Continue" and not "Describe" or "Quit".
As soon as an important error occurs, the Debugger has a snapshot of the system's registers at that point.So open a command window and type
Now call up the faulty instruction. Enter
Pi 2 issues
I wanted an ARMv7 Pi 2, and not the current ARMv8 type. Why? Because every new generation of the ARM processor makes subtle changes to the instruction set. Usually this is to fault instructions that have been deprecated for a while, but that's not a lot of help if you have software that contains these instructions...
TemplEd
Trying to run TemplEd failed with a big scary serious looking error message.
LDMIA R13!,{R0-R2,R13,PC}
For the non-geeky among you, that is trying to load data from memory into four of the processor's internal registers. This is a pretty normal instruction. R13 is a special register that points to something called a stack. Since the processor only has a certain number of registers inside it, it is quite common to put stuff on the stack to free up those registers, and then retrieve whatever was written to the stack afterwards, that's what the "LDM" means - "LoaD Multiple" (instead of just one register at a time). To put this in human terms - you are drinking a cup of tea when the phone rings. You put the tea on the table (you stack it) and go answer the phone. When you're done with the phone call, you come back and retrieve the tea from the table and resume drinking it.
So you don't have to worry about what R13 is, you let the processor figure it out.
Zap
Catastrophe!
But the extension module that colourises C and assembler source code did not.
STR R10,[R10,#-4]!
Now this does logically work - write the value of R10 to the address R10-4 (it's a stack) and write back the new address to R10. However it is possible that making that work takes an unacceptable amount of extra logic, so the rule is simple - if the source and destination register are the same with writeback... boom!
DigitalCD
I listen to Eagle on my phone now (using the Orange Radio application). This is because using DigitalCD causes random complete freezes, anywhere from a few minutes to a half hour or so. I would imagine that it may be some sort of issue regarding, perhaps, buffering or something? I can imagine that hitting an instruction that isn't permitted when in IRQ level code might be a bit...nasty. Unfortunately the machine completely freezes (no mouse pointer movement, nothing) which makes tracking this down practically impossible.
STREQ a1,[a1],#-0
at +&2D8, but that instruction is also &04000000
so it's quite likely that it is data. Certainly, there's nothing that looks able to reach that instruction legitimately. But these are just guesses.
How did I track down these errors?
*ShowRegs
to see the registers. These may or may not be useful later (for example, if an instruction is trying to load from a weird address):
*MemoryI PC-8
to see two instructions - one of which will be faulty. Which it is depends upon how the instruction failed. A normal failure to read/write memory will be the upper instruction, however in this case a failed instruction decode will be the lower instruction. Why it is like this is because of how the pipeline works. At any rate, the problem ought to be fairly self-evident, and if you look at the comments on the right, you will see the debugger has even pointed this out with the comment ; *** Rd=Rn
.
Jeffrey Doggett, 18th August 2017, 08:54 How do you delete comments that clearly show that you're an idiot?Rob, 18th August 2017, 19:22 Jeffrey: You email Rick ... :-)Bernard, 18th August 2017, 21:00 StrongED appears to notice the danger with the LDMIA instruction because, in Dump mode, it comments it with with "; *** Rn in". Is this better than Zap?Rick, 18th August 2017, 21:30 Bernard:
Both Zap and StrongEd say "; *** Rn in list" because that is what the Debugger module says.
Jeffrey:
When I next switch my PC on (need WinSCP to access my site), I'll remove the first two comments [DONE!].
Rob:
Emailing helps, but I should receive an email every time a comment is added, though whether or not Orange deigns to pass it on to me is a bit phase-of-the-moon-ish. So, yeah, probably best to email.
Reminds me - I'd better flag the notification as Unread so I don't forget.
And back to Jeffrey:
Don't sweat it. This blog clearly shows that I'm an idiot. ;-)
© 2017 Rick Murray |
This web page is licenced for your personal, private, non-commercial use only. No automated processing by advertising systems is permitted. RIPA notice: No consent is given for interception of page transmission. |