CPSC 355: Tutorial 11
Review
PhD Student
Fall 2017
Bitwise Shifts
It's also often useful to shift bits left and right in a register, for this we have >> (shift right) and << (shift left). Bits that exceed the width of the register are dropped
1001 >> 1
--------
0100
Example
Shift left can be used as a fast "multiply by 2" and shift right can be used as a fast "integer divide by 2"
1001 << 1
--------
0010
Bitwise Shifts
Logical Shift Right, let's assume a 4 bit register shift by one
1 | 1 | 0 | 1 |
---|
0 | 1 | 1 | 0 |
---|
Ignored
0
Appropriate for unsigned numbers, signed numbers need an arithmetic shift
Bitwise Shifts
Arithmetic Shift Right, let's assume a 4 bit register shift by one
1 | 1 | 0 | 1 |
---|
1 | 1 | 1 | 0 |
---|
Ignored
Keeps the sign of the number
Bitwise Shifts
Logical Shift Left, let's assume a 4 bit register shift by one
1 | 1 | 0 | 1 |
---|
1 | 0 | 1 | 0 |
---|
Ignored
0
No such thing as arithmetic shift
Bitwise Shifts
#include <stdio.h>
void main(int argc, char *argv[]) {
char a = 0b11111100;
unsigned char b = 0b1001;
printf("a=%d, b=%d\na >> 2 = %d, b >> 2 = %d\n", a, b, a >> 2, b >> 2);
}
fmt: .string "a=%d, b=%d\na >> 2 = %d, b << 2 = %d\n"
.balign 4
.global main
main:
stp x29, x30, [sp, -16]!
mov x29, sp
ldr x0, =fmt
mov x1, 0b11111100
mov x2, 0b1001
asr x3, x1, 2 // This is because the first variable is signed
lsr x4, x2, 2 // This is because the second variable is signed
bl printf
ldp x29, x30, [sp], 16
ret
Bitwise Shifts
#include <stdio.h>
void main(int argc, char *argv[]) {
int a = -1; //0b1111...111 in binary
int b = -1; //
printf("a=%d, b=%d\na >> 1 = %d, b << 1 = %d\n", a, b, a >> 1, b << 1);
}
fmt: .string "a=%d, b=%d\na >> 2 = %d, b << 2 = %d\n"
.balign 4
.global main
main:
stp x29, x30, [sp, -16]!
mov x29, sp
ldr x0, =fmt
mov w1, -1
mov w2, -1
asr w3, w1, 1
lsl w4, w2, 1 // LSL is an Arithmetic shift
bl printf
ldp x29, x30, [sp], 16
ret
Arithmetic in binary
As it turns out, all the binary operations shown up until now are easy to implement in transistor logic.
With a few transistors it's easy to build an AND, OR, XOR operator -- but how do we add numbers?
Basically, we have to figure out how to use binary operations to perform arithmetic
Addition in binary
Let's start with an 8-bit example, binary addition works the same as base-10 addition
Addition in binary
Let's start with an 8-bit example, binary addition works the same as base-10 addition
Addition in binary
Moving on to a more general case
As it turns out, we can very easily express the results and carries
Assuming
Addition in binary
#include <stdio.h>
int main()
{
unsigned int a, b, result = 0;
unsigned int carry = 0, i = 0;
a = 100;
b = 123;
printf("%d + %d = \n", a, b);
for(i = 0; i < 32; i++)
{
int ai = a & 0x1; // get the first bit
int bi = b & 0x1;
result = result >> 1;
if(ai ^ bi ^ carry) {
result |= 0x80000000; // set the last bit of result
} else {
result &= 0x7FFFFFFF; // clear last bit of result
}
// Figure out what the carry should be
carry = ((ai ^ bi) & carry) | (ai & bi);
a = a >> 1;
b = b >> 1;
}
printf("%d\n", result);
}
Addition in binary
#include <stdio.h>
int main()
{
unsigned int a, b, result = 0;
unsigned int carry = 0, i = 0;
a = -100; // <---- This is now negative
b = 123;
printf("%d + %d = \n", a, b);
for(i = 0; i < 32; i++)
{
int ai = a & 0x1;
int bi = b & 0x1;
result = result >> 1;
if(ai ^ bi ^ carry) {
result |= 0x80000000;
} else {
result &= 0x7FFFFFFF;
}
carry = ((ai ^ bi) & carry) | (ai & bi);
a = a >> 1;
b = b >> 1;
}
printf("%d\n", result);
}
Multiplication in binary
Let's do another example, with an unsigned 4-bit number. Unsurprisingly, this works like base-10 arithmetic
Multiplication in binary
This is a little trickier to write out a recurrence relation between bits as we did before, but it's easy to see how to write an algorithm that does this.
Multiplication in binary
#include <stdio.h>
int main()
{
int multiplier, multiplicand, result_high, result_low, i, negative;
long int result, temp1, temp2;
multiplicand = 8192;
multiplier = 99;
result_high = 0;
result_low = 0;
printf("multiplier = 0x%08x (%d) multiplicand = 0x%09x (%d) \n\n",
multiplier, multiplier, multiplicand, multiplicand);
for(i = 0; i < 32; i++) {
if(multiplier & 1) {
result_high = result_high + multiplicand;
}
multiplier = multiplier >> 1;
result_low = result_low >> 1;
if(result_high & 1) {
result_low = result_low | 0x80000000;
} else {
result_low = result_low & 0x7FFFFFFF;
}
result_high = result_high >> 1;
}
printf("result_high = 0x%08x, result_low = 0x0%08x\n", result_high, result_low);
temp1 = (long int) result_high;
temp1 = temp1 << 32;
temp2 = (long int) result_low & 0xFFFFFFFF;
result = temp1 + temp2;
printf("64-bit result: 0x%016lx (%ld)\n", result, result);
}
Multiplication in binary
#include <stdio.h>
int main()
{
int multiplier, multiplicand, result_high, result_low, i, negative;
long int result, temp1, temp2;
multiplicand = 8192;
multiplier = 99;
result_high = 0;
result_low = 0;
printf("multiplier = 0x%08x (%d) multiplicand = 0x%09x (%d) \n\n",
multiplier, multiplier, multiplicand, multiplicand);
negative = multiplier < 0;
for(i = 0; i < 32; i++) {
if(multiplier & 1) {
result_high = result_high + multiplicand;
}
multiplier = multiplier >> 1;
result_low = result_low >> 1;
if(result_high & 1) {
result_low = result_low | 0x80000000;
} else {
result_low = result_low & 0x7FFFFFFF;
}
result_high = result_high >> 1;
}
if(negative) {
result_high = result_high - multiplicand;
}
printf("result_high = 0x%08x, result_low = 0x0%08x\n", result_high, result_low);
temp1 = (long int) result_high;
temp1 = temp1 << 32;
temp2 = (long int) result_low & 0xFFFFFFFF;
result = temp1 + temp2;
printf("64-bit result: 0x%016lx (%ld)\n", result, result);
}
Rounding
What does it mean to be divisible by two in binary?
Divisibly by 2 if the lowest bit is 0
What does it mean to be divisible by four in binary?
Divisibly by 4 if the lowest two bits are 0
Rounding Trick
stp lr, fp [sp, -size & -16]!
What's -16 in binary?
2's complement
Assuming 8bits
Rounding Trick
stp lr, fp [sp, -size & -16]!
What's let's take -size = 4?
Rounds downwards to the nearest integer divisible by 16
Rounding Trick
stp lr, fp [sp, -size & -16]!
What's let's take -size = 4?
Rounds downwards to the nearest integer divisible by 16
The Stack
OS |
Program |
Heap |
Free memory |
Stack |
low
high
Used to store local variables and arrays whose sizes are known at run time
local vars, return addrs, frame pointers etc... |
The Stack
void main(int argc, char *argv[]) {
char sum;
unsigned short product;
// more code...
}
The Stack
Let's tally what we need to store on the stack
- old lr and fp (16 bytes)
- sum (1 byte)
- product (2 bytes)
stp x29, x30, [sp, -(16 + 1 + 2) & -16]!
mov x29, sp
That's a total of 19 bytes
The Stack
high
Free memory |
old stack data |
$sp
Free memory |
x29 ($fp) |
x30 ($lr) |
??? |
??? |
old stack data |
$sp
$x29
The Stack
high
Free memory |
old stack data |
$sp
Free memory |
x29 ($fp) |
x30 ($lr) |
sum, product |
padding |
old stack data |
$sp
$fp
Sum is at fp+ 16, product is at fp+16+1
Choose a layout for variables on the stack
Next Day
Structs and Accessing Struct Members
CPSC 355: Tutorial 11
By Joshua Horacsek
CPSC 355: Tutorial 11
- 1,482