Difference between bit and sbit? - embedded

What is the difference between the bit and sbit keywords in Keil C51 for the 8051 Microcontroller?
When should sbit be used and when bit?
Some examples would be very helpful.

This should help you :
BIT
C51 provides you with a bit data type which may be used for variable
declarations, argument lists, and function return values. A bit
variable is declared just as other C data types are declared. For
example:
static bit done_flag = 0; /* bit variable */
bit testfunc ( /* bit function */
bit flag1, /* bit arguments */
bit flag2)
{
.
.
.
return (0); /* bit return value */
}
All bit variables are stored in a bit segment located in the internal
memory area of the 8051. Because this area is only 16 bytes long, a
maximum of 128 bit variables may be declared within any one scope.
Memory types may be included in the declaration of a bit variable.
However, because bit variables are stored in the internal data area of
the 8051, the data and idata memory types only may be included in the
declaration. Any other memory types are invalid.
The following restrictions apply to bit variables and bit
declarations:
Functions which use disabled interrupts (#pragma disable) and functions that are declared using an explicit register bank (using n)
cannot return a bit value. The C51 compiler generates an error message
for functions of this type that attempt to return a bit type.
A bit cannot be declared as a pointer. For example:
bit *ptr
An array of type bit is invalid. For example:
bit ware [5]
SBIT
With typical 8051 applications, it is often necessary to access
individual bits within an SFR. The C51 compiler makes this possible
with the sbit data type. The sbit data type allows you to access
bit-addressable SFRs. For example:
sbit EA = 0xAF;
This declaration defines EA to be the SFR bit at address 0xAF. On the
8051, this is the enable all bit in the interrupt enable register.
NOTE:
Not all SFRs are bit-addressable. Only those SFRs whose address is
evenly divisible by 8 are bit-addressable. These SFR’s lower nibble
will be either 0 or 8; for example, SFRs at 0xA8 and 0xD0 are
bit-addressable, whereas SFRs at 0xC7 and 0xEB are not. SFR bit
addresses are easy to calculate. Add the bit position to the SFR byte
address to get the SFR bit address. So, to access bit 6 in the SFR at
0xC8, the SFR bit address would be 0xCE (0xC8 + 6).
Any symbolic name can be used in an sbit declaration. The expression
to the right of the equal sign (=) specifies an absolute bit address
for the symbolic name. There are three variants for specifying the
address.
Variant 1:
sfr_name ^ int_constant
This variant uses a previously-declared sfr (sfr_name) as the base
address for the sbit. The address of the existing SFR must be evenly
divisible by 8. The expression following the carat symbol (^)
specifies the position of the bit to access with this declaration. The
bit position must be a number in the range 0 to 7. For example:
sfr PSW = 0xD0;
sfr IE = 0xA8;
sbit OV = PSW ^ 2;
sbit CY = PSW ^ 7;
sbit EA = IE ^ 7;
Variant 2:
int_constant ^ int_constant
This variant uses an integer constant as the base address for the
sbit. The base address value must be evenly divisible by 8. The
expression following the carat symbol (^) specifies the position of
the bit to access with this declaration. The bit position must be a
number in the range 0 to 7. For example:
sbit OV = 0xD0 ^ 2;
sbit CY = 0xD0 ^ 7;
sbit EA = 0xA8 ^ 7;
Variant 3:
int_constant
This variant uses an absolute bit address for the sbit. For example:
sbit OV = 0xD2;
sbit CY = 0xD7;
sbit EA = 0xAF;
NOTES :
Special function bits represent an independent declaration class that
may not be interchanged with other bit declarations or bit fields.
The sbit data type declaration may be used to access individual bits
of variables declared with the bdata memory type specifier
Source :
BIT and SBIT

Check this forum:
The main difference between the bit and sbit is that you can declare
sbit a varible in a unit in such way that it points to a specific bit
in the SFR register. In the main program you need to specify to which
register this sbit points to.
dim Abit as sbit sfr external ' Abit is precisely defined in some external file, for example
in the main program unit
...
implements
....
end.
The mikroBasic PRO for PIC compiler provides a bit data type that may
be used for variable declarations. It can not be used for argument
lists, and function-return values, there are no pointers to bit
variables, and an array of type bit is not valid.
dim bf as bit ' bit variable
sbit is not a new variable and does not take extra memory space, while
with a bit different, will the new variable, which further defines and
takes additional space in memory.
Also check the references(added by nos in comments):
Bit
SBit

sBIT is a special type of register used in 8051 microcontroller and are used for accessing individual bits that are declared with bdata while Bit is used to define a single-bit variable.

Related

RISC-V inline assembly using memory not behaving correctly

This system call code is not working at all. The compiler is optimizing things out and generally behaving strangely:
template <typename... Args>
inline void print(Args&&... args)
{
char buffer[1024];
auto res = strf::to(buffer) (std::forward<Args> (args)...);
const size_t size = res.ptr - buffer;
register const char* a0 asm("a0") = buffer;
register size_t a1 asm("a1") = size;
register long syscall_id asm("a7") = ECALL_WRITE;
register long a0_out asm("a0");
asm volatile ("ecall" : "=r"(a0_out)
: "m"(*(const char(*)[size]) a0), "r"(a1), "r"(syscall_id) : "memory");
}
This is a custom system call that takes a buffer and a length as arguments.
If I write this using global assembly it works as expected, but program code has generally been extraordinarily good if I write the wrappers inline.
A function that calls the print function with a constant string produces invalid machine code:
0000000000120f54 <start>:
start():
120f54: fa1ff06f j 120ef4 <public_donothing-0x5c>
-->
120ef4: 747367b7 lui a5,0x74736
120ef8: c0010113 addi sp,sp,-1024
120efc: 55478793 addi a5,a5,1364 # 74736554 <add_work+0x74615310>
120f00: 00f12023 sw a5,0(sp)
120f04: 00a00793 li a5,10
120f08: 00f10223 sb a5,4(sp)
120f0c: 000102a3 sb zero,5(sp)
120f10: 00500593 li a1,5
120f14: 06600893 li a7,102
120f18: 00000073 ecall
120f1c: 40010113 addi sp,sp,1024
120f20: 00008067 ret
It's not loading a0 with the buffer at sp.
What am I doing wrong?
It's not loading a0 with the buffer at sp.
Because you didn't ask for a pointer as an "r" input in a register. The one and only guaranteed/supported behaviour of T foo asm("a0") is to make an "r" constraint (including +r or =r) pick that register.
But you used "m" to let it pick an addressing mode for that buffer, not necessarily 0(a0), so it probably picked an SP-relative mode. If you add asm comments inside the template like "ecall # 0 = %0 1 = %1 2 = %2" you can look at the compiler's asm output and see what it picked. (With clang, use -no-integrated-as so asm comments in the template come through in the -S output.)
Wrapping a system call does need the pointer in a specific register, i.e. using "r" or +"r"
asm volatile ("ecall # 0=%0 1=%1 2=%2 3=%3 4=%4"
: "=r"(a0_out)
: "r"(a0), "r"(a1), "r"(syscall_id), "m"(*(const char(*)[size]) a0)
: // "memory" unneeded; the "m" input tells the compiler which memory is read
);
That "m" input can be used instead of the "memory" clobber, not instead of an "r" pointer input. (For write specifically, because it only reads that one area of pointed-to memory and has no other side-effects on memory user-space can see, only on kernel write write buffers and file-descriptor positions which aren't C objects this program can access directly. For a read call, you'd need the memory to be an output operand.)
With optimization disabled, compilers do typically pick another register as the base for the "m" input (e.g. 0(a5) for GCC), but with optimization enabled GCC picks 0(a0) so it doesn't cost extra instructions. Clang still picks 0(a2), wasting an instruction to set up that pointer, even though the "=r"(a0_out) is not early-clobber. (Godbolt, with a very cut-down version of the function that doesn't call strf::to, whatever that is, just copies a byte into the buffer.)
Interestingly, with optimization enabled for my cut-down stand-alone version of the function without fixing the bug, GCC and clang do happen to put a pointer to buffer into a0, picking 0(a0) as the template expansion for that operand (see the Godbolt link above). This seems to be a missed optimization vs. using 16(sp); I don't see why they'd need the buffer address in a register at all.
But without optimization, GCC picks ecall # 0 = a0 1 = 0(a5) 2 = a1. (In my simplified version of the function, it sets a5 with mv a5,a0, so it did actually have the address in a0 as well. So it's a good thing you had more code in your function to make it not happen to work by accident, so you could find the bug in your code.)

