0% found this document useful (0 votes)
13 views34 pages

Lecture 10

Uploaded by

en.lennart.berg
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views34 pages

Lecture 10

Uploaded by

en.lennart.berg
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

Realtime Systems – SMD138

Lecture 10:
Hardware interfacing and bit-level
programming
Burns/Wellings ch 15

1
Basics
• The bit:
- 0 or 1
- high or low voltage
• The byte:
- a collection of 8 bits
• The word:
- 32 bits on modern machines
- 16 bits on smaller architectures
- 64-bit machines are coming

REALTIME SYSTEMS – SMD138

2
Binary numbers
• There are 256 different possibilities of combining
bits in a byte
• These can be ordered as follows:
00000000
00000001
00000010
00000011
00000100
00000101
...
11111110
11111111
REALTIME SYSTEMS – SMD138

3
Integers
• Now let
- 00000000 denote the integer 0
- 00000001 denote the integer 1
- 00000010 denote the integer 2, etc...
• It’s easy to design hardware that
- maps 00000001 and 00000010 onto 00000011
- maps 00000010 and 00000010 onto 00000100
- ...
- i.e., maps 1 and 2 onto 3, 2 and 2 onto 4, ...
• Thus we can implement addition, subtraction, ...
REALTIME SYSTEMS – SMD138

4
Manipulating bits
• In principle, we could define any bit-manipulating
function by just using addition and subtraction
• However, such a scheme will be very bulky for bit
patterns that don’ rea"y represent integers; e.g., bits
that represent status and command flags in some
hardware device registers
• Here we would rather like operations that could
- map 00000010 and 00000011 onto 00000010
(take the logical AND of the bit values)
- map 00001111 onto 11110000
(invert all bit values)
- etc
REALTIME SYSTEMS – SMD138

5
Bit operations
• Luckily, such operations are available in C:
- Bitwise AND (a & b)
- Bitwise OR (a | b)
- Bitwise XOR (a ^ b)
- Bitwise NOT (~ a)
- Shift bits left (a << b)
- Shift bits right (a >> b)
• However: the standard integer representation isn’t
very convenient for this purpose (which bits are
actually set in the representation of 137?)
• Writing bit strings isn’t very convenient either...

REALTIME SYSTEMS – SMD138

6
Alternative bases
• Notice: the decimal number system uses the base 10
(a digit to the left is worth 10 times more)
• The binary number system uses the base 2
(a digit to the left is worth twice as much)
• Idea: use a base that is > 2, but still a power of 2
• That should give shorter constants, but still
provide for good correspondence with bit patterns
• Two alternative bases have become popular:
- The octal system (base 8)
- The hexadecimal system (base 16)

REALTIME SYSTEMS – SMD138

7
The octal system
• Denote three bits by a number 0 - 7:
000 (0)
001 (1)
010 (2)
011 (3)
100 (4)
101 (5)
110 (6)
111 (7)
• A byte is then given by 3 octal numbers, of which
the first is < 4
• In C, all numbers prefixed by 0 are octal
REALTIME SYSTEMS – SMD138

8
The hexadecimal system
• Denote four bits by a “number” 0 - 9, a - f:
0000 (0) 1000 (8)
0001 (1) 1001 (9)
0010 (2) 1010 (a)
0011 (3) 1011 (b)
0100 (4) 1100 (c)
0101 (5) 1101 (d)
0110 (6) 1110 (e)
0111 (7) 1111 (f)
• A byte is given by 2 hexadecimal numbers (nibbles)
• In C, all numbers prefixed by 0x are hexadecimal

REALTIME SYSTEMS – SMD138

9
Examples

Binary Decimal Octal Hexadecimal


00000000 0 0 0x00
11111111 255 0377 0xff
10000000 128 0200 0x80
00001111 15 017 0x0f
00001000 8 010 0x08
00001100 12 014 0x0c
00010000 16 020 0x10

REALTIME SYSTEMS – SMD138

10
Bitwise AND
0xc1 & 0xea = 0xc0

0xc1 : 11000001
0xea : 11101010
0xc0 : 11000000
1 AND 0 = 0
0 AND 1 = 0
0 AND 0 = 0
0 AND 1 = 0
0 AND 0 = 0
0 AND 1 = 0
1 AND 1 = 1
1 AND 1 = 1
REALTIME SYSTEMS – SMD138

11
Bitwise OR
0xc1 & 0xea = 0xeb

