8051 port

jwestmoreland wrote on Wednesday, August 22, 2007:

Hello All,

I’ve searched the archives - there is discussion of this port - but wanted to ask a few questions:

Is it possible to get the SP to point to XRAM (XDATA) - or will it always only point to IDATA (internal 256 byte space)?

Since the 8051 is a Harvard Architecture, I suppose it isn’t possible to get the PC to point to XRAM, but I’ve heard of some
8051 variants that fix this up - allegedly one of the TI/Chipcon chips does, haven’t checked this myself yet.

Since some of the 8051’s are fairly fast now - be nice just to have task stacks stay in XRAM without the need to swap to IDATA - just
wondering if anyone out there has tried that.  I think it may be possible to just copy the return address to IDATA to make this work
after a RETI.  Of course, SP will have to point to XRAM, not sure if that’s possible or not.

John W.

rtel wrote on Wednesday, August 22, 2007:

Using Chipcon with IAR I am able to set the option “XDATA stack reentrant”.  I think this does what you want, but access to XDATA on an 8051 is not pleasant.  I have not tried this with FreeRTOS.org (and have no plan on doing so).  8051’s are low cost, that is about the only nice thing to say about them :o)

While an ARM is an ARM is an ARM, not all ‘8051’ based processors are the same.  The Chipcon device for example has more data pointer registers than a true 8051 architecture, so things quickly get out of compatability.


jwestmoreland wrote on Wednesday, August 22, 2007:


You have no arguments from me regarding the 8051 architecture.  And I certainly agree about the ARM architecture as well.

I’m working with the C8051F120 from Silicon Labs - it has a CIP-51 core which is an enhanced MCS-51 core.  A lot of the instructions are single cycle - but I agree with the XDATA comment.  Compared to modern RISC cores, the 8051 is an
abomination - but Silicon Labs has wrapped some sexy peripherals around it.


rtel wrote on Wednesday, August 22, 2007:

