Creating a Processor - c

It is my last semester but one in university, the sublect is called Architecture and Programming of Microprocessors, the professor wrote this code and i just cannot understand what he is doing. Especially the part with the mask. Here is the code. Can anyone help me to understand it please?
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
uint32_t Instruction_Memory[0x2000];
uint32_t PC = 0;
uint32_t Registers[32];
uint32_t Data_Memory[0x3000];
uint32_t get_instruction(uint32_t input){
uint32_t temp = input/4;
return Instruction_Memory[temp];
}
void print_registers() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 8; j++) {
printf("x%d: %x \t", i*8+j, Registers[i*8+j]);
}
printf("\n");
};
};
uint32_t get_bits(uint32_t input, int start, int numberOfBits){
uint32_t t4 = input >> start;
uint32_t mask = (1 << numberOfBits) - 1;
t4 = mask & t4;
// printf("input : %x, start : %d, nob : %d, mask : %x\n", input, start, numberOfBits, mask);
return t4;
}
int main(){
PC = 0x1000;
// x5
Registers[5] = 6;
// x9
Registers[9] = 0x2004;
Data_Memory[0x2000] = 10;
Instruction_Memory[0x1000 / 4] = 0xFFC4A303;
Instruction_Memory[0x1004 / 4] = 0x0064A423;
Instruction_Memory[0x1008 / 4] = 0x0062E233;
uint32_t instruction = get_instruction(0x1000);
printf("Instruction = 0x%x\n\r", instruction);
print_registers();
uint32_t A1 = get_bits(instruction, 15, 5);
printf("A1 = %x\n\r", A1);
return 0;
}
I understood that he printed out the registers and also provided an instruction to the system.

