$0.03 microcontroller

Ok, thanks. So much for using Google to translate currency. You just saved my fledgling import, export, arbitrage business!

Rick C.

Reply to
gnuarm.deletethisbit
Loading thread data ...

If you do not have efficient stack pointer relative addressing modes, why would you put local variables on stack ?

Just create global variables Tmp1, Tmp2, Tmp3 ... and use these as function local variables. As long as two functions do not call each other directly or indirectly, you can safely use these global variables as function local variables.

To make your program even prettier, use function specific aliases for Tmp1, Tnp2 etc.. by using #define statements in C or multiple labels in assembly language storage allocation.

Why do you need a linker for such small processor.? Since you are going to use a cross-copiler on a PC with mega/gigabytes of memory, you just compile/assemble everything into binary at once.

See above, no need for linker or stack variables.

The question is, do you even need full scale parameter passing ?

Function h() could use some predefined memory locations and both f() and g() can put the parameter into those memory locations before calling h(). Only those parameters that are different when calling from f() or g() needs to be passed, h() can get the parameters that are the same in both cases do not need to be passed, h() knows the parameter already at startup.

Of course such tricks becomes impractical with larger system, but with

1 KW / 64 B, this should definitely be doable.
Reply to
upsidedown

Am 15.10.2018 um 10:44 schrieb Philipp Klaus Krause:

Absolutely not. Reentrant functions are a massive nuisance on fully embedded systems, if only because they routinely make it impossible to determine the actual stack size usage.

And without such an addressing mode, you don't, because you'll suffer badly in every conceivable aspect.

So don't mark them 'static', unless they actually have to be.

On the contrary: it's precisely the compilers for such stack-starved architectures (e.g. the 8051) that have been coupling behind-the-scenes static allocation of automatic variables with whole-program overlay analysis since effectively forever. They really had to, because the alternative would be painful to the point of being unusable.

Reply to
Hans-Bernhard Bröker

anyhting supported by GCC tends to have rather powerful insturction sets and plenty of registers aynway, so functions could be made reentrant by default without any problems resulting.

While some link-time optimizations are commonly requested features for SDCC, currently none are supported. In SDCC, even inter-procedural optimizations within the same translation unit are not as powerful as they should be. Well, there always is a lot of work to do on SDCC, and there are only a few volunteers with time to work on it. So SDCC developers priorize (usually by personal preferences).

Still, when looking at the big picture, SDCC is doing quite well compared to other compilers for the same architectures (see e.g.

formatting link
- comparison from early

2018, around the time of the SDCC 3.7.0 release - current SDCC is 3.8.0).

Philipp

Reply to
Philipp Klaus Krause

Am 15.10.2018 um 20:34 schrieb snipped-for-privacy@downunder.com:

1) The question was "With such small ROM/RAM sizes, who needs reentrant functions ?". And it was a reply to a post were the lack of a effiednt sp-relative addressing mode was cited as a disadvatage of the Padauk. So my reasoning was, that one would want local variables on the stack, even for small RAM / ROM, so the lack of sp-relative addressing is a disadvatage - as one has to either put local variables elsewhere or handle stackk accesses in an inefficent way. 2) There will still be some use cases for reentrant functions. And since the Padauk has a relatively large ROM - at least compared to the RAM (the ROM/RAM ratio seems far higher than on typical STM8 or MCS-51 devices), when speed doesn't matter, maybe it might still be worth putting variables on the stack. A compiler should provide an option for that (as, e.g. SDCC does for architectures without efficnet stack access, such as MCS-51 or HC08).

I'd rather write idiomatic C anmd leave such optimizations to the compiler.

Philipp

Reply to
Philipp Klaus Krause

What is the problem? Either you use recursion - in which case the functions need to be reentrant, there is no alternative, or you don't. In the latter case you'd need to do whole-program analysis to efficiently overlay the variables - a very similar analysis could tell you the the total stack usage.

Yes. So compilers like SDCC when targeting MCS-51 or HC08 don't use the stack by default (--stack-auto puts local variables on the stack per-file, __reentrant does so per function).

