LectEPE2206_A_C_Programming_Struct

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 27

EPE2206 Computer Systems and

Microprocessors

 C Structures
 Bit Fields

Dr Kwee Hiong Lee


kweehiong.lee@singaporetech.edu.sg
EPE2206 Computer Systems and
Microprocessors

 C Structures
Introduction

 Structures
● Collections of related variables under one name
● Can contain variables of different data types

● Commonly used to define records to be stored in files


● Combined with pointers, can create sophisticated data
structures
● Is an example of an object
Structure Definitions
 Example
struct score {
char matricno[20];
char lastname[20];
float marks;
};
● struct introduces the definition for score
● score contains three members
● Forgetting the semicolon that terminates a structure
definition is a syntax error
Structure Definitions (2)
 struct information
● A struct cannot contain an instance of itself
● Can contain a member that points to the same struct
● A structure definition does not use up memory
 Definitions
● Defined like other variables:
struct score student1, year1[30], *sPtr;
Structure Definitions (3)

 Can use a comma separated list:


struct score {
char matricno[20];
char lastname[20];
float marks;
} student1, year1[30], *sPtr;
 Valid Operations
● Assigning a structure to a structure of the same type
● Taking the address (&) of a structure
● Accessing the members of a structure
● Using the sizeof operator to determine the size of a
structure
Common Programming Errors

 Assigning a structure of one type to a structure


of a different type is a compilation error.

Comparing structures is a syntax error.


Accessing Members of Structures

● Accessing structure members


● Dot operator (.) used with structure variables
struct score student1;
printf( "%f", student1.marks );
● Arrow operator (->) used with pointers to structure
variables
struct score *sPtr = &student1;
printf( "%f", sPtr->marks );
Tips, Good practice and Errors
Error-Prevention Tip
 Avoid using the same names for members of structures of
different types. This is allowed, but it may cause confusion.

Good Programming Practice


 Do not put spaces around the -> and .
operators. Omitting spaces helps emphasize that the
expressions the operators are contained in are essentially
single variable names.

Syntax error
 Inserting space between the - and > components of the
structure pointer operator (or between the components of
any other multiple keystroke operator) is a syntax error.
EPE2206 Computer Systems and
Microprocessors

 Bit Fields
Bit Fields

 Bit field
● Specifies how many bits a field of a struct uses
● Enables better memory utilization
● Essential when modeling hardware
● Must be defined as int or unsigned

 Defining bit fields


● Follow unsigned or int member with a colon (:)
and an integer constant representing the width of
the field
Hard drive struct example

The processor typically uses several registers on the hard drive


controller to communicate with the HD, for example:

HDDS Drive Status


HDER Error register
HDCS Control Status register
HDWC Word Count
HDMA Memory Address
HDDA Disk Address
HDDB Pointer to Data Buffer
Hard drive struct example (2)

 A computer contains a I/O device: a hard drive controller. This


has a number of control registers, each 16 bits long.

 One of these, the CSR (control/status register) has the


following form, which is quite typical for an I/O device:

15 7 6 3 2 1 0

CSR
ERROR
CONTROL READY

INTERRUPT ENABLE

FUNCTION
GO
Hard drive struct example (3)

 Code:

int *csr;

csr = (int *) 0xFFFF8800;

 Access to the control status register and set func to 2 (010):

*csr = *csr | 4;
Hard drive struct example (4)

 We could define the placement of the elements of a


struct by attaching a bit field, which tells the compiler
how many bits to use:
struct cntl_stat {
int error: 1;
int cont_ready: 1;
int intr_enable: 1;
int func: 3;
int go: 1;
};

 This is not quite correct:


It takes no account of the positions within the register;
you must start with the Least Significant Bit.
Hard drive struct example (5)

 Firstly, we put the least significant bit first, then we add some
fillers for the parts we are not interested in:

struct cntl_stat {
int go: 1;
int func: 3;
int filler1: 2;
int intr_enable: 1;
int cont_ready: 1;
int filler2: 7;
int error: 1;
};

‘go’ is now the least significant bit.


Note that all the bit fields add up to 16 as expected.
Hard drive struct example (6)

 After this declaration, we can now refer to the bits using their
name, after declaring the appropriate variables:

struct cntl_stat *pt;

pt = (struct cntl_stat *) 0xFFFF8800;

pt->func = 2;

This clearly improves the readability of the code.


UART programming

 Let us now look at some code to access a UART


through its memory mapped address. Use address
FF00 as before.

 The CPU needs to be able to detect when a character


arrives. It can do this using polling, by inspecting the
Status Register of the UART.

 The CPU should continuously inspect the Receive bit


of the status register, and when it becomes set, a new
character has arrived. It can then retrieve the
character from the receive register.
UART programming (2)

 Output to the UART involves placing a byte in the


transmit register. The UART then sends the byte.

 But we must make sure that the UART is not still busy
with the previous character. Again we can make use of
the Status register to discover the state of the device.

 If the appropriate bit is set, then the device is busy,


and a new character should not be sent.

 We’ll access the UART using a pointer, of course. First


we must model the registers of the device using a struct.
UART register layout

 The registers are assumed to be mapped as follows:

Word 1 status register


Word 2 mode register
Word 3 receive register
Word 4 transmit register

 Words are used to keep the address boundaries even.

 If the Status register is mapped at FF00, then the


Mode register is at FF02, Rx at FF04, and Tx at FF06.

 These details are found in the data sheet of the UART.


UART register layout (2)

 We’ll make the following assumptions:

• Bit 0 in the Status Register indicates whether the


Transmit Register is available.

• Bit 1 in the Status Register indicates whether


something has been received.
Programming the UART

Example: echo character from keyboard to screen.


Declarations:
struct epci { // Enhanced Programmable
int status; // Communications Interface
int mode;
int tx;
int rx;
};

struct epci *uart; // pointer to UART


char c;
Programming the UART (2)

Code for an read-then-write loop:


uart = (struct epci *) 0xFF00;
for(;;) {
if ((uart->status & (1 << 1)) != 0){
// read it, and remove parity bit
c = uart->rx & 127;
while ((uart->status & 1) == 0);
// write it
uart->tx = c;
}
}
Programming the UART (3)

// UART programming example, using functions

// function prototypes
char readUart();
void writeUart(char);

struct epci {
int status;
int mode;
int tx;
int rx;
};

struct epci *uart; // pointer to UART


Programming the UART (4)

// wait until something is received,


// then grab it
char readUart() {
char c;

for(;;) {
if ((uart->status & 2) != 0){
// read it, and remove parity bit
c = uart->rx & 127;
return(c);
}
}
}
Programming the UART (5)

// wait until transmitter is free,


// then transmit
void writeUart(char c)
{
// wait until the UART is ready
while ((uart->status & 1) == 0)
/* do nothing */;
// write it
uart->tx = c;
}
Programming the UART (6)

// main loop
main() {
char c;

uart = (struct epci*) 0xFF00;

for(;;) {
c = readUart();
writeUart(c);
}
}

You might also like