0xc1 : 11000001
0xea : 11101010
0xeb : 11101011
1 OR 0 = 1
0 OR 1 = 1
0 OR 0 = 0
0 OR 1 = 1
0 OR 0 = 0
0 OR 1 = 1
1 OR 1 = 1
1 OR 1 = 1
REALTIME SYSTEMS – SMD138

12
C.f. logical AND, OR

• Don’t confuse the bitwise operators & and | with


the logical operators that work on integer expressions:
0 && 17 = 0
31 || -28 = 1
0x40 || 0x02 = 1
• These operators only distinguish between the values
zero and non-zero

REALTIME SYSTEMS – SMD138

13
More bitwise operations

• Bitwise XOR
0xc1 ^ 0xea = 0x2b 11000001 (0xc1)
11101010 (0xea)
00101011 (0x2b)
• Bitwise NOT
~ 0xc1 = 0x3e 11000001 (0xc1)
00111110 (0x3e)

REALTIME SYSTEMS – SMD138

14
Accessing a single bit
• Setting a bit
0xc1 | 0x08 = 0xc9 11000001 (0xc1)
00001000 (0x08)
11001001 (0xc9)
• Clearing a bit
0xc1 & 0xbf = 0x81 11000001 (0xc1)
10111111 (0xbf)
10000001 (0x81)
• Alternatively
0xc1 & (~0x40) = 0x81 01000000 (0x40)
10111111 (0xbf)

REALTIME SYSTEMS – SMD138

15
Shifting
• Shifting left
0x1c << 2 = 0x70 00011100 (0x1c)
00000010 (2)
01110000 (0x70)
• Shifting right
0x1c >> 2 = 0x07 00011100 (0x1c)
00000010 (2)
00000111 (0x07)
• “New” bits are zero (or sign-extensions – see later)
• Note that the second argument is really treated as
an integer, not just a bit pattern

REALTIME SYSTEMS – SMD138

16
Using bit numbers
• Setting bit number 3
1 << 3 = 0x08 00000001 (1)
00000010 (3)
00001000 (0x08)
• Setting bit number 0
1 << 0 = 0x01 00000001 (1)
00000000 (0) Bit numbers
00000001 (0x01) are counted
• Setting bit number x from right,
starting from 0
1 << x = ... 00000001 (1)
(x)
...00100... (...)
REALTIME SYSTEMS – SMD138

17
Storage sizes
• A byte corresponds to the type char in C
• A 32-bit word corresponds to an int on most
machines, a long on some (check!)
• A 16-bit word mostly maps to a short
• Chopping off higher bits:
int value = expr;
char abyte;
abyte = value;
• Sign-extending up to higher bits:
char abyte = expr;
int value;
value = abyte;
REALTIME SYSTEMS – SMD138

18
Signed integers
• Swapping the two range halves:
10000000 (-128)
10000001 (-127) char : (-128) – 127
... short : (-32768) – 32767
11111110 (-2)
long : (-2147483648) – 2147483647
11111111 (-1)
00000000 (0)
00000001 (1)
00000010 (2) Note:
... 0xffffffff < 0 = TRUE
01111110 (126)
01111111 (127)
REALTIME SYSTEMS – SMD138

19
Sign extension
• Shifting negative numbers to the right
char num = -128; 10000000 (-128, or 0x80)
num = num >> 2; 00000010 (2)
( num == -32 ) 11100000 (-32, or 0xe0)
• Note: sign-extension only applies to signed types
• Use variables of unsigned type to prevent sign-
extension when shifting right:
unsigned char val = 0xf0; 11110000
val = val >> 4; 00000010
( val == 0x0f ) 00001111

REALTIME SYSTEMS – SMD138

20
Separate bus architecture

data bus I/O data bus

Memory CPU Device Device

address bus I/O address bus

I/O devices accessed by special I_O instructions


Example: Intel x86 family
REALTIME SYSTEMS – SMD138

21
Memory-mapped architecture

data bus

CPU Memory Device Device

address bus

I/O devices appear as plain memory cells


Example: the PowerPC family
REALTIME SYSTEMS – SMD138

22
Accessing I/O ports

• Reading a byte from port 0x30d Recall: the unsigned


unsigned char val = in8(0x30d); modifier changes
the char range to
• Writing a word to port 0xf4 0 – 255
out32(0xf4, expr);
• QNX provides operations for reading and writing
8, 16 and 32-bit ports in various combinations (see
documentation)
• Note: the port concept is only valid on architectures tha#
use separate busses for I/O and memory

