Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
With such a limited ram and stack you can't really have a context.
You have to "interleave" the code for the different tasks together into one stream.
Writing in assembler is the easy way to use a jump/branch for subroutine calls - but with only 256 bytes of ram doesn't leave you any space to save registers (unless that is a typo and would be 256k).
And the hardware has to have a way to set the stack. If there is no stack then you have to emulate one in software (the only processor I ever had even remote contact with that was as limited was an 8008). Having only 8 entries in a stack means that any use of the stack has to be copied off the stack before any other use - thus a software emulated stack which lets you do anything you want.
Using a subroutine call to start a context switch is just a way to start saving the context. Otherwise you have to save a resume address, and jump to the context save - which is just a software subroutine call...
Number of tasks will probably be small - 4 to 5. I will be collecting weather data and it looks like I will be able to average it over time. Collecting rain, wind, humidity, temperature and light levels and if averaged the absolute worst case would be 32 bits each or 4X5 twenty bytes. I will need some bytes for I2C communications say another 20 or 30 tops. I have 256 bytes so that is 50 gone. say another 30 for incidental operations that is 80 bytes total to do the operation max. That leaves about 176 for the OS. Two bytes for the return address, one byte for the w register two bytes for status register and that is about it. I think it is doable. It is amazing what you can do with 256 bytes of ram and 3500 lines of program (350 lines of C worst case). The total OS may be only 100 lines of C. Most of the C would be loads and stores. In some ways I am thinking about it just to see what can be done. The computer cost about $1.23 in lots of one. Pretty wild huh.
The other way is foreground / background with a super loop in the background of state machines so you can exit and save state. Salvo does not seem to use the hardware stack at all with all context switching being done at task level - if a subroutine is called it must return to the calling task before a yield to the operating system occurs to keep the hardware stack empty. The yield is just a macro with an assembler branch to the os after saving registers and the location to return to.
My problem is I don't know if I will have to save the peripherals registers. I know to save the w (byte), return address (2 bytes) the F which I think is two bytes and the status register which I think is 2 bytes. Since CCS C functions set up the peripherals before use I don't think their state needs to be saved. Thanks for your input and your lengthy explanation above.
I wouldn't think so. The device operates independantly. The only device that gets shared use is normally just a terminal/graphic interface. Sometimes that needs to be saved/restored as different tasks might want it setup differently. But that would be quite unusual as shared resources usually have a driver that manages the device - and that handles things directly, and thus not require save/restore on context switches.
Normally devices get set to a known state - and they stay that way. Only if a physical interface is being mucked with by two tasks - and you won't know when... In which case you need a semaphore to control access - in which case the task that has locked the device for use can trust the device until the semaphore is released.
You might consider the dsPIC or PIC24 for your stack machine. They are 16 bit and are stack based. PIC32 is MIPS based and 32 bit which may be a natural for your stack machine. It has 512k flash words and 512k bytes ram in the largest machines. Max speed for the PIC32 is 200 mips. See: http://en.wikipedia.org/wiki/PIC_microcontroller
So hows it going. Have not heard from you in a while. You probably have everything working already. I only have PRINT, STOP and LIST working and am using PRINT to debug such things as the infix_to_postfix routine, Unary routine, etc. UNARY was not working and I found that I had a parameter representing an operation as unsigned char instead of short. Took a while to find that mostly with print statements. Once that was fixed infix to postfix and unary worked except now it is giving me a parenthesis error when they are correct. Used the malfunction parenthesis error to build a routine to display the line number and line and put a ^ under the start of the error. Tomorrow I will look into fixing the parenthesis error. I have print statements in #ifdef blocks - must have as many print statements as I have code statements.
I am also working on a weather measuring device to aid in the prediction of time between mists for plant propagation using cuttings. Was able to use a 8 pin MCU to act as a I2C slave while measuring Wind, Temperature, Humidity, Light and Rain all with only 5 I/Os and 1 I. It only has 256 bytes of ram and space for 4k instructions and I think I can get a very small RTOS to run in it as well. All for $1.65. It will run at 32 MHz, Has a PLL in it with a top speed of 8 MIPS. I will run it at 1 MIP with a 0.01 second tic timer. It should be able to run 10,000 instructions in 0.01 second so I think it will get through all tasks at that speed.
One thing that used to help with the prints were macros - in the simple case something like:
Code:
#if defined (DEBug)
#define DEBUG(a,b,c) fprintf(stderr,a,b,c)
#else
#define DEBUG(a,b,c)
#endif
This way the macro is all it needs, and the DEBUG lines are always present, but if the debug symbol DEBug is not defined, they are all translated into nothing, and disappear from the compiled code.
Now you would have to lookup how a variable number of parameters are handled (I think they are) but it can simplify all the test codes.
With the GNU C I believe it can even be extended to inline functions that either exist... or are #defined to be empty - and again, no code gets generated without the debug symbol being defined.
I believe an example is in some of the ASSERT macros (though they can be a bit complex, there are examples of even including expressions as part of the parameter list).
One advantage this has is that the debug code remains within the program, and allow portions to be enabled/disabled on gcc command line (using the -D option to define symbols). This way the debug code can be re-enabled for future bug hunts that may involve code with existing debugging capability.
You might find this course interesting: https://www.coursera.org/course/algo It is a course on algorithms - the first given by Stanford to undergraduates and graduate students. It is a required course for all degrees at Stanford. Alvin...
Nope. But it does look interesting for really small CPUs.
I've looked at their "Under the Hood" section - it actually just encapsulates a switch.
Syntacticly, it still uses a stack to call the functions, but the switch control determines how the body of the function is actually used. So there is added overhead for the function call even if the function does nothing.
Now I have not looked at the full implementation, so there could be other features that may reduce that overhead or the effect of that overhead.
I need to be able to define a unique label in a #define macro. I thought about using __LINE__ with an L in front of it But I need to define the label on one line and reference the same label on another. Any ideas? Thanks alvin...
I'm not sure why you would need that... since even a normal label has to be unique...
But as long as you never use forward references using a #define might do the trick. I'm not sure if it would work though, but since macro definitions are lexical symbols I would think it would.
The problem with forward references is that the #define will only occur when the label is created, thus references could be used AFTER that point in the code.
I've done some limited testing with the __lineno__... I couldn't use a "#define" to capture the label for use in a goto - all that did was a textual substitution. The __lineno__ would not be evaluated to provide a number, until it was expanded later - at which time the wrong value is provided.
I don't think it will work the way you describe. It is not designed to be used for labels. And hiding an actual label will make things MUCH harder to debug.
PS. The reason I had problems was that I couldn't USE the label so generated... Putting the __line__ gets a different value where the goto is used...
The usual way is by use of an "inline" function as the function provides the context for the label and its goto.
If I could set some sort of variable (macro variable) equal to __LINE__ and then concatenate it with an L in front that would do it but #define does not seem to have the facilities needed to do this. Pseudo code:
Code:
&1 = __LINE__ // to set the label only this line number is used. &1 is a variable not a macro.
// to reference the label:
MOVLW high L||&1
MOVWF return_high
MOVLW low L||&1
MOVWF return_low
.
.
.
goto yield;
L||&1: //return
wish #define was a more complete macro processor. Any ideas?
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.