I have to agree that the Sil Labs stuff is nice - they have created a smart car (http://www.smart.com/ for those not familiar) and then put a tweaked Model T Ford engine in it.  If they switched to a Cortex-M3 engine they would have a fantastic product, although probably not so low cost.


jorick23 wrote on Wednesday, August 22, 2007:

The IAR compiler can use an XDATA stack in C if the option is selected, but the IDATA and XDATA stacks are handled by software.  Every time a function call is made, the IAR library moves the return address from IDATA to XDATA.  When the function returns, the return address is popped off the XDATA stack and an LJMP is done to it.

If you’re programming in assembler, you’ll have to do all that yourself.

As for the SP register, it always points to IDATA.  It’s only a one-byte register so it’s limited to accessing 256 bytes.

adarkar9 wrote on Wednesday, August 22, 2007:

> …they have created a smart car…and then put a tweaked Model T Ford engine in it.

That is hilarious!

I work with Si Labs 8051’s on a daily basis.  They can do things a traditional 8051 never dreamed of doing.  The peripherals are very nice and are tied quite well to the processor.  Working with the architecture feels quite kludgey at first, but once you get used to it, you hardly notice it.  Sure it takes a few more instructions to access XDATA, but those instructions are running at 10ns each.

The 8051 is not good for everything, and I probably would not be using it at all if I hadn’t been forced to, but it works great for some things.

P.S.  Si Labs C8051F120 and FreeRTOS.org are a great fit.  I have two applications running great.  One of them has about a dozen tasks with quite a few queues.

jwestmoreland wrote on Wednesday, August 22, 2007:

David H.,

What tools do you use?  SDCC?

SPX (Stack Pointer for XDATA in IAR) - is a ‘virtual’ register in Data memory for the IAR tools - but still, I don’t think there’s
anyway to get the PC to point to XRAM (Harvard architecture).

John W.

jwestmoreland wrote on Thursday, August 23, 2007:


Have you used the IAR tools for the 8051 - specifically the c8051F120?

John W.

jorick23 wrote on Thursday, August 23, 2007:

Yes, I’m using IAR’s 8051 compiler, but only for the AT89S51, AT89S52, and AT89C51RB2 processors.  I’m not using the C8051F120.

adarkar9 wrote on Thursday, August 23, 2007:

John W.,

I use Keil’s C51 compiler.  As far as I know, C51 does not have a provision for using anything but the 8-bit SP for function return addresses.  I use the “copy to/from XDATA” method.  My context switch code only performs the copy if the task being switched in is not the current task.  C51 also provides a software stack in IDATA space if you use the REENTRANT attribute on any SMALL memory model functions.  My context switch code saves both stacks to XDATA.  The copy does increase context switch time, but my applications can handle it.


jwestmoreland wrote on Thursday, August 23, 2007:

Hello Ricky & David (Richard too!),

Thanks for the replies.

I’m using the copy to/from XDATA method as well.  IAR handles those pointers (residing in idata pointing to xdata, e.g.) a little differently syntactically,
but I have that working in my port.  My port is currently limping along, I’ve managed to get the timerISR to run but I seem to have a few ‘fencepost’ type of issues with idata as I can observe my stacks marching towards the end of idata… SP is being incremented someplace rather than being (re)set - so once I fix that I think the port will be in good shape.

I think I will take David’s advice and add the code to detect whether or not the current task is trying to swap itself out/in - that’ll save some time.

I’m using the REENTRANT attribute as well on the LARGE model.

John W.

jwestmoreland wrote on Friday, September 21, 2007:

I have a few general questions regarding this port.

I’ve searched the archives again for this - but want to ask some of these questions again from a tools perspective - I’m using IAR - some of you have 8051 ports working with other tool sets.

IAR doesn’t have a stack frame pointer per se as the SDCC port has.  Some of you are probably using toolsets that also don’t have a stack frame pointer.

Since this is the case - I suppose those of you that are running successful ports and are using assemblers that don’t have stack frame pointers are having to manually save usCriticalNesting - or at least you’re keeping track of Critical Nesting in the portENTER/EXIT_CRITICAL macros - correct?

Are any of you saving XSP in the task stacks?  I’m using the LARGE data model.  In the IAR tools - XSP is a 16-bit pointer that is the stack pointer for the

Are any of you keeping track of pxCode or pxCurrentTCB in your task stacks?  The 8051 pushes the return address onto the stack when an interrupt occurs -
so I don’t think this is necessary but am wondering how others have handled this.  The SDCC port pushes pxCode initially to mimic what the stack would
like like during an IRQ but the portSAVE/RESTORE_CONTEXT macros in the SDCC port do not push/pop pxCode since the processor pushes the return address during
an IRQ.

Thanks in advance,
John W.

adarkar9 wrote on Friday, September 21, 2007:

I can answer these questions from the point of view of my Keil C51 port.

- C51 does not have a stack frame pointer.

- My port keeps track of critical nesting in the portENTER/EXIT_CRITICAL macros and manually saves "usCriticalNesting" in the portSAVE/RESTORE macros.

- C51 does not have an XPS, but it does have a ?C_XPB.  ?C_XPB is C51’s 16-bit large model reentrant stack pointer.  My port saves ?C_XPB in the task stacks.

- My port handles pxCode the same as the SDCC port.  pxPortInitialiseStack() puts it on the stack and the hardware takes care of the rest.  I do not keep track of pxCurrentTCB in my task stacks, nor can I think of why one would.


jwestmoreland wrote on Friday, September 21, 2007:


Thanks for your response.

I’ve gleaned that I need to do the equivalent with the IAR toolset.  I’m effectively doing the same thing as we’ve both outlined above.  I am seeing a problem - maybe it’s just a bug on my part - where it appears pxCurrentTCB is getting the stack size value vs. the actual address of the current TCB - making me think that the pxCurrentTCB may need to be saved/restored - but I suppose
that’s a bug on my end.  If you look at TCB’s for most RTOS’s - the task address is almost always saved as part of the tasks stack.

It isn’t clear to me how the SDCC 8051 port handles Critical Nesting - it doesn’t look like it does.  It’s hard for me to believe that it works when a nested interrupt occurs - but since this is a CISC machine vs. RISC - and I’m more accustomed to the RISC
machines - I guess some CISC ‘magic’ can be occuring that makes it work in the SDCC port.  It also uses its almost magical stack
frame pointer that seems to make a lot of these issues ‘go away’ - but that’s kindof hard for me to believe as well.

Is anyone out there actually using the SDCC port ‘as-is’ - and it works for you?

It’d be nice if we could post some notes on how to make the 8051 ports work for tools other than the SDCC tools.
I will post some general notes regarding the IAR port.  This will be helpful to others in the future.

If some of you that have successful ports running could post your port.c, portmacro.h, and any port<asm>.<asm> that would be
extremely helpful.  I will post mine when complete.

Richard works pretty hard to make FreeRTOS available to the universe; I think the least the rest of us can do is to post our port work.  I’ve done this for my MSP430 ports that I have working.  I must admit getting this off the ground in the RISC world is
easier than CISC - at least it has been for me.

John W.

adarkar9 wrote on Friday, September 21, 2007:

> …the pxCurrentTCB may need to be saved/restored…

Won’t the value of pxCurrentTCB always be the same for any one task?  After all, it is the current TCB while that task is running.  Only vTaskSwitchContext() should change the value of pxCurrentTCB and this is only in a very well controlled manner.

> It isn’t clear to me how the SDCC 8051 port handles Critical Nesting…I guess some CISC ‘magic’…

No magic here.  Let me explain.  Here is the code for entering a critical section:

#define portENTER_CRITICAL()    _asm       
                push    ACC   
                push    IE   
                EA = 0;

The SDCC port pushes the interrupt enable (IE) register on the stack every time portENTER_CRITICAL() is called (and the accumulator, you’ll see why in a bit).  Then it clears the global interrupt enable bit (EA).  Each nesting will get two more bytes pushed on the stack (and get interrupt disabled again).

Now, here is the code for exiting a critical section:

#define portEXIT_CRITICAL()    _asm       
                pop    ACC   
                ACC &= 0x80;   
                IE |= ACC;   
                pop    ACC   

The saved value of IE is poped into ACC, all the bits except EA are masked off, and the result is OR’ed into IE.  Because only the first call to portENTER_CRITICAL() will have had EA set, only the corresponding call to portEXIT_CRITICAL() that pops off that first copy of IE will actually result in EA being set.  This method is nice because it does not require a per task count, but it could end up using more stack space if you next your critical section deeply.

I started with the SDCC port.  I got it running on my target hardware and verified correct operation before I ported it to Keil’s C51.  It worked fine “as-is”.

I only changed to the critical nesting count because the C51’s inline assembly support is, uh, less than perfect.

> [SDCC] also uses its almost magical stack frame pointer…

I am no SDCC expert, but I did not come across any discussion of a stack frame pointer during my brief foray.  I don’t believe the SDCC port uses this feature.

> …post your port.c, [etc.]

I have been waiting for the development effort to settle down a bit before doing this, but I haven’t touched the RTOS files for quite a while.  I’ll send my port to Richard.


jwestmoreland wrote on Friday, September 21, 2007:


Thanks for your reply.

The SDCC port uses push _bp and pop _bp in its portSAVE/RESTORE_CONTEXT’s respectively.  According to the SDCC docs this is the stack frame pointer for the SDCC assembler.


jwestmoreland wrote on Wednesday, September 26, 2007:

I’ve been able to get the timer2ISR and IDLE task to run without problems using the IAR toolset.  However, when I add a task the system fails. 

As far as the IDATA stack goes for those of you with working ports (besides Cygnal) - do you have the task stacks (when they are
copied) and the stack space allocated for system functions sharing the same IDATA space?  Has anyone found it necessary to save
off the SP (DATA/IDATA) in the context switch?

In case you’re wondering - in the IAR toolset you can say something like use 0x50 bytes for IDATA stack and then you can set
the start of the stack space for the tasks to be something like 0x82 - and only use values below 0xb0 for the task stack
swap space (0x82-0xad being used for stack swap and 0xb0-0xff being used for system IDATA stack).  For my current system
this is adequate but it still fails after just adding one simple task.


jwestmoreland wrote on Thursday, October 11, 2007:


When using the XDATA reentrant model under IAR - when an interrupt occurs, does it also do the same thing as in a function return?
Pops off the XDATA stack & LJMP is done?  I’ve looked for this in the IAR docs but haven’t found it.  I’m using the 7.30B version
of the MCS-51 tools from IAR.  I’ve even e-mailed their tech support with this question and am still waiting for an answer.

Can you make your IAR ports available to Richard?

Specifically, it would be nice to take a look at your port.c, portmacro.h, and and port<asm>.<asm> files and also your workspace

My e-mail address is john <at> WestmorelandEngineering <dot> com - I’d like to be cc’ed if you send the files to Richard.

Thanks In Advance,
John W.