How Data Store in ARM processor - c

I'm newbie in ARM experiment and I have a problem with concept of data in this processor.
I ran into trouble. there is code to check timer interval:
// get the current timer 0 count
unsigned long Timer0_GetTimestamp(void)
{
return T0TC;
}
// check to see if a timestamp is in the past
// returns 1 if in the past, 0 if not
int Timer0_TimestampExpiredCk(unsigned long timestamp)
{
unsigned long now = T0TC;
if (now > timestamp)
{
if ((now - timestamp) < 0x80000000)
return 1;
else
return 0;
}
else
{
if ((timestamp - now) >= 0x80000000)
return 1;
else
return 0;
}
}
// pause for a specific number of milliseconds
void Timer0_Delay(unsigned long milliseconds) {
unsigned long timestamp = Timer0_GetTimestamp() + milliseconds;
while (!Timer0_TimestampExpiredCk(timestamp));
}
I have a problem with the number "0x80000000". Should we consider this number as a 2's complement or just binary ?
it is supposed, when the difference between two variable is Zero we change our flag. Correct me if I wrong.
Thank you

(your question has nothing to do with ARM, it is a language question).
what do you want that number to be? you can specify it 0x8000000UL will make it an unsigned long yes?
BTW if you are wanting 0x80000000 as an unsigned long then you can also just look at the msbit of the now-timestamp result
if((now-timestamp)&0x80000000)
return 0;
else
return 1;
and there is no ambiguity there.
or
return (~(now-timestamp))>>31;
Might need an &1 on the end of that if unsigned long is 64 bits, not if unsigned long is 32.

In C, the constant 0x8000000 would be represented as an unsigned int as long as int is 32 bits or greater. This because the compiler must choose the first type from the following list in which the constant can be represented:
int
unsigned int
long
unsigned long
long long
unsigned long long
(C99 standard section 6.4.4.1)
And 0x80000000 can't be represented as a 32 bit int, at least not in 2's complement.
Both of the variables being compared are unsigned int. I can't see any purpose in this comparison with 0x80000000. Surely to check if a timestamp is in the past you just need to do the comparison
return (now > timeStamp);
Your code returns true if the time stamp is in the past unless it is a very long way in the past i.e. more than 0x80000000 milliseconds. It also returns true if the timestamp is a long way in the future.
What's T0TC by the way? If it's a constant, your timer will never expire.

Related

Calculating max long value using exponent overflows

I'm trying to figure out maximum value for type long by calculating an exponential of base 2 to the power of the bit number.
Unfortunately the calculation overflows at step 61 and I don't understand why.
long exponential(int base, int exponent)
{
long result = (long)base;
for (int i = 0; i < exponent; i++) {
result *= base;
}
return result;
}
unsigned int sLong = sizeof(long);
long lResult = exponential(2, (sLong * 8) - 1);
lResult is 0 after running the function.
What's odd is that when I do this for char, short and int it works fine.
The code here has an off-by-one error.
Consider the following: what is the result of exponential(10, 2)? Empirical debugging (use a printf statement) shows that it's 1000. So exponential calculates the mathematical expression be+1.
The long type usually has 64 bits. This seems to be your case (seeing that the overflow happens around step 64). Seeing that it's a signed type, its range is (typically) from -263 to 263-1. That is, the maximal power of 2 that the data type can represent is 262; if the code tries to calculate 263, then overflow happens (you probably want to avoid it).
So, because of the off-by-one error, the code will cause an overflow for exponent greater or equal to 62.
To fix the off-by-one error, start multiplying from 1:
long power_of(int base, int exponent)
{
long result = (long)1; // 0th power of base is 1
for (int i=0; i<exponent;i++) {
result*=base;
}
return result;
}
However, this will not get rid of the overflow, because the long data type cannot represent the number 263. Fortunately, you can use unsigned long long, which is guaranteed to be big enough for the type of calculations you are doing:
unsigned long long power_of(int base, int exponent)
{
unsigned long long result = 1ULL; // 0th power of base is 1
for (int i=0; i<exponent;i++) {
result*=base;
}
return result;
}
Print it with the llu format:
printf("%llu", power_of(2, 63));

How to assign an int to unsigned long using C?

I am using C language. There is a function named "npu_session_total".
Then, I will use the return value of this func and assign it to an unsigned long variable "accelerated_count".
int npu_session_total(void)
{
// this will return an int
return atomic_read(&npu_session_count);
}
........
unsigned long accelerated_count = npu_session_total();
Will this cause any problems? How can I do the cast?
Thanks!
Assigning an int to a unsigned long can be done simply as OP did. It is well defined in C. When some_int_value >= 0 it will always fit unchanged into an unsigned long.
INT_MAX <= UINT_MAX <= ULONG_MAX
No cast, masking, nor math is needed - just like OP did.
unsigned long some_unsigned_long_object = some_int_value;
The trick is when some_int_value < 0. The value saved will be some_int_value + ULONG_MAX + 1. #AnT Now is this OK for OP's code? Perhaps not.
A safer conversion would test for negativeness first.
int session_total = npu_session_total();
if (session_total < 0) {
Handle_Negative_Case(session_total);
}
else {
unsigned long accelerated_count = npu_session_total();
...
}
#OP comments that the int value should never be negative. Defensive coding would still detect negative values and handle that. Maybe a simple error message and exit.