4 lsb bits masked due to 4 reserved bits in register--OHCI USB Host implementation- Unrecoverable error

I am using an AT91SAM9G45 and am implementing the OHCI for full speed USB host implementation.
I have created the Endpoint Descriptors(ED) and Transfer Descriptors(TD), these are created as structure pointers.
The Host Controller Driver(HCD) is supposed to write the address of the head ED in the HcControlHeadED register. This is a 32 bit register with the last 4 bits reserved and are all 0's. When I create an ED structure pointer, I get a 32-bit address when I write this 32-bit address in the HcControlED register the last 4bits are masked and they become zeros.
How do I resolve this?
When the host controller is given command to start processing of the control ED's I get an unrecoverable error(can say this because the unrecoverable error bit is set then), I am guessing this is because the last 4 bits get masked which changes the pointer address.
How do I fix this problem?
typedef struct {
/ FunctionAddress | EndpointNumber | Direction | Speed | sKip | Format
// MaximumPacketSize
volatile unsigned int Control;
// TailP: TDQueueTailPointer
volatile unsigned int TailP;
// HeadP: TDQueueHeadPointer Points to the next TD to be processed for
volatile unsigned int HeadP;
// NextED: If nonzero, then this entry points to the next ED on the list
volatile unsigned int NextEd;
} __attribute__((aligned(16))) OHCIEndpointDescriptor;
OHCIEndpointDescriptor *ed1;
AT91C_BASE_UHP->UHP_HcControlHeadED=((unsigned int)&ed1);
If someone in the future faces this problem, I figured it out, it was with the environment I am using. Alignment is a gcc thing which needs
#pragma data_alignment=16 static OHCIEndpointDescriptor *ed1;

