Creating a byte (8 bits) from 4 2 bits - c

I am trying to figure out a way to get as much out of the limited memory in my microcontroller (32kb) and am seeking suggestions or pointers to an algorithm that performs what I am attempting to do.
Some background: I am sending Manchester Encoded bits out a SPI (Serial Peripheral Interface) directly from DMA. As the smallest possible unit I can store data into DMA is a byte (8 bits), I am having to represent my 1's as 0b11110000 and my 0's as 0b00001111. This basically means that for every bit of information, I need to use a byte (8 bits) of memory. Which is very inefficient.
If I could reduce this, so that my 1's are represented as 0b10 and my 0's as 0b01, I'd only have to use a 1/4 of a byte (2 bits) for every 1 bit of memory, which is fine for my solution.
Now, if I could save to DMA in bits, this would not be a problem, but of course I need to work with bytes. So I know the solution to my problem involves collecting the 8 bits (or in my case, 4 2bits) and then storing to DMA as a byte.
Questions:
Is there a standard way to solve this problem?
How can I some how create a 8 bit number from a collection of 4 2 bit numbers? But I do not want the addition of these numbers, but the actual way it looks when collected together.
For example: I have the following 4 2 bit numbers (keeping in mind that 0b10 represents 1 and 0b01 represents 0) (Also, the type these are stored in is open to the solution, as obviously there is no such thing as a 2 bit type)
Number1: 0b01 Number 2: 0b10 Number 3: 0b10 Number4: 0b01
And I want to create the following 8 bit number from these:
8 Bit Number: 0b01 10 10 01 or without the spaces 0b01101001 (0x69)
I am programming in c

It seems that you can pack four numbers a, b, c, d, all of which of value zero or one, like so:
64 * (a + 1) + 16 * (b + 1) + 4 * (c + 1) + (d + 1)
This is using the fact that x + 1 encodes your two-bit integer: 1 becomes 0b10, and 0 becomes 0b01.

It's Manchester encoding so 0b11110000 and 0b00001111 should be the only candidates. If so, then reduce the memory by a factor of 8.
uint8_t PackedByte = 0;
for (i=0; i<8; i++) {
PackedByte <<= 1;
if (buf[i] == 0xF0) // 0b11110000
PackedByte++;
}
Other other hand, if it's Manchester encoding and one may not have perfect encoding, then there are 3 results: 0, 1, indeterminate.
uint8_t PackedByte = 0;
for (i=0; i<8; i++) {
int upper = BitCount(buf[i] >> 4);
int lower = BitCount(buf[i] & 0xF);
if (upper > lower)
PackedByte++;
else if (upper == lower)
Hande_Indeterminate();
}
Various simplifications absent in the above, but shown for logic flow.

To number get abcd from (a,b,c,d) you need to shift the number to their places and OR :-
(a<<6)|(b<<4)|(c<<2)|d

Related

Read Specific values from given address?

