Packing bits in XC8

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
A proficient C programmer might have written the library functions with a level of scope or encapsulation that might have eliminated the need for many ad hoc global flags.
Maybe. But they would not nearly be as fast, nor as code efficient.
 

nsaspook

Joined Aug 27, 2009
16,326
Maybe. But they would not nearly be as fast, nor as code efficient.
True, that's why some ASM is used in Linux. When the tradeoffs of HLL structure exceeds the absolute requirement for speed and efficiency it is used but it's not very often outside of the hardware bit banging needed in drivers or chip level boot code.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
True, that's why some ASM is used in Linux. When the tradeoffs of HLL structure exceeds the absolute requirement for speed and efficiency it is used but it's not very often outside of the hardware bit banging needed in drivers or chip level boot code.
Yup. And, again, I am not writing kernels, and I don't have essentially infinite RAM, ROM, and instructions cycles.

I do, though, tend to pack 10 lbs. of crap into a 5 lb. bag.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
BTW, my LED blinky code is 2 instructions long:

Code:
        btsfc   tc256ms
        btg     led
I'd love to see the C code that resolves into these 2, and only 2, instructions.
 

BobaMosfet

Joined Jul 1, 2009
2,211
Yes, that is what I thought. This just reinforces my belief that C has no place for coding small embedded processors.

If wanting to write code with as few bytes as possible is your primary concern, then by all means, assembly language is the way you should go.
 
Last edited:

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
If wanting to write code with as few bytes as possible is your primary concern, then by all means, assembly language is the way you should go.
And this would be my continued preference, as it has been for nearly 40! years.

Unfortunately, as I mentioned above, MPLab, which has excellent .asm support, is no longer supported, and does not support the newer PICs. MPLabX, while supporting all the newer silicon, has crappy .asm support.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
Done.
Code:
asm("btsfc tc256ms; btg led");
Any questions? :D
Excellent. In your example, how are tc256ms and led defined, such that they are accessible* to both the C and .asm code?

In mine, it is:

Code:
#define tc256ms tmrchg,0,0     ;bit 0 of tmrchg register
#define led     latc,0,0       ;bit 0 of latc register
*Edit: and visible to the debugger.
 
Last edited:

xox

Joined Sep 8, 2017
936
Excellent. In your example, how are tc256ms and led defined, such that they are accessible* to both the C and .asm code?
Well, which variables need to be visible from each environment? The basic pattern for the two use cases would be something like...

To access a C variable from ASM:
Code:
/*
    These should appear at global scope (not within any function)
*/
volatile short foo = 1024;
asm("EXTERN foo");
To access an ASM variable from C:
Code:
/*
    These should appear at global scope (not within any function)
*/
extern short foo;
asm("foo res 2");
asm("GLOBAL foo");
EDIT: changed "int" to "short".
 
Last edited:

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
Well, which variables need to be visible from each environment? The basic pattern for the two use cases would be something like...

To access a C variable from ASM:
Code:
/*
    These should appear at global scope (not within any function)
*/
volatile short foo = 1024;
asm("EXTERN foo");
To access an ASM variable from C:
Code:
/*
    These should appear at global scope (not within any function)
*/
extern short foo;
asm("foo res 2");
asm("GLOBAL foo");
EDIT: changed "int" to "short".
Yeah...

Well, you're making me regret starting this conversation.

Thanks anyway...
 

nsaspook

Joined Aug 27, 2009
16,326
The generic bit packing in C is implementation dependent by default but there are ways to pack bits in an efficient manner if you use the C way of handling data in the design and implementation of a program.

For my toy POV display project I'm sending raw structure data with flags and sub-byte sized fields from a Linux machine to a PIC18. XC8 uses byte alignment for C structures because it's a 8-bit chip but most 32/64-bit x86 machines default structure alignment is to pad for efficient memory access by adding byes. It's very easy to change the default with a gcc #pragma like this.
Linux machine:
https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
#pragma pack(push,1) // pack it compatiable with the PIC18 and xc8
define structures
#pragma pack(pop)


MPLAB X with xc8 on the right, Netbeans with gcc on the left. Easy to see where MPLAB X is from.:D It's very easy to initialize sequ data using the IDE for each flag or field on the
common (they could have been defined in a separate file but this is a simple example) header typedef'd structures.


The Linux code just sends a few command sequences for testing the protocol via rs232 from the sequ union structure/byte array to the PIC18 command state machine to change the current display lines as seen below.
 

Picbuster

Joined Dec 2, 2013
1,058
With the demise and continued aging of MPLab (in favor of X), I am considering porting some of my .asm libraries to XC8. But I've got a dilemma:

Each of my libraries has a set of library-dependent global flags (boolean bits) that are packed into flag bytes. In assembly, I do this in a .inc file. The register location and position of the bits are irrelevant, and tracked by the label. For example:

Code:
#define pwrup      flag0,0,0        ;0=normal/1=powering up
#define minboot    flag0,1,0        ;0=normal/1=minboot
#define shtdwn     flag0,2,0        ;1=Shutdown system
#define fsleep     flag0,3,0        ;0=Normal Operation/1=go to sleep
#define update     flag0,4,0        ;1=update display
#define fbcolon    flag0,5,0        ;1=blink colon when clock runs
#define fcold      flag0,6,0        ;1=temp too cold
#define fhot       flag0,7,0        ;1=temp too hot