How do I access an integer array within a struct/class from in-line assembly (blackfin dialect) using gcc?

Not very familiar with in-line assembly to begin with, and much less with that of the blackfin processor. I am in the process of migrating a legacy C application over to C++, and ran into a problem this morning regarding the following routine:
//
void clear_buffer ( short * buffer, int len ) {
__asm__ (
"/* clear_buffer */\n\t"
"LSETUP (1f, 1f) LC0=%1;\n"
"1:\n\t"
"W [%0++] = %2;"
:: "a" ( buffer ), "a" ( len ), "d" ( 0 )
: "memory", "LC0", "LT0", "LB0"
);
}
I have a class that contains an array of shorts that is used for audio processing:
class AudProc
{
enum { buffer_size = 512 };
short M_samples[ buffer_size * 2 ];
// remaining part of class omitted for brevity
};
Within the AudProc class I have a method that calls clear_buffer, passing it the samples array:
clear_buffer ( M_samples, sizeof ( M_samples ) / 2 );
This generates a "Bus Error" and aborts the application.
I have tried making the array public, and that produces the same result. I have also tried making it static; that allows the call to go through without error, but no longer allows for multiple instances of my class as each needs its own buffer to work with. Now, my first thought is, it has something to do with where the buffer is in memory, or from where it is being accessed. Does something need to be changed in the in-line assembly to make this work, or in the way it is being called?
Thought that this was similar to what I was trying to accomplish, but it is using a different dialect of asm, and I can't figure out if it is the same problem I am experiencing or not:
GCC extended asm, struct element offset encoding
Anyone know why this is occurring and how to correct it?
Does anyone know where there is helpful documentation regarding the blackfin asm instruction set? I've tried looking on the ADSP site, but to no avail.
I would suspect that you could define your clear_buffer as
inline void clear_buffer (short * buffer, int len) {
memset (buffer, 0, sizeof(short)*len);
}
and probably GCC is able to optimize (when invoked with -O2 or -O3) that cleverly (because GCC knows about memset).
To understand assembly code, I suggest running gcc -S -O -fverbose-asm on some small C file, then to look inside the produced .s file.
I would have take a guess, because I don't know Blackfin assembler:
That LC0 sounds like "loop counter", LSETUP looks like a macro/insn, which, well, setups a loop between two labels and with a certain loop counter.
The "%0" operands is apparently the address to write to and we can safely guess it's incremented in the loop, in other words it's both an input and output operand and should be described as such.
Thus, I suggest describing it as in input-output operand, using "+" constraint modifier, as follows:
void clear_buffer ( short * buffer, int len ) {
__asm__ (
"/* clear_buffer */\n\t"
"LSETUP (1f, 1f) LC0=%1;\n"
"1:\n\t"
"W [%0++] = %2;"
: "+a" ( buffer )
: "a" ( len ), "d" ( 0 )
: "memory", "LC0", "LT0", "LB0"
);
}
This is, of course, just a hypothesis, but you could disassemble the code and check if by any chance GCC allocated the same register for "%0" and "%2".
PS. Actually, only "+a" should be enough, early-clobber is irrelevant.
For anyone else who runs into a similar circumstance, the problem here was not with the in-line assembly, nor with the way it was being called: it was with the classes / structs in the program. The class that I believed to be the offender was not the problem - there was another class that held an instance of it, and due to other members of that outer class, the inner one was not aligned on a word boundary. This was causing the "Bus Error" that I was experiencing. I had not come across this before because the classes were not declared with __attribute__((packed)) in other code, but they are in my implementation.
Giving Type Attributes - Using the GNU Compiler Collection (GCC) a read was what actually sparked the answer for me. Two particular attributes that affect memory alignment (and, thus, in-line assembly such as I am using) are packed and aligned.
As taken from the aforementioned link:
aligned (alignment)
This attribute specifies a minimum alignment (in bytes) for variables of the specified type. For example, the declarations:
struct S { short f[3]; } __attribute__ ((aligned (8)));
typedef int more_aligned_int __attribute__ ((aligned (8)));
force the compiler to ensure (as far as it can) that each variable whose type is struct S or more_aligned_int is allocated and aligned at least on a 8-byte boundary. On a SPARC, having all variables of type struct S aligned to 8-byte boundaries allows the compiler to use the ldd and std (doubleword load and store) instructions when copying one variable of type struct S to another, thus improving run-time efficiency.
Note that the alignment of any given struct or union type is required by the ISO C standard to be at least a perfect multiple of the lowest common multiple of the alignments of all of the members of the struct or union in question. This means that you can effectively adjust the alignment of a struct or union type by attaching an aligned attribute to any one of the members of such a type, but the notation illustrated in the example above is a more obvious, intuitive, and readable way to request the compiler to adjust the alignment of an entire struct or union type.
As in the preceding example, you can explicitly specify the alignment (in bytes) that you wish the compiler to use for a given struct or union type. Alternatively, you can leave out the alignment factor and just ask the compiler to align a type to the maximum useful alignment for the target machine you are compiling for. For example, you could write:
struct S { short f[3]; } __attribute__ ((aligned));
Whenever you leave out the alignment factor in an aligned attribute specification, the compiler automatically sets the alignment for the type to the largest alignment that is ever used for any data type on the target machine you are compiling for. Doing this can often make copy operations more efficient, because the compiler can use whatever instructions copy the biggest chunks of memory when performing copies to or from the variables that have types that you have aligned this way.
In the example above, if the size of each short is 2 bytes, then the size of the entire struct S type is 6 bytes. The smallest power of two that is greater than or equal to that is 8, so the compiler sets the alignment for the entire struct S type to 8 bytes.
Note that although you can ask the compiler to select a time-efficient alignment for a given type and then declare only individual stand-alone objects of that type, the compiler's ability to select a time-efficient alignment is primarily useful only when you plan to create arrays of variables having the relevant (efficiently aligned) type. If you declare or use arrays of variables of an efficiently-aligned type, then it is likely that your program also does pointer arithmetic (or subscripting, which amounts to the same thing) on pointers to the relevant type, and the code that the compiler generates for these pointer arithmetic operations is often more efficient for efficiently-aligned types than for other types.
The aligned attribute can only increase the alignment; but you can decrease it by specifying packed as well. See below.
Note that the effectiveness of aligned attributes may be limited by inherent limitations in your linker. On many systems, the linker is only able to arrange for variables to be aligned up to a certain maximum alignment. (For some linkers, the maximum supported alignment may be very very small.) If your linker is only able to align variables up to a maximum of 8-byte alignment, then specifying aligned(16) in an __attribute__ still only provides you with 8-byte alignment. See your linker documentation for further information.
.
packed
This attribute, attached to struct or union type definition, specifies that each member (other than zero-width bit-fields) of the structure or union is placed to minimize the memory required. When attached to an enum definition, it indicates that the smallest integral type should be used.
Specifying this attribute for struct and union types is equivalent to specifying the packed attribute on each of the structure or union members. Specifying the -fshort-enums flag on the line is equivalent to specifying the packed attribute on all enum definitions.
In the following example struct my_packed_struct's members are packed closely together, but the internal layout of its s member is not packed—to do that, struct my_unpacked_struct needs to be packed too.
struct my_unpacked_struct
{
char c;
int i;
};
struct __attribute__ ((__packed__)) my_packed_struct
{
char c;
int i;
struct my_unpacked_struct s;
};
You may only specify this attribute on the definition of an enum, struct or union, not on a typedef that does not also define the enumerated type, structure or union.
The problem which I was experiencing was specifically due to the use of packed. I attempted to simply add the aligned attribute to the structs and classes, but the error persisted. Only removing the packed attribute resolved the problem. For now, I am leaving the aligned attribute on them and testing to see if I find any improvements in the efficiency of the code as mentioned above, simply due to their being aligned on word boundaries. The application makes use of arrays of these structures, so perhaps there will be better performance, but only profiling the code will say for certain.