REALTIME SYSTEMS – SMD138

23
Memory-mapped I/O
• Addressing a byte
volatile char *ptr = (volatile char *)0xffff0004;
char tmp = *ptr;
*ptr = new_val;
• Addressing a word
volatile int *ptr = (volatile int *)0xffff0004;
char tmp = *ptr;
*ptr = new_val;
• The volatile keyword ensures that the compiler
isn’t fooled into optimizing the pointer access as if
it pointed to real memory

REALTIME SYSTEMS – SMD138

24
Big vs. little endianess
• Where is the “first” byte of a word – to the right or
to the left?
• Example:
long a = 0x12345678;
char *p = (char *)&a;
printf(”%02X\n”, *p);
• What gets printed depends on the architecture
- On a little-endian machine (Intel): 0x12
- On a big-endian machine (most others): 0x78
• Use caution when treating words as bytes
(and vice versa)!
REALTIME SYSTEMS – SMD138

25
Examples

• Testing a certain bit (separate I/O bus)


#define OK_BIT 5
#define OK_MASK (1 << OK_BIT)
#define STATUS_REG 0x34c

if (in8(STATUS_REG) & OK_MASK)


// bit 5 was set in status register
else
// it was not

REALTIME SYSTEMS – SMD138

26
Examples

• Testing a certain bit (memory-mapped I/O)


#define OK_BIT 5
#define OK_MASK (1 << OK_BIT)
volatile char *status_reg = (volatile char *)0x34c;

if (*status_reg & OK_MASK)


// bit 5 was set in status register
else
// it was not

REALTIME SYSTEMS – SMD138

27
Examples

• Setting a certain bit (separate I/O bus)


#define OK_BIT 5
#define OK_MASK (1 << OK_BIT)
#define RW_REG 0x34c

out8(RW_REG, in8(RW_REG) | OK_MASK));

REALTIME SYSTEMS – SMD138

28
Examples

• Setting a certain bit (memory-mapped I/O)


#define OK_BIT 5
#define OK_MASK (1 << OK_BIT)
volatile char *reg = (volatile char *) 0x34c;

*reg = *reg | OK_MASK;

REALTIME SYSTEMS – SMD138

29
Note:
• There is nothing that guarantees that reading and
writing on the same address will refer to the same
register
• For example, some devices map a status register
(for reading) and a command register (for writing)
to the same address:
#define IS_READY (1 << 5)
#define CONVERT (1 << 5)
#define STATUS_REG 0x34c
#define CMD_REG 0x34c

if (in8(STATUS_REG) & IS_READY)


out8(CMD_REG, CONVERT);
REALTIME SYSTEMS – SMD138

30
Shadowing
• The correct way to update such overlayed registers
is to use a shadow:
#define CONVERT (1 << 5)
#define CMD_REG 0x34c
char cmd_shadow;
...
cmd_shadow |= CONVERT;
out8(CMD_REG, cmd_shadow);
• It’s important to let all changes to CMD_REG be
reflected in cmd_shadow as well
• Notice the convenient assignment sytax C provides
var op= expr; means var = var op expr;
REALTIME SYSTEMS – SMD138

31
Single write

• In most cases, though, output ports are written as


single values:
#define CTRL (1 << 3)
#define SIZE1 (1 << 4)
#define SIZE2 (2 << 4)
#define SIZE3 (3 << 4)
#define EXTRAFLAG (1 << 6)
...
out8( 0xfff0, EXTRAFLAG | SIZE2 | CTRL );

REALTIME SYSTEMS – SMD138

32
Reading multi-bit values
• Masking out a multi-bit value, and then shifting:
#define DONE (1 << 3)
#define SIZE1 (1 << 4)
#define SIZE2 (2 << 4)
#define SIZE3 (3 << 4)
#define SIZEMASK (3 << 4)
#define READY (1 << 6)
...
switch ((in8(0xfff0) & SIZEMASK) >> 4) {
case 1: ...
case 2: ...
case 3: ...
}
REALTIME SYSTEMS – SMD138

33
A slightly bigger example

• In the register pointed to by reg, set n bits starting at


bit number p to the value of x
void setbits(int *reg, int n, int p, int x) {
int mask = ~(~0 << n); // the mask
int data = (x & mask) << p; // data to be set
*reg &= ~(mask << p); // clear current bits
*reg |= data; // OR in data
}

• [Notice the assumption that reg is read/write]

REALTIME SYSTEMS – SMD138

34

You might also like