Well, SDCC when targeting MCS-51 or HC08 would be the combination that I know a bit about (though personally, I mostly use SDCC to target Z80 or STM8, which can both use the stack efficiently). SDCC doesn't really have link-time optimization yet, compilation units are handled independently. Regarding different compilation units, it can still overlay the variables of leaf functions - i.e. non-reentrant differnet that do not call non-reentrant functions, but not much more.

Philipp

Reply to
Philipp Klaus Krause

No.

Most gcc targets are quite powerful, with plenty of registers - and re-entrancy is not a problem. Some are a bit weaker, like the 8-bit AVR, and get inefficient with complicated stack usage. But it does not support the 8-bit CISC accumulator-based devices that SDCC targets.

Reply to
David Brown

Am 16.10.2018 um 10:00 schrieb Philipp Klaus Krause:

The major part of it is that I mixed up Reentrance with Recursion there ... sorry for that.

OTOH, one does tend to influence the other. Without recursion, one would only really need reentrance to be able to call the same function from separate threads of execution. On controllers this small, that would only happen if you're calling the same function from inside an interrupt handler and the main loop. And frankly: you really don't want to do that. If an ISR on this kind of hardware becomes big enough you feel the need to split it into sub-functions, that almost certainly means you've picked entirely the wrong tool for the job.

In other words: for this kind of system (very small, with rotten stack-based addressing), not only doesn't everyone need re-entrant functions, it's more like nobody does.

I don't think anyone has ever seriously claimed SDCC to be anywhere near the pinnacle of compiler design for the 8051. ;-P

Frankly, just looking at statements in this thread has me thinking that the usual suspects among commercial offerings from 20 years ago might still run circles around it today.

Well, given the gigantic scale differences between the target hardware and the build host, just turning the whole thing into a single compilation unit (by force, if necessary) should really be a no-brainer.

Reply to
Hans-Bernhard Bröker

I don't believe this is correct. Reentrance is a problem any time a routin e is entered again before it is exited from a prior call. This can happen without multiple threads when a routine is called from a routine that was u ltimately called from within the routine. I suppose you might consider thi s to be recursion, but my point is this can happen without the intent of us ing recursion.

Rick C.

Reply to
gnuarm.deletethisbit

Am 16.10.2018 um 23:01 schrieb snipped-for-privacy@gmail.com:

Oh, there's no doubt about it: that's recursion all right.

Some might prefer to qualify it as indirect recursion, a.k.a. a loop in the call graph, but it's still recursion.

I'll asume we agree on this: unintended recursion is clear a bug in the code, every time.

That could arguably be classified an actual benefit of using a such a stack-starved CPU architecture: any competent C compiler for it will have to perform call tree analysis anyway, so it finds that particular bug "en passant".

More typical C toolchains relying on stack-centric calling conventions might not bother with such analysis, and thus won't see the bug. Until you use the accompanying stack size calculation tool, that is, which will barf.

Reply to
Hans-Bernhard Bröker

We call it mutual recursion.

Reply to
Clifford Heath

Clearly there would be a bug, but it is just as much that the routine wasn' t designed for recursion and that would be the most likely fix.

Are you swearing at me in French? ;)

Yeah, I'm not much of a C programmer, so I wouldn't know about such tools. What made me think of this is a problem often encountered by novices in Fo rth. Some system words use globally static data and can be called twice fr om different code before the first call has ended use of the data structure . Not quite the same thing as recursion, but the same result.

Rick C.

Reply to
gnuarm.deletethisbit

I think we can agree that /any/ unintended action is a clear bug in the code!

But recursion or re-entrancy without a clear purpose and careful limits on depths is a bug in the /design/, not just the code.

When I am faced with someone else's code to examine or maintain, I often run it through Doxygen with "generate documentation for /everything/ - caller graphs, callee graphs, cross-linked source, etc." It can make it quick to jump around in the code. And recursive (or re-entrant, whichever you prefer) code stands out like a sore thumb, as long as the code is single-threaded - you get loops in the call graphs.

The only other case is if interrupts call other functions - that won't be seen so easily.

Reply to
David Brown