Pic programming: what is the variable type of a port bit in MikroC?

I'm programming in C in the MikroC IDE for a pic16f887 and I want more versatility with pins such as being able to put them into an array, passing them as arguments to functions...etc.
So I was wondering what the "type" of a pin such as PORTB.F1 is?
How would I store bits into an array?
Would this work?
const char pinArr[3] = {PORTB.F1, PORTC.F1, PORTD.F1};
Thanks
I'm assuming you are trying to do this with a set of inputs pins. A digital input pin should be read as an int, specifically it will be 0 or 1. Your char array probably wouldn't work as a pin with an input of 0 would be read as a NULL character, which would signal the end of the string to anything expecting a normal c string. However there should be nothing stopping you using an int array.
You can define your pins and use the predefined names instead. It's a lot more easier.
For example:
#define front_sensor PORTE.F0
#define left_sensor PORTE.F1
#define right_sensor PORTE.F2
or
unsigned char sensor = PORTE.F0;

Ints to Bytes: Endianess a Concern?

Do I have to worry about endianness in this case (integers MUST be 0-127):
int a = 120;
int b = 100;
int c = 50;
char theBytes[] = {a, b, c};
I think that, since each integer sits in its own byte, I don't have to worry about Endianess in passing the byte array between systems. This has also worked out empirically. Am I missing something?
Endianness only affects the ordering of bytes within an individual value. Individual bytes are not subject to endian issues, and arrays are always sequential, so byte arrays are the same on big- and little-endian architectures.
Note that this doesn't necessarily mean that only using chars will make datatypes 100% byte-portable. Structs may still include architecture-dependent padding, for example, and one system may have unsigned chars while another uses signed (though I see you sidestep this by only allowing 0-127).
No, you don't need to worry, compiler produces code which makes correct casting and assignment.