#define bdead      flag1,0,0        ;1=Battery dead
#define _adrdy     flag1,1,0        ;1=On-chip A/D conversion ready
#define run        flag1,2,0        ;0=warmup/1=run
#define lbpdf      flag1,3,0        ;low battery power down flag
#define _spst      flag1,5,0        ;0=speaker lo, 1=speaker hi
#define ftest      flag1,6,0        ;0=normal, 1=test mode
#define fsecond    flag1,7,0        ;1=1 second elapsed
I do this manually, and pack all of the required bits into the fewest number of registers as possible.

I could likely do something similar in C:

C:
struct {
   unsigned pwrup   :1; //0=normal/1=powering up
   unsigned minboot :1; //0=normal/1=minboot
   unsigned shtdwn  :1; //1=Shutdown system
   unsigned fsleep  :1; //0=Normal Operation/1=go to sleep
   unsigned update  :1; //1=update display
   unsigned fbcolon :1; //1=blink colon when clock runs
   unsigned fcold   :1; //1=temp too cold
   unsigned fhot    :1; //1=temp too hot
} flag0;
But I would need to define my globals on a project (as opposed to library) basis -- depending upon the libraries I wanted to use -- and pack the bits manually into one struct per flag register, with each flag register possibly spanning multiple libraries. This is sub-optimal.

Is there a way to define global bits in XC8 in the library header files so that they are automatically packed into the smallest possible number of compiler-allocated global bytes?

Interestingly, this is easy to do in Pascal (using sets). Can C do it?
You want Boolean flags if I do understand you correct when using xc8
in your .H file

#include <stdbool.h>


bool run_this_thing;
bool Stop;

// or

struct
{
int Beep_Count;
int Beep_Int;
int Beep_Time;
int Beeps;
bool Silent; //<<<<<<<<<<<<
}Beep_Gen;

Picbuster
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
You want Boolean flags if I do understand you correct when using xc8
in your .H file

#include <stdbool.h>


bool run_this_thing;
bool Stop;

// or

struct
{
int Beep_Count;
int Beep_Int;
int Beep_Time;
int Beeps;
bool Silent; //<<<<<<<<<<<<
}Beep_Gen;

Picbuster
I am not familiar with the stdbool.h library. Does it pack multiple bits (flags) into a single register or give each flag its own register?
 

xox

Joined Sep 8, 2017
936
I am not familiar with the stdbool.h library. Does it pack multiple bits (flags) into a single register or give each flag its own register?
Nope, just imports a few C++ boolean-related constructs into a C program. Something along the lines of:
Code:
typedef unsigned char bool;
#define false 0
#define true 1
Not much else...
 

Picbuster

Joined Dec 2, 2013
1,058
putting all bool's into a byte or word is possible and do a bit test detecting true or false however; this will use more mem space then the bool structure.

Picbuster
 

BobaMosfet

Joined Jul 1, 2009
2,211
There is a reason 'C' is considered the high-level assembler. There are very few things it cannot do as well as, or almost as well as assembler, because it was written for that purpose. Maximum responsibility, maximum freedom.

So far, I haven't seen anyone discussing (in this thread) simply handcoding assembly language, stuffing it into a C variable, and then calling it with a function pointer (you have to manage the stack-frame and registers, but this is a stub on either end of the called assembly code, and is not difficult). This simply eliminates the inability of a compiler to support inline assembly.
 

nsaspook

Joined Aug 27, 2009
16,326
There is a reason 'C' is considered the high-level assembler. There are very few things it cannot do as well as, or almost as well as assembler, because it was written for that purpose. Maximum responsibility, maximum freedom.

So far, I haven't seen anyone discussing (in this thread) simply handcoding assembly language, stuffing it into a C variable, and then calling it with a function pointer (you have to manage the stack-frame and registers, but this is a stub on either end of the called assembly code, and is not difficult). This simply eliminates the inability of a compiler to support inline assembly.
This thread is not really about running asm code, it's about data structures and how you move from the hardware machine level structures of registers/bits to abstract HLL data structures in an efficient and logical manner. C is a general language that leaves details like packing and padding to the implementation on each machine type for the C abstract machine registers. Obviously this is necessary because each machines architecture is different in the way it can efficiently handle registers and bits. When you actually need hardware machine level control of the C registers/bits layout (like in my example above using rs232 data transfers) there are options to manipulate them from the default to just about any format. However, there are limits. What might be efficient and logical data structures in a ASM context dealing directly with hardware registers might not be efficient and logical data structures in a pure C context to those same hardware registers and trying to force that structure detracts from the ability of C to possibly eliminate the need for flat low level global implementations of data in the first place.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
...detracts from the ability of C to possibly eliminate the need for flat low level global implementations of data in the first place.
And as you ponder this thought, consider my objective: the tightest, fastest possible code.

In fact, Hank Smith had this goal specifically in mind when he wrote PL/M back in 1973. Damn, there were some bright guys in the 'old days' when hardware was expensive!

This gives me an idea: I wonder how hard it would be to integrate a Pic based PL/M type compiler (with some advanced concepts) into MPLabX? Now, that would be useful!
 

nsaspook

Joined Aug 27, 2009
16,326
And as you ponder this thought, consider my objective: the tightest, fastest possible code.
It's unlikely you will get that with C but what you will get with good C code is something another person can read and understand quickly if you are hit by a meteor while in the swimming pool.
 

Thread Starter

joeyd999

Joined Jun 6, 2011
6,300
It's unlikely you will get that with C but what you will get with good C code is something another person can read and understand quickly if you are hit by a meteor while in the swimming pool.
Actually, my commercial .asm code is laid out pretty damn well, in a very organized fashion, and is pretty easy to maintain.

I've seen C code written by "experienced" programmers that I wouldn't touch with your keyboard.

Writing comprehensible code is a function of the human programmer, not the language he chooses to use!
 
Top