Adding 32 bit signed in C

I have been given this problem and would like to solve it in C:
Assume you have a 32-bit processor and that the C compiler does not support long long (or long int). Write a function add(a,b) which returns c = a+b where a and b are 32-bit integers.
I wrote this code which is able to detect overflow and underflow
#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */
#define INT_MAX 2147483647 /* maximum (signed) int value */
int add(int a, int b)
{
if (a > 0 && b > INT_MAX - a)
{
/* handle overflow */
printf("Handle over flow\n");
}
else if (a < 0 && b < INT_MIN - a)
{
/* handle underflow */
printf("Handle under flow\n");
}
return a + b;
}
I am not sure how to implement the long using 32 bit registers so that I can print the value properly. Can someone help me with how to use the underflow and overflow information so that I can store the result properly in the c variable with I think should be 2 32 bit locations. I think that is what the problem is saying when it hints that that long is not supported. Would the variable c be 2 32 bit registers put together somehow to hold the correct result so that it can be printed? What action should I preform when the result over or under flows?
Since this is a homework question I'll try not to spoil it completely.
One annoying aspect here is that the result is bigger than anything you're allowed to use (I interpret the ban on long long to also include int64_t, otherwise there's really no point to it). It may be temping to go for "two ints" for the result value, but that's weird to interpret the value of. So I'd go for two uint32_t's and interpret them as two halves of a 64 bit two's complement integer.
Unsigned multiword addition is easy and has been covered many times (just search). The signed variant is really the same if the inputs are sign-extended: (not tested)
uint32_t a_l = a;
uint32_t a_h = -(a_l >> 31); // sign-extend a
uint32_t b_l = b;
uint32_t b_h = -(b_l >> 31); // sign-extend b
// todo: implement the addition
return some struct containing c_l and c_h
It can't overflow the 64 bit result when interpreted signed, obviously. It can (and should, sometimes) wrap.
To print that thing, if that's part of the assignment, first reason about which values c_h can have. There aren't many possibilities. It should be easy to print using existing integer printing functions (that is, you don't have to write a whole multiword-itoa, just handle a couple of cases).
As a hint for the addition: what happens when you add two decimal digits and the result is larger than 9? Why is the low digit of 7+6=13 a 3? Given only 7, 6 and 3, how can you determine the second digit of the result? You should be able to apply all this to base 232 as well.
First, the simplest solution that satisfies the problem as stated:
double add(int a, int b)
{
// this will not lose precision, as a double-precision float
// will have more than 33 bits in the mantissa
return (double) a + b;
}
More seriously, the professor probably expected the number to be decomposed into a combination of ints. Holding the sum of two 32-bit integers requires 33 bits, which can be represented with an int and a bit for the carry flag. Assuming unsigned integers for simplicity, adding would be implemented like this:
struct add_result {
unsigned int sum;
unsigned int carry:1;
};
struct add_result add(unsigned int a, unsigned int b)
{
struct add_result ret;
ret.sum = a + b;
ret.carry = b > UINT_MAX - a;
return ret;
}
The harder part is doing something useful with the result, such as printing it. As proposed by harold, a printing function doesn't need to do full division, it can simply cover the possible large 33-bit values and hard-code the first digits for those ranges. Here is an implementation, again limited to unsigned integers:
void print_result(struct add_result n)
{
if (!n.carry) {
// no carry flag - just print the number
printf("%d\n", n.sum);
return;
}
if (n.sum < 705032704u)
printf("4%09u\n", n.sum + 294967296u);
else if (n.sum < 1705032704u)
printf("5%09u\n", n.sum - 705032704u);
else if (n.sum < 2705032704u)
printf("6%09u\n", n.sum - 1705032704u);
else if (n.sum < 3705032704u)
printf("7%09u\n", n.sum - 2705032704u);
else
printf("8%09u\n", n.sum - 3705032704u);
}
Converting this to signed quantities is left as an exercise.

Determine the ranges of char by direct computation in C89 (do not use limits.h)

I am trying to solve the Ex 2-1 of K&R's C book. The exercise asks to, among others, determine the ranges of char by direct computation (rather than printing the values directly from the limits.h). Any idea on how this should be done nicely?
Ok, I throw my version in the ring:
unsigned char uchar_max = (unsigned char)~0;
// min is 0, of course
signed char schar_min = (signed char)(uchar_max & ~(uchar_max >> 1));
signed char schar_max = (signed char)(0 - (schar_min + 1));
It does assume 2's complement for signed and the same size for signed and unsigned char. While the former I just define, the latter I'm sure can be deduced from the standard as both are char and have to hold all encodings of the "execution charset" (What would that imply for RL-encoded charsets like UTF-8).
It is straigt-forward to get a 1's complement and sing/magnitude-version from this. Note that the unsigned version is always the same.
One advantage is that is completely runs with char types and no loops, etc. So it will be still performant on 8-bit architectures.
Hmm ... I really thought this would need a loop for signed. What did I miss?
Assuming that the type will wrap intelligently1, you can simply start by setting the char variable to be zero.
Then increment it until the new value is less than the previous value.
The new value is the minimum, the previous value was the maximum.
The following code should be a good start:
#include<stdio.h>
int main (void) {
char prev = 0, c = 0;
while (c >= prev) {
prev = c;
c++;
}
printf ("Minimum is %d\n", c);
printf ("Maximum is %d\n", prev);
return 0;
}
1 Technically, overflowing a variable is undefined behaviour and anything can happen, but the vast majority of implementations will work. Just keep in mind it's not guaranteed to work.
In fact, the difficulty in working this out in a portable way (some implementations had various different bit-widths for char and some even used different encoding schemes for negative numbers) is probably precisely why those useful macros were put into limits.h in the first place.
You could always try the ol' standby, printf...
let's just strip things down for simplicity's sake.
This isn't a complete answer to your question, but it will check to see if a char is 8-bit--with a little help (yes, there's a bug in the code). I'll leave it up to you to figure out how.
#include <stdio.h>
#DEFINE MMAX_8_BIT_SIGNED_CHAR 127
main ()
{
char c;
c = MAX_8_BIT_SIGNED_CHAR;
printf("%d\n", c);
c++;
printf("%d\n", c);
}
Look at the output. I'm not going to give you the rest of the answer because I think you will get more out of it if you figure it out yourself, but I will say that you might want to take a look at the bit shift operator.
There are 3 relatively simple functions that can cover both the signed and unsigned types on both x86 & x86_64:
/* signed data type low storage limit */
long long limit_s_low (unsigned char bytes)
{ return -(1ULL << (bytes * CHAR_BIT - 1)); }
/* signed data type high storage limit */
long long limit_s_high (unsigned char bytes)
{ return (1ULL << (bytes * CHAR_BIT - 1)) - 1; }
/* unsigned data type high storage limit */
unsigned long long limit_u_high (unsigned char bytes)
{
if (bytes < sizeof (long long))
return (1ULL << (bytes * CHAR_BIT)) - 1;
else
return ~1ULL - 1;
}
With CHAR_BIT generally being 8.
the smart way, simply calculate sizeof() of your variable and you know it's that many times larger than whatever has sizeof()=1, usually char. Given that you can use math to calculate the range. Doesn't work if you have odd sized types, like 3 bit chars or something.
the try hard way, put 0 in the type, and increment until it doesn't increment anymore (wrap around or stays the same depending on machine). Whatever the number before that was, that's the max. Do the same for min.