The function get_bits (aka "the part with the mask") takes a 32bit integer and two counts. The first count is how many low bits are to be ignored, the second how many are to be returned. (As #PeterCordes pointed out in a comment, the function as-is is not fit for general use due to some limitations, but I guess this code is a one-shot to illustrate certain points.)
get_bits is called with the values 15 and 5, respectively. This means ignore 15, return 5.
Mbbbbbbb bbbbbbbb bbbbbbbb bbbbbbbL
rrrr riiiiiii iiiiiiii
"M" for most significant bit, "L" for least significant bit, "i" for ignored (shifted right), "r" for returned.
As to how that is done, look at your C reference on bitshift and bitwise operators. As to what it means semantically, that should be clear from your accompanying course material explaining what those bits -- labeled A1 -- signify.

Related

How to sum values in a sequence of bytes in C

I am trying to figure out how to add sequential bytes in a data block starting at a given offset(sequenceOffset) to sequenceLength, by typcasting them to signed 16 bit integers(int16_t). The numbers can be negative and positive. I feel like i am not incrementing the offset properly but cannot figure out how it is meant to be done.
For example:
Summing sequence of 8 bytes at offset 53:
57 AB 2A 2C 4E A4 7A 64
-21673 11306 -23474 25722
You said the sum is: 22848
Should be: -8119
int16_t sumSequence16(const uint8_t* const blockAddress, uint32_t blockLength, uint32_t sequenceOffset,
uint8_t sequenceLength) {
int count = 0;
for (int i = 0; i < blockLength; i++) {
if (*(blockAddress + i) == sequenceOffset) {
count += (int16_t*)(&sequenceOffset);
sequenceOffset++;
}
}
return count;
}
There are some serious problems with your code.
Start by noticing that your code doesn't use sequenceLength at all - that's strange.
Then there is no need to loop over the whole block - you only need to look at the bytes inside the relevant sequence.
This line is very strange:
if (*(blockAddress + i) == sequenceOffset)
^^^^^^^^^^^^^^^^^^^
Reads the data at index i
It compare a data value inside the data block with the sequenceOffset - that doesn't seem correct.
And this part:
(int16_t*)(&sequenceOffset);
is actually a violation of the strict aliasing rule.
Finally, you never mention which endianess the data is stored with. From your example it seems to be little endian so I'll use little endian in the code below:
int16_t sumSequence16(const uint8_t* const blockAddress,
const uint32_t sequenceOffset,
const uint8_t sequenceLength)
{
uint8_t* p = blockAddress + sequenceOffset; // Point to first byte in sequence
int sum = 0;
for (uint8_t i = 0; i < sequenceLength; i += 2)
{
int16_t t = 0;
t = p[i+1]; // Read MSB
t = t << 8; // Shift MSB 8 bits to the left
t = t | p[i]; // Add LSB
sum = sum + t; // Update the running sum
}
return sum;
}

2-bit mapping using bitwise operations in C

This is my first question, so I hope to do this right.
I have a problem where I have to map a key which can be in the range (0, 1, 2) to select a value from the same range (0, 1, 2). I have to repeat this millions of times and I was trying to implement this by using bitwise operations in C, without success.
So let's say I have 16 keys in the range (0, 1, 2) which I want to map to 16 values in the same range by using the following rules:
0 -> 2
1 -> 1
2 -> 1
I can represent the array of 16 keys as 16 2-bit pairs in a 32bit unsigned int. For instance:
0, 1, 2, 1, 2, 0, ... //Original array of keys
00 01 10 01 10 00 ... //2-bit pairs representation of keys in a 32bit int
and I am interested in transforming the unsigned int, following the rules above (i.e. the 2-bit pairs have to be transformed following the rules: 00->10, 01->01, and 10->01), so that I end up with a 32bit unsigned int like:
10 01 01 01 01 10 ... //2-bit pairs transformed using the given rule.
Would it be a relatively fast bitwise procedure which will allow me to apply efficiently this transformation (given that the transformation rules can change)?
I hope I formulated my question clearly. Thanks for any help.
EDIT: I corrected some mistakes, and clarified some points following comments.
EDIT2: Following some suggestions, I add what I hope is a code example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
unsigned int keys[16];
unsigned int bitKeys = 0;
unsigned int mapping[3];
unsigned int result[16];
unsigned int bitResults = 0;
//Initialize random keys and mapping dict
for(i = 0; i<16; i++)
keys[i] = rand() % 3;
bitKeys |= keys[i] << (2*i);
for(i = 0; i<3; i++)
mapping[i] = rand() % 3;
//Get results without using bitwise opperations.
for(i = 0; i<16; i++)
result[i] = mapping[ keys[i] ];
bitResults |= result[i] << (2*i);
//Would it be possible to get bitResults directly from bitKeys efficiently by using bitwise operations?
return 0;
}
This is essentially a problem of simplifying truth tables to minimal Boolean expressions; here we need two expressions, one for each output value bit.
BA QP
00 10
01 01
10 01
11 XX
B: high key bit, A: low key bit, Q: high value bit, P: low value bit
By using any of the many tools available (including our brain) for minimizing combinational logic circuits, we get the expressions
Q = ¬A·¬B
P = A + B
Now that we have the expressions, we can apply them to all keys in a 32-bit variable:
uint32_t keys = 2<<30|0<<10|1<<8|2<<6|1<<4|2<<2|0; // for example
uint32_t vals = ~keys & ~keys<<1 & 0xAAAAAAAA // value_high is !key_high & !key_low
| (keys>>1 | keys) & 0x55555555; // value_low is key_high | key_low
I would need a solution for any arbitrary mapping.
Here's an example program for arbitrary mappings. For each of the two value bits, there are 23 possible expressions (the same set for both bits); these expressions are:
0 ¬A·¬B A ¬B B ¬A A+B 1
By concatenating the high and low mapping bits, respectively, for keys 0, 1 and 2, we get the index of the expression corresponding to the mapping function. In the following program, the values of all the expressions, even the ones unused by the mapping, are stored in the term array. While this may seem wasteful, it allows computation without branches, which may be a win in the end.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main()
{
int i;
unsigned mapping[3];
// generate example mapping
for (i = 0; i < 3; ++i) mapping[i] = rand() % 3, printf(" %d->%d", i, mapping[i]);
puts("");
// determine the mapping expression index 0..7 for high and low value bit
short h = mapping[0]/2 | mapping[1]/2<<1 | mapping[2]/2<<2;
short l = mapping[0]%2 | mapping[1]%2<<1 | mapping[2]%2<<2;
uint32_t keys = 0x1245689A; // for example
uint32_t b = keys, a = keys<<1;
uint32_t term[8] = { 0, ~a&~b, a, ~b, b, ~a, a|b, -1 }; // all possible terms
uint32_t vals = term[h] & 0xAAAAAAAA // value_high
| term[l]>>1 & 0x55555555; // value_low
printf("%8x\n%8x\n", keys, vals);
}
After thinking about it, and using some of the ideas from other answers, I think I found a general solution. It is based in first estimating the value assuming there are only the keys 10, and 01 (i.e. one bit of the pair determines the other) and then correct by the key 00. An example code of the solution:
#include <stdio.h>
#include <stdlib.h>
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = (b[i] >> j) & 1;
printf("%u", byte);
if(j%2 == 0) printf("|");
}
}
puts("");
}
int test2BitMapping(unsigned int * mapping)
{
int i;
unsigned int keys[16];
unsigned int bitKeys = 0;
unsigned int b = 0;
unsigned int c = 0;
unsigned int d = 0;
unsigned int expand[4] = {0x00000000u, 0x55555555u, 0xAAAAAAAAu, 0xFFFFFFFFu};
unsigned int v12 = 0;
unsigned int v0mask = 0;
unsigned int result[16];
unsigned int bitResults = 0;
unsigned int bitResultsTest = 0;
//Create mapping masks
b = ((1 & mapping[1]) | (2 & mapping[2]));
c = (2 & mapping[1]) | (1 & mapping[2]);
d = mapping[0];
b = expand[b];
c = expand[c];
d = expand[d];
//Initialize random keys
for(i = 0; i<16; i++) {
if(0) { //Test random keys
keys[i] = rand() % 3;
}
else { //Check all keys are generated
keys[i] = i % 3;
}
bitKeys |= keys[i] << (2*i);
}
//Get results without using bitwise opperations.
for(i = 0; i<16; i++) {
result[i] = mapping[ keys[i] ];
bitResultsTest |= result[i] << (2*i);
}
//Get results by using bitwise opperations.
v12 = ( bitKeys & b ) | ( (~bitKeys) & c );
v0mask = bitKeys | (((bitKeys & 0xAAAAAAAAu) >> 1) | ((bitKeys & 0x55555555u) << 1));
bitResults = ( d & (~v0mask) ) | ( v12 & v0mask );
//Check results
if(0) {
for(i = 0; i<3; i++) {
printf("%d -> %d, ", i, mapping[i]);
}
printf("\n");
printBits(sizeof(unsigned int), &bitKeys);
printBits(sizeof(unsigned int), &bitResults);
printBits(sizeof(unsigned int), &bitResultsTest);
printf("-------\n");
}
if(bitResults != bitResultsTest) {
printf("*********\nDifferent\n*********\n");
}
else {
printf("OK\n");
}
}
int main(void)
{
int i, j, k;
unsigned int mapping[3];
//Test using random mapping
for(k = 0; k < 1000; k++) {
for(i = 0; i<3; i++) {
mapping[i] = rand() % 3;
}
test2BitMapping(mapping);
}
//Test all possible mappings
for(i = 0; i<3; i++) {
for(j = 0; j<3; j++) {
for(k = 0; k<3; k++) {
mapping[0] = i;
mapping[1] = j;
mapping[2] = k;
test2BitMapping(mapping);
}
}
}
return 0;
}
and I am interested in transforming the unsigned int, following the rules above (i.e. the 2-bit pairs have to be transformed following the rules: 00->10, 01->01, and 10->01), so that I end up with a 32bit unsigned int
Certainly this can be done, but the required sequence of operations will be different for each of the 27 distinct mappings from { 0, 1, 2 } to { 0, 1, 2 }. Some can be very simple, such as for the three constant mappings, but others require more complex expressions.
Without having performed a thorough analysis, I'm inclined to guess that the mappings that are neither constant nor permutations, such as the one presented in the example, probably have the greatest minimum complexity. These all share the characteristic that two keys map to the same value, whereas the other key maps to a different one. One way -- not necessarily the best -- to approach finding an expression for such a mapping is to focus first on achieving the general result that the two keys map to one value and the other to a different one, and then move on to transforming the resulting values to the desired ones, if necessary.
For the example presented, for instance,
0 -> 2
1 -> 1
2 -> 1
, one could (on a per-key basis) use ((key & 2) >> 1) | ((key & 1) << 1) to achieve these preliminary results:
0 -> 0
1 -> 3
2 -> 3
, which can be converted to the desired final result by flipping the higher-order bit via an exclusive-or operation.
Note well the bit masking. There are other ways that could be approached for mapping a single key, but for the case of multiple keys stored in contiguous bits of the same integer, you need to be careful to avoid contaminating the computed mappings with data from different keys.
In 16-entry bit-vector form, that would be
uint32_t keys = /*...*/;
uint32_t values = (((keys & 0xAAAAAAAAu) >> 1) | ((keys & 0x55555555u) << 1))
^ 0xAAAAAAAAu;
. That happens to have a couple fewer operations than the expression in your other answer so far, but I am not certain that it is the smallest possible number of operations. In fact, if you are prepared to accept arithmetic operations in addition to bitwise ones, then you can definitely do it with fewer operations:
uint32_t keys = /*...*/;
uint32_t values = 0xAAAAAAAAu
- (((keys & 0xAAAAAAAAu) >> 1) | (keys & 0x55555555u));
Of course, in general, various operations do not all have the same cost as each other, but integer addition and subtraction and bitwise AND, OR, and XOR all have the the same cost as each other on most architectures (see, for example, https://www.agner.org/optimize/instruction_tables.pdf).

Binary representation of the 32 bits integer

I am pretty new in c programming and I am trying to figure out more about bits, binary e.c.t
For example, I have three int variables m1 =255 or 11111111 in binary; m2 =255 or 11111111 in binary, m3 = 255 or 11111111 in binary and m4 =0 or 00000000. I am trying to put all theme together into single int variable temp. Something like this (11111111 11111111 11111111 00000000)
Here is the piece of code that I have:
int x1;
unsigned char x2;
unsigned char x3;
unsigned char x4;
int temp;
x1 = x1|m1;
printf("x1:%d\n", x1);
x2 = x2|m2;
printf("x2:%d\n", x2);
temp = x1<<8;
printf("temp:%d\n", temp);
temp = temp|x2;
printf("temp:%d\n", temp);
x3 = x3|m3;
printf("x3:%d\n", x3);
temp = temp<<8;
printf("temp:%d\n", temp);
temp = temp|x3;
printf("temp:%d\n", temp);
x4 = x4|m4;
printf("x4:%d\n", x4);
temp = temp<<8;
printf("temp:%d\n", x1);
temp = temp|x4;
printf("%d\n", temp);
I am using left shift and OR operators here. But I got a little bit wierd output. (I printed out every to step to find out what is wrong).
I got next output:
x1:255
x2:255
temp:65280
temp:65535
x3:255
temp:16776960
temp:16777215
x4:0
temp:-256
temp:-256
Everything goes fine until temp becomes -256 and I do not know why.
I appreciate any help! Thank you!
You're using %d format and it treats variables as signed integers, you need to use %u and change the variable types to unsigned.
unsigned char x1;
unsigned int temp;
You really have a couple of choices in C. First, what it appears you are attempting to do is the following. (note: you should include stdint.h and use uint32_t guaranteed width values instead of int) Your problems surround invoking Undefined Behavior by OR'ing uninitialized values, and failing to properly shift the values for x1, ..., x4.
To do what it looks like you are attempting to do, you could:
#include <stdio.h>
int main (void) {
unsigned int x1 = 0, x2 = 0, x3 = 0, x4 = 0;
unsigned char m1, m2, m3, m4 = 0;
m1 = m2 = m3 = 255;
x1 |= m1;
x2 |= ((unsigned)m2 << 8);
x3 |= ((unsigned)m3 << 16);
x4 = ((x1 | x2 | x3) << 8) | (unsigned)m4;
printf("x1: %u\n", x1);
printf("x2: %u\n", x2);
printf("x3: %u\n", x3);
printf("x4: %u\n", x4);
return 0;
}
Example Use/Output
$ ./bin/shiftx
x1: 255
x2: 65280
x3: 16711680
x4: 4294967040
You can also simplify your logic by simply using a two variables and the value 255. Essentially, you are setting your temp variable to 255 and shifting left by 8, 3-times. Your final value is the OR'ing of the first 3 temp values with a final shift by 8 to get your combined value with the least significant byte zero, e.g.
#include <stdio.h>
#include <stdint.h>
int main (void) {
uint32_t tmp = 0, val = 0;
uint8_t m = 255;
val = m;
printf ("tmp1 : %u\n", val);
tmp = val << 8;
printf ("tmp2 : %u\n", tmp);
val |= tmp;
tmp <<= 8;
printf ("tmp3 : %u\n", tmp);
val |= tmp;
tmp <<= 8;
printf ("tmp4 : %u\n", tmp);
val <<= 8;
printf ("val : %u\n", val);
return 0;
}
Example Use/Output
$ ./bin/shift1var
tmp1 : 255
tmp2 : 65280
tmp3 : 16711680
tmp4 : 4278190080
val : 4294967040
An improved version could make use of a union between a bitfield struct and a uint32_t value, guaranteeing a 32-bit width regardless of architecture. For example, you could:
#include <stdio.h>
#include <stdint.h>
typedef union {
struct {
uint32_t a : 8,
b : 8,
c : 8,
d : 8;
} bits;
uint32_t value;
} bitunion;
int main (void) {
bitunion bu = { .bits = {.a = 0, .b = 255, .c = 255, .d = 255} };
printf ("bu.bits.a: %u\n", bu.bits.a);
printf ("bu.bits.b: %u\n", bu.bits.b << 8);
printf ("bu.bits.c: %u\n", bu.bits.c << 16);
printf ("bu.bits.d: %u\n", bu.bits.d << 24);
printf ("value : %u\n", bu.value);
return 0;
}
(note: the bitfield is made up of d-c-b-a bytes)
Example Use/Output
$ ./bin/shiftxstruct
bu.bits.a: 0
bu.bits.b: 65280
bu.bits.c: 16711680
bu.bits.d: 4278190080
value : 4294967040
Now, don't think these are the only ways to do this. You can use any combination of shifts and OR's as long as you accurately account for the bytes within your final value. Look things over and let me know if you have additional questions.

Going below zero in unsigned integer operations

I want to deduce a list of 16-bit unsigned integers from another list of 16-bit unsigned integers.
For example, given the list:
10000, 12349, 32333, 3342
and I know the first integer of the other list is 0, now I want to deduce the rest. The mapping is to subtract 10000 from them, I got
0, 2349, 22333, 58878
where 58878 = (3342-10000+65536) modulo 65536 as the result of a wrapping.
The pseudocode is something like:
void deduce(u_int16_t list1[100], u_int16_t *list2[100], u_int16_t first)
{
int diff = first - list1[0];
for (i = 0; i < 100; i++)
(*list2)[i] = (list1[i] + diff + 65536) % 65536;
}
but we know that there is no minus number in unsigned integers.
so how to do the mapping(or deduction)?
thanks!
unsigned integers variables can be subtracted more than they contain - if I understand correctly the question.
u_int16_t u = 10;
u -= 20; // => u = u - 20;
printf("%x, %u\n", u, u); // => fff6, 65526
The difference is
when displayed, u does not show a negative value - ie the MSb (most significant bit, ie bit 15) is interpreted (here) as 215, the next as 214 etc...
when extended (eg to 32 bits) the MBb is not propagated from bit 16 to bit 31 (as they would be if signed) - they're 0
when right shifted the value MSb is always 0 (would be the same as previous MSb if signed, e.g 1 for a negative value)
So your mapping will keep working with u_int16_t (and you don't need the % modulo 65536 if you work with that type everywhere since anyway the values are on 16 bits - the modulo is implicit).
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
void deduce(uint16_t list1[], uint16_t list2[], size_t size){
int32_t i, first = list1[0];
for(i=0;i<size;++i){
// list2[i]= list1[i] - first;
int32_t wk = list1[i];
wk -= first;
if(wk<0)
wk += 65536;
list2[i] = wk;
}
}
int main(void){
uint16_t list1[100] = {
10000,
12349,
32333,
3342
};
uint16_t list2[100];
int i;
deduce(list1, list2, 4);
for(i = 0; i<4; ++i)
printf("%5" PRIu16 "\n", list2[i]);
return 0;
}
I'm not quite understand your question, but if what you want is to subtract every element of the first list by the different between the first element of both list. This code should work.
void deduce(uint16_t list1[], uint16_t list2[], int size)
{
uint16_t diff = list1[0] - list2[0];
int i;
for (i=0; i<size; i++)
list2[i] = list1[i] - diff;
}
You don't need to pass list2 as u_int16_t* list2[] because you actually can edit the content of the array with u_int16_t list2[]. Only use u_int16_t* list2[] if you want to do dynamic memory allocation in this function.

Fastest way to calculate possible values of unsigned int with N unreliable bits?

Given an unsigned int A (32 bit), and another unsigned int B, where B's binary form denotes the 10 "least reliable" bits of A, what is the fastest way to expand all 1024 potential values of A? I'm looking to do this in C.
E.g uint B is guaranteed to always have 10 1's and 22 0's in it's binary form (10 least reliable bits).
For example, let's say
A = 2323409845
B = 1145324694
Their binary representations are:
a=10001010011111000110101110110101
b=01000100010001000100010010010110
B denotes the 10 least reliable bits of A. So each bit that is set to 1 in B denotes an unreliable bit in A.
I would like to calculate all 1024 possible values created by toggling any of those 10 bits in A.
No guarantees that this is certifiably "the fastest", but this is what I'd do. First, sieve out the fixed bits:
uint32_t const reliable_mask = ~B;
uint32_t const reliable_value = A & reliable_mask;
Now I'd preprocess an array of 1024 possible values of the unreliable bits:
uint32_t const unreliables[1024] = /* ... */
And finally I'd just OR all those together:
for (size_t i = 0; i != 1024; ++i)
{
uint32_t const val = reliable_value | unreliables[i];
}
To get the unreliable bits, you could just loop over [0, 1024) (maybe even inside the existing loop) and "spread" the bits out to the requisite positions.
You can iterate through the 1024 different settings of the bits in b like so:
unsigned long b = 1145324694;
unsigned long c;
c = 0;
do {
printf("%#.8lx\n", c & b);
c = (c | ~b) + 1;
} while (c);
To use these to modify a you can just use XOR:
unsigned long a = 2323409845;
unsigned long b = 1145324694;
unsigned long c;
c = 0;
do {
printf("%#.8lx\n", a ^ (c & b));
c = (c | ~b) + 1;
} while (c);
This method has the advantages that you don't need to precalculate any tables, and you don't need to hardcode the 1024 - it will loop based entirely on the number of 1 bits in b.
It's also a relatively simple matter to parallelise this algorithm using integer vector instructions.
This follows essentially the technique used by Kerrek, but fleshes out the difficult parts:
int* getValues(int value, int unreliable_bits)
{
int unreliables[10];
int *values = malloc(1024 * sizeof(int));
int i = 0;
int mask;
The function definition and some variable declarations. Here, value is your A and unreliable_bits is your B.
value &= ~unreliable_bits;
Mask out the unreliable bits to ensure that ORing an integer containing some unreliable bits and value will yield what we want.
for(mask = 1;i < 10;mask <<= 1)
{
if(mask & unreliable_bits)
unreliables[i++] = mask;
}
Here, we get each unreliable bit into an individual int for use later.
for(i = 0;i < 1024;i++)
{
int some_unreliables = 0;
int j;
for(j = 0;j < 10;j++)
{
if(i & (1 << j))
some_unreliables |= unreliables[j];
}
values[i] = value | some_unreliables;
}
The meat of the function. The outer loop is over each of the outputs we want. Then, we use the lowest 10 bits of the loop variable i to determine whether to turn on each unreliable bit, using the fact that the integers 0 to 1023 go through all possibilities of the lowest 10 bits.
return values;
}
Finally, return the array we built. Here is a short main that can be used to test it with the values for A and B given in your question:
int main()
{
int *values = getValues(0x8A7C6BB5, 0x44444496);
int i;
for(i = 0;i < 1024;i++)
printf("%X\n", values[i]);
}

Resources