crt0.s for r2k, r2ka and r3ka creates internal interrupt table in Flash, which has several bugs:
- Location of the secondary watchdog is incorrectly set to
0x100
intead of 0x110
so it overrides the periodic interrupt's ISR.
- Several ISRs use
reti
instruction, which is wrong. It should be ipres
and ret
instead.
- Having interrupt table in Flash where it cannot be modified is pointless IMHO. Especially since there is no support in sdcc for creating ISRs. So, one essentially has to re-create it from scratch in RAM.
So, I've fixed the above things, but I can't for the life of me get interrupts to work. As soon as I enable one of the interrupts, the board hangs.
I've reduced the code to the point, where I have my test bits inside crt0.s (attached). If I don't enable any interrupts, I get blinking lights. As soon as I un-comment either
call _enable_periodic
orcall _enable_timer_b
-- no blinking lights.I do have proper ISR stubs in the vector table for both. Not sure what's going on.
Could someone please help?
Last edit: D-mo 2023-09-21
Have you checked that all your code ends up at the correct addresses (you can see that in the .rst file)?
Also: can you post the .lst and .rst files here?
Have you checked if your program still works with minimal interrupt handlers (i.e. just returning from the interrupt, but not doing anything else)?
Last edit: Philipp Klaus Krause 2023-09-22
I've created the current Rabbit crt0 in 2020 - before they were so wrong, they worked with the simulator only. The current ones "worked" (I was able to run benchmarks, and see the results on the serial console) for me on a few RCM boards, but I did not do any further testing of any advanced stuff, such as interrupts.
Back then my goal was to support the Rabbits in the code size / peed regression testing (those graphs at https://sourceforge.net/p/sdcc/code/HEAD/tree/trunk/sdcc-extra/historygraphs/), but OpenRabbit never became reliable enough for that - it tended to hang about once in five times I flashed the Rabbit.
Thus, the only testing the Rabbits get is via the nightly regression testing using the uC simulator. That works very well for ensuring that SDCC generates correct code from C source, but doesn't cover µC-specific stuff, such as interrupts, well.
Also, the Rabbit ports don't have a lot of users - I guess the problem is that very few people are starting new projects with Rabbits, and the current Rabbit users don't want to migrate their existing code from Dynamic C to SDCC, especially, since they often use libraries written for Dynamic C.
So thanks for doing some testing on real hardware, and helping improve the Rabbit crt0(.)s.
The interrupt table is in flash with no support in SDCC for creating handlers for historial reasons: This is a reasonable choice for Z80 (interrupt handling varies widely on Z80-based systems, so having an example crt0 that the user then can adapt to their needs and reassemble themselves is all we can do).
The Rabbit ports were derived from the Z80 ports, so they inherited this. I guess, it would make more sense to have a table in flash, but allow specifying the handlers from C via the
__interrupt(N)
syntax, like e.g. the stm8 port does.Related
Commit: [r14359]
Last edit: Maarten Brock 2023-10-13
Thanks Philipp, I got it sorted out. There were two things going on:
"The internal interrupt vector table occupies 512 bytes, and the external interrupt vector
table is 256 bytes in size. Since the RST and SYSCALL vectors use all eight bits of the
IIR for addressing, the lowermost bit of IIR should always be set to zero so to keep some
vectors from inadvertently overlapping."
I've highlighted the important bit. I am not doing anything with syscalls or RSTs, but for some reason if IIR is set to an odd number, the interrupts don't work -- the board hangs.
In the current crt0 the interrupt table is at address
0x0100
, which meansIIR
is set to0x01
(odd number) and the board will hang. In my testing I've moved the interrupt table into RAM at address0xdd00
, which also caused the board to hang (since0xdd
is also an odd number). Once I've moved it to0xdc00
everything started working fine.I've ended up re-writing crt0 quite a bit to suit my needs. Feel free to grab any bits from it (attached) if you want.
I've now found that sentence in the Rabbit 4000 user manual, and later revisions of the Rabbit 3000 user manual, but not in the Rabbit 2000 user manuals, and earlier revisions of the Rabbit 3000 user manual. AFAIK, the Rabbit 3000 and 4000 have a 512B internal interrupt table, while Rabbit 2000 has a 256B one.
On which hardware did you encounter the problem?
I still wonder why the odd value in iir triggers an issue for you - after all, from the tables, it looks like an odd value in iir would just make rst 0x38 overlap with the interrupt handler for the pwm interrupt, which should be fine as long as those are not used.
Yeah, I am not sure either. That sentence honestly is a bit confusing.
I suspect that later Rabbit boards simply ignore the lowest bit of IIR. In table B.1.2 at the end of the manual they list a bunch of ISRs that do that. Eg, for Timer B they say:
{IIR[7:1], 0, 0x00B0}
Although periodic interrupt is not listed, it could just be an omission...
OK I've just confirmed that bit 0 of IIR gets simply ignored.
I've loaded
0xdd
into IIR and placed my periodic ISR at address0xdc00
(instead of0xdd00
) and everything was working fine.Last edit: D-mo 2023-09-27
Thanks. I now also found the info in the Rabbit 3000 user manuals. This is clearly a breaking change from the Rabbit 2000.
I'll update the crt0 in SDCC accordingly.
Done in [r14361].
Related
Commit: [r14361]
Hehe. Well, it probably worked for two reasons:
1. all interrupts are disabled by default;
2. the board runs at IP (interrupt priority) 3 by default, so even if you enable any of them, they won't fire until you drop to lower priority.
:)
Interesting. I wrote my own utility (rabbit-util) before I came across OpenRabbit and ended up using it as a reference in a few cases. Mine also hangs once in a while but not that often.
I am one of those people. :) I've got close to 500 Rabbits (if not more) that have been running for over 10 year. Didn't think I'd ever need to touch them. But, now I need to update them all due to circumstances outside of my control.
I've switched to Linux many years ago and didn't really feel like going back to Windows and Dynamic C. So, thanks to you and all the other folks that have ported sdcc to work with them.
Last edit: D-mo 2023-09-22
Here is the final version. There are two differences from the original (other than fixing the interrupt table):
I can't put these into SDCC's crt0. The crt0 that comes with SDCC should contain safe defaults. Users can write a custom crt0 based on the SDCC one, or set clocks and wait states in
__sdcc_external_startup
.Can you have a look at the crt0 in current SDCC svn, to see if it is okayish?
I haven't made the reti vs. ipres change yet, as I don't feel comfortable enough with Rabbit interrupt handling yet.
Sorry, I've missed this.
No problem, I understand.
reti
is a chained version ofpop ip
+ret
. So, if you are going to usereti
, you need to addpush ip
as a first instruction in the isr. In reality, I haven't seen it used much even in the Digi's own BIOS code:Most of the time you just see
ipres
+ret
, which saves 9 clocks compared topush ip
+reti
.Last edit: D-mo 2023-10-02
A more fundamental question, I guess, is the usefulness of this table, since:
There is also the External interrupt table (using the EIR register), which is not provided at all.
If you are cool with my approach of stealing 1K from the stack and using the range of
0xdc00 - 0xdfff
for the internal and external tables, I can submit a patched version of crt0.s with just those changes (and some clean-ups).I wouldn't fill it with any stub ISRs though, for the above reasons (points 1 and 3).
Last edit: D-mo 2023-10-03
I'd rather keep the table in the Flash. The default crt0 can still serve as a starting point for users to make a custom crt0.
It's up to you of course.
But, in case you change your mind, here is the version I am currently using. I've got periodic interrupt working, as well as interrupts for serial ports A and B.
I've made the reti vs ipres / ret change in [r14379]. That should make the crt0 more useful as a starting point for user's custom ones. With this last change, AFAIK all the bugs are fixed (though one might consider further crt0 improvements that would be feature requests).
Related
Commit: [r14379]