Given the 16 bit address(memory address, not value) 0x1144, 16-bit is divided into Type bit 15- bit 16 , Module bit 9 to bit 14, group bit 1 to bit 8
Type = Bit 15 - Bit 16
Module = Bit 9 - Bit 14
Group = Bit 1 - Bit 8
Read and Print the Values in Following variables.
uint16_t Type;
uint16_t Module;
uint16_t Group;
How to read & print values using C.
I tried with
uint16_t *ptr = 0x1144;
Type = *ptr >> 14;
Module = *ptr << 2;
Module = Module >> 10;
Group = *ptr << 8;
Group = Group >> 8;
Is this the correct ?
You can use Bit fields in C which is quite commonly used while addressing individual bit positions in HW registers. Just model your bit positions in a struct by defining below (on my machine with little endian)
typedef struct {
uint16_t group:8;
uint16_t module:6;
uint16_t type:2;
}nwGroup ;
All you need to do is cast the address containing your 16 bit value to this struct type and you can access the fields individually after that.
uint16_t *val = (uint16_t *)0x1144;
nwGroup *ptr = (nwGroup*)(val);
printf("NW group: %d\n", ptr->group);
(Note: We usually number things starting from 0 in computer science, so I've interpreted your requirements from a zero-based mindset.)
Use a combination of masking and shifting. For example, if you want to be able to recover the NetworkModule value, create a mask that has 1-bits in the positions you want, and 0-bits everywhere else:
#define NetworkModuleMask 0x3E00 // that is, 0011 1110 0000 0000
Now you can use that to mask out the unwanted bits using bitwise AND:
int address = 0x1144;
int networkModule = address & NetworkModuleMask
Another way to do it, which is essentially equivalent, is to use division and modulo operators with powers of 2. For example, your NetworkGroup is the
Then, to interpret the value as a number, you'll want to shift it right by 9 bits:
#define NetworkModulePosition 9
networkModule = networkModule >> NetworkModulePosition
You can use a similar process to construct an address using component values: shift each part into position and then bitwise OR it into the address.
You can also approach the problem arithmetically, using division and modulo operators with powers of 2. Dividing an integer by a power of 2 is the same as shifting it to the right by some number of bits, and modulo by a power of 2 is the same as shifting some number of bits to the right and then clearing some number of bits on the left, so you end up doing pretty much what we did above. For example, your NetworkGroup value is the low 8 bits of the address, so you can recover it by taking the address mod 2^^8, or 256. The NetworkType is the highest 2 bits, and you can recover that by dividing the address by 2^^14, or 16384.

c: bit reversal logic

I was looking at the below bit reversal code and just wondering how does one come up with these kind of things. (source : http://www.cl.cam.ac.uk/~am21/hakmemc.html)
/* reverse 8 bits (Schroeppel) */
unsigned reverse_8bits(unsigned41 a) {
return ((a * 0x000202020202) /* 5 copies in 40 bits */
& 0x010884422010) /* where bits coincide with reverse repeated base 2^10 */
/* PDP-10: 041(6 bits):020420420020(35 bits) */
% 1023; /* casting out 2^10 - 1's */
}
Can someone explain what does comment "where bits coincide with reverse repeated base 2^10" mean?
Also how does "%1023" pull out the relevent bits? Is there any general idea in this?
It is a very broad question you are asking.
Here is an explanation of what % 1023 might be about: you know how computing n % 9 is like summing the digits of the base-10 representation of n? For instance, 52 % 9 = 7 = 5 + 2.
The code in your question is doing the same thing with 1023 = 1024 - 1 instead of 9 = 10 - 1. It is using the operation % 1023 to gather multiple results that have been computed “independently” as 10-bit slices of a large number.
And this is the beginning of a clue as to how the constants 0x000202020202 and 0x010884422010 are chosen: they make wide integer operations operate as independent simpler operations on 10-bit slices of a large number.
Expanding on Pascal Cuoq idea, here is an explaination.
The general idea is, in any base, if any number is divided by (base-1), the remainder will be sum of all the digits in the number.
For example, 34 when divided by 9 leaves 7 as remainder. This is because 34 can be written as 3 * 10 + 4
i.e. 34 = 3 * 10 + 4
= 3 * (9 +1) + 4
= 3 * 9 + (3 +4)
Now, 9 divides 3 * 9, leaving remainder (3 + 4). This process can be extended to any base 'b', since (b^n - 1) is always divided by (b-1).
Now, coming to the problem, if a number is represented in base 1024, and if the number is divided by 1023, the remainder will be sum of its digits.
To convert a binary number to base 1024, we can group bits of 10 from the right side into single number
For example, to convert binary number 0x010884422010(0b10000100010000100010000100010000000010000) to base 1024, we can group it into 10 bits number as follows
(1) (0000100010) (0001000100) (0010001000) (0000010000) =
(0b0000000001)*1024^4 + (0b0000100010)*1024^3 + (0b0001000100)*1024^2 + (0b0010001000)*1024^1 + (0b0000010000)*1024^0
So, when this number is divided by 1023, the remainder will sum of
0b0000000001
+ 0b0000100010
+ 0b0001000100
+ 0b0010001000
+ 0b0000010000
--------------------
0b0011111111
If you observe the above digits closely, the '1' bits in each above digit occupy complementay positions. So, when added together, it should pull all the 8 bits in the original number.
So, in the above code, "a * 0x000202020202", creates 5 copies of the byte "a". When the result is ANDed with 0x010884422010, we selectively choose 8 bits in the 5 copies of "a". When "% 1023" is applied, we pull all the 8 bits.
So, how does it actually reverse bits? That is bit clever. The idea is, the "1" bit in the digit 0b0000000001 is actually aligned with MSB of the original byte. So, when you "AND" and you are actually ANDing MSB of the original byte with LSB of the magic number digit. Similary the digit 0b0000100010 is aligned with second and sixth bits from MSB and so on.
So, when you add all the digits of the magic number, the resulting number will be reverse of the original byte.

converting little endian hex to big endian decimal in C

I am trying to understand and implement a simple file system based on FAT12. I am currently looking at the following snippet of code and its driving me crazy:
int getTotalSize(char * mmap)
{
int *tmp1 = malloc(sizeof(int));
int *tmp2 = malloc(sizeof(int));
int retVal;
* tmp1 = mmap[19];
* tmp2 = mmap[20];
printf("%d and %d read\n",*tmp1,*tmp2);
retVal = *tmp1+((*tmp2)<<8);
free(tmp1);
free(tmp2);
return retVal;
};
From what I've read so far, the FAT12 format stores the integers in little endian format.
and the code above is getting the size of the file system which is stored in the 19th and 20th byte of boot sector.
however I don't understand why retVal = *tmp1+((*tmp2)<<8); works. is the bitwise <<8 converting the second byte to decimal? or to big endian format?
why is it only doing it to the second byte and not the first one?
the bytes in question are [in little endian format] :
40 0B
and i tried converting them manually by switching the order first to
0B 40
and then converting from hex to decimal, and I get the right output, I just don't understand how adding the first byte to the bitwise shift of second byte does the same thing?
Thanks
The use of malloc() here is seriously facepalm-inducing. Utterly unnecessary, and a serious "code smell" (makes me doubt the overall quality of the code). Also, mmap clearly should be unsigned char (or, even better, uint8_t).
That said, the code you're asking about is pretty straight-forward.
Given two byte-sized values a and b, there are two ways of combining them into a 16-bit value (which is what the code is doing): you can either consider a to be the least-significant byte, or b.
Using boxes, the 16-bit value can look either like this:
+---+---+
| a | b |
+---+---+
or like this, if you instead consider b to be the most significant byte:
+---+---+
| b | a |
+---+---+
The way to combine the lsb and the msb into 16-bit value is simply:
result = (msb * 256) + lsb;
UPDATE: The 256 comes from the fact that that's the "worth" of each successively more significant byte in a multibyte number. Compare it to the role of 10 in a decimal number (to combine two single-digit decimal numbers c and d you would use result = 10 * c + d).
Consider msb = 0x01 and lsb = 0x00, then the above would be:
result = 0x1 * 256 + 0 = 256 = 0x0100
You can see that the msb byte ended up in the upper part of the 16-bit value, just as expected.
Your code is using << 8 to do bitwise shifting to the left, which is the same as multiplying by 28, i.e. 256.
Note that result above is a value, i.e. not a byte buffer in memory, so its endianness doesn't matter.
I see no problem combining individual digits or bytes into larger integers.
Let's do decimal with 2 digits: 1 (least significant) and 2 (most significant):
1 + 2 * 10 = 21 (10 is the system base)
Let's now do base-256 with 2 digits: 0x40 (least significant) and 0x0B (most significant):
0x40 + 0x0B * 0x100 = 0x0B40 (0x100=256 is the system base)
The problem, however, is likely lying somewhere else, in how 12-bit integers are stored in FAT12.
A 12-bit integer occupies 1.5 8-bit bytes. And in 3 bytes you have 2 12-bit integers.
Suppose, you have 0x12, 0x34, 0x56 as those 3 bytes.
In order to extract the first integer you only need take the first byte (0x12) and the 4 least significant bits of the second (0x04) and combine them like this:
0x12 + ((0x34 & 0x0F) << 8) == 0x412
In order to extract the second integer you need to take the 4 most significant bits of the second byte (0x03) and the third byte (0x56) and combine them like this:
(0x56 << 4) + (0x34 >> 4) == 0x563
If you read the official Microsoft's document on FAT (look up fatgen103 online), you'll find all the FAT relevant formulas/pseudo code.
The << operator is the left shift operator. It takes the value to the left of the operator, and shift it by the number used on the right side of the operator.
So in your case, it shifts the value of *tmp2 eight bits to the left, and combines it with the value of *tmp1 to generate a 16 bit value from two eight bit values.
For example, lets say you have the integer 1. This is, in 16-bit binary, 0000000000000001. If you shift it left by eight bits, you end up with the binary value 0000000100000000, i.e. 256 in decimal.
The presentation (i.e. binary, decimal or hexadecimal) has nothing to do with it. All integers are stored the same way on the computer.

Combining two integers with bit-shifting

I am writing a program, I have to store the distances between pairs of numbers in a hash table.
I will be given a Range R. Let's say the range is 5.
Now I have to find distances between the following pairs:
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
that is, the total number of pairs is (R^2/2 -R). I want to store it in a hash table. All these are unsigned integers. So there are 32 bits. My idea was that, I take an unsigned long (64 bits).
Let's say I need to hash the distance between 1 and 5. Now
long k = 1;
k = k<<31;
k+=5;
Since I have 64 bits, I am storing the first number in the first 31 bits and the second number in the second 31 bits. This guarantees unique keys which can then be used for hashing.
But when I do this:
long k = 2;
k << 31;
k+= 2;
The value of k becomes zero.
I am not able to wrap my head around this shifting concept.
Essentially what I am trying to achieve is that,
An unsigned long has | 32bits | 32 bits |
Store |1st integer|2nd integer|
How can I achieve this to get unique keys for each pair?
I am running the code on a 64 bit AMD Opteron processor. sizeof(ulong) returns 8. So it is 64 bits. Do I need a long long in such a case?
Also I need to know if this will create unique keys? From my understanding , it does seem to create unique keys. But I would like a confirmation.
Assuming you're using C or something that follows vaguely similar rules, your problem is primarily with types.
long k = 2; // This defines `k` a a long
k << 31; // This (sort of) shifts k left, but still as a 32-bit long.
What you almost certainly want/need to do is convert k to a long long before you shift it left, so you're shifting in a 64-bit word.
unsigned long first_number = 2;
unsigned long long both_numbers = (unsigned long long)first_number << 32;
unsigned long second_number = 5;
both_numbers |= second_number;
In this case, if (for example) you print out both_numbers, in hexadecimal, you should get 0x0000000200000005.
The concept makes sense. As Oli has added, you want to shift by 32, not 31 - shifting by 31 will put it in the 31st bit, so if you shifted back to the right to try and get the first number you would end up with a bit missing, and the second number would be potentially huge because you could have put a 1 in the uppermost bit.
But if you want to do bit manipulation, I would do instead:
k = 1 << 32;
k = k|5;
It really should produce the same result though. Are you sure that long is 64 bits on your machine? This is not always the case (although it usually is, I think). If long is actually 32 bits, 2<<31 will result in 0.
How large is R? You can get away with a 32 bit sized variable if R doesn't go past 65535...

How to set the 513th bit of a char[1024] in C?

I was recently asked in an interview how to set the 513th bit of a char[1024] in C, but I'm unsure how to approach the problem. I saw How do you set, clear, and toggle a single bit?, but how do I choose the bit from such a large array?
int bitToSet = 513;
inArray[bitToSet / 8] |= (1 << (bitToSet % 8));
...making certain assumptions about character size and desired endianness.
EDIT: Okay, fine. You can replace 8 with CHAR_BIT if you want.
#include <limits.h>
int charContaining513thBit = 513 / CHAR_BIT;
int offsetOf513thBitInChar = 513 - charContaining513thBit*CHAR_BIT;
int bit513 = array[charContaining513thBit] >> offsetOf513thBitInChar & 1;
You have to know the width of characters (in bits) on your machine. For pretty much everyone, that's 8. You can use the constant CHAR_BIT from limits.h in a C program. You can then do some fairly simple math to find the offset of the bit (depending on how you count them).
Numbering bits from the left, with the 2⁷ bit in a[0] being bit 0, the 2⁰ bit being bit 7, and the 2⁷ bit in a[1] being bit 8, this gives:
offset = 513 / CHAR_BIT; /* using integer (truncating) math, of course */
bit = 513 % CHAR_BIT;
a[offset] |= (0x80>>bit)
There are many sane ways to number bits, here are two:
a[0] a[1]
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 This is the above
7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 This is |= (1<<bit)
You could also number from the other end of the array (treating it as one very large big-endian number).
Small optimization:
The / and % operators are rather slow, even on a lot of modern cpus, with modulus being slightly slower. I would replace them with the equivalent operations using bit shifting (and subtraction), which only works nicely when the second operand is a power of two, obviously.
x / 8 becomes x >> 3
x % 8 becomes x-((x>>3)<<3)
for this second operation, just reuse the result from the initial division.
Depending on the desired order (left to right versus right to left), it might change. But the general idea assuming 8 bits per byte would be to choose the byte as. This is expanded into lots of lines of code to hopefully show more clearly the intended steps (or perhaps it just obfuscates the intention):
int bitNum = 513;
int bytePos = bitNum / 8;
Then the bit position would be computed as:
int bitInByte = bitNum % 8;
Then set the bit (assuming the goal is to set it to 1 as opposed to clear or toggle it):
charArray[bytePos] |= ( 1 << bitInByte );
When you say 513th are you using index 0 or 1 for the 1st bit? If it's the former your post refers to the bit at index 512. I think the question is valid since everywhere else in C the first index is always 0.
BTW
static char chr[1024];
...
chr[512>>3]=1<<(512&0x7);

Resources