ProjectEuler#3: Why is it telling me that this division breaks even when it doesn't?

For smaller numbers, my code seems to find the highest prime number ok. However, for this particular larger number it thinks 600851475143 is divisible by 7 (It is not a factor, which I verified using wolfram).
My algorithm to solve the problem is as follows:
1) Let p=value for which we want to find the immediately smaller prime number.
2) Check if p is prime using isComposite(p)
3) If p is composite, decrement p and try again
4) Stop when found a prime number
isComposite(p) works as follows:
1) Let i=2
2) Given some number 'limit', check to see if i divides 'limit'
3) If it does, then return i (Originally, it was 1 but I wanted to check what it think divides 'limit')
4) If i does not divide limit, increment i and repeat starting from 2, stopping when i>= sqrt(limit). This is because factors of a number, if they exist, occur in pairs in which one value is less than sqrt(number).
Here is the call tree:
printf("P3:%lu\n",p3v2(600851475143)); //Print the highest prime
Here is the p3v2() function:
unsigned long p3v2(unsigned long limit)
{
unsigned long i = limit;
while(i>1)
{
printf("Checking %lu\n", i);
if(!(isComposite(i) != 0))
{
printf("%lu is prime!\n", isComposite(i));
return i;
}
else
{
printf("%lu is composite!\n", isComposite(i));
i--;
}
}
return -1;
}
And isComposite()
unsigned long isComposite(unsigned int limit)
{
unsigned long i = 2;
unsigned long searchUpperBound = (unsigned long)sqrt(limit); //Only need to search up to sqrt(limit) to see if there is a factor
while(i<=searchUpperBound) //See if numbers up through searchUpperBound divides limit
{
if(limit%i==0) //If factor found
return i;
else
i++;
}
return 0;
}
unsigned long is probably 32-bit on your machine. 600851475143 (hex 0x8BE589EAC7) doesn't fit in an unsigned long, it's actually 0xE589EAC7 (decimal 3851020999, which is dividable by 7) that is used in calculation.
The solution is to use unsigned long long instead.
I'm going to assume that unsigned longs are 64-bit on your machine and unsigned ints are 32-bit. Otherwise your printfs would probably be printing weird numbers already. If this is all true, the culprit is this line:
unsigned long isComposite(unsigned int limit)
Here, you should make limit an unsigned long:
unsigned long isComposite(unsigned long limit)
However, I would suggest you remove all your unsigned longs and replace them with uint64_t:
#include <stdint.h>
uint64_t isComposite(uint64_t limit)

Resources