Multithreading matters here. It is not common on such small devices, but this one is an exception: Padauk sells multiple dual-core variants of this controller and one 8-core variant. And there is always the support functions the compilers tend to need on small systems (while I assume people would think twice before using an expensive division in an interrupt handler, the situation looks different for multithreading).

I don't know of a current comparison for the MCS-51.

For MCS-51, I do not know of a good compiler comparison; I did some benchmarks a while ago

formatting link
and SDCC still has a bit of catching-up to do.

On the other hand, for the STM8, SDCC seems to be doing more than just okay:

formatting link

Philipp

Reply to
Philipp Klaus Krause

On 18-10-17 01:46 , David Brown wrote: ...

Anecdote: some years ago, when I was applying a WCET analysis tool to someone else's program, the tool found recursion. This surprised the people I was working with, because they had generated call graphs for the program, analysed them visually, and found no recursive, looping paths.

Turned out that they had asked the call-graph tool to optimize the size of the window used to display the call-graphs. The tool did as it was told, with the result that the line segments on the path for the recursive call went down to the bottom edge of the diagram, then

*merged* with the lower border line of the diagram, followed that lower border, went up one side of the diagram -- still merged with the border line -- and then reentered the diagram to point at the source of the recursive call, effectively making the loop very hard to see...

(It turned out that this recursion was intentional. At this point, the program was sending an alarm message, but the alarm buffer was full, so the alarm routine called itself to send an alarm about the full buffer

-- and that worked, because one buffer slot was reserved, by design, for this "buffer full" alarm.)

--
Niklas Holsti 
Tidorum Ltd 
 Click to see the full signature
Reply to
Niklas Holsti

Visual tools are helpful, but don't show everything!

On the other hand, they can show things that can be hard to quantify in more rigorous tools. It is easy to look at the call graph of a function and say "that function is a bowl of spaghetti, and needs restructured" - it's harder to define rules or limits for an automatic checker that make such judgements.

I can appreciate the purpose here, but I would rather have this:

static bool putAlarmInLog(alarmPtr slot, ...) { ... }

static alarmSlot_t alarmSlots[maxAlarmSlots]; static alarmSlot_t emergencyAlarmSlot;

static alarmPtr findFreeAlarmSlot(void) { ... }

void logAlarm(...) { alarmPtr = findFreeAlarmSlot(); if (alarmPtr) { putAlarmInLog(alarmPtr, ...); } else { putAlarmInLog(&emergencyAlarmSlot, "Buffer full"); } }

Hoist the condition checks up a step, and put the actual storage mechanism down a step, and you no longer have the re-entrancy. The code is a lot easier to write, read, analyse and test.

Reply to
David Brown

Seems to me what actually failed was that they knew they had recursion in the design but didn't realize the fact that they didn't see the recursion in the call graphs was an error that should have been caught.

Rick C.

Reply to
gnuarm.deletethisbit

Recursion simply is a particlar useage of re-entrance: a function calling itself (possibly indirectly through other functions).

You can use re-entrant functions without using recursion, but you can't recurse without re-entrant functions.

Of course, re-entrance doesn't depend on a CPU stack ... it requires only that the local variables of each instance be kept separate. That can be done with auxiliary data structures. [It's interesting to watch programming students reinvent recursion - accidentally, or as an exercise - and realize all the effort saved by having it built into the language.]

George

Reply to
George Neuner

The guys creating and viewing the call-graphs were not the designers of the program, either, so they didn't know, but for sure it was something they should have discovered and remarked on as part of their work.

--
Niklas Holsti 
Tidorum Ltd 
 Click to see the full signature
Reply to
Niklas Holsti

While I have been playing around with the idea of making some RTOS for such 1kW/64B machine (realistically supporting 2-3 tasks such as a foregroud/bacground monitor) realistically having 2 or 8 thread is no very realistic, even if the hardware supports it.

The 8 core version might be usable for xCore style "pseudo-interupts" running a single DSP sample or PLC loop at a time. This would require

8 input pins, each starting its own thread.

But of course, the same rules should apply to pseudo-interrupts as real interrupts regarding re-entrancy etc.

Reply to
upsidedown

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.