[go: up one dir, main page]

0% found this document useful (0 votes)
152 views36 pages

IL2206 L04 IO Programming

The document provides an overview of programming in C and assembler. It discusses programming in C including data types, variables, pointers, arrays, and memory management. It also discusses using the HAL library for embedded systems programming including busy wait I/O and accessing memory locations. Programming in assembler and mixing C and assembler is also briefly mentioned.

Uploaded by

Zedd Zina
Copyright
© Attribution Non-Commercial (BY-NC)
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)
152 views36 pages

IL2206 L04 IO Programming

The document provides an overview of programming in C and assembler. It discusses programming in C including data types, variables, pointers, arrays, and memory management. It also discusses using the HAL library for embedded systems programming including busy wait I/O and accessing memory locations. Programming in assembler and mixing C and assembler is also briefly mentioned.

Uploaded by

Zedd Zina
Copyright
© Attribution Non-Commercial (BY-NC)
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/ 36

Lecture 4

Programming in C and Assembler

Ingo Sander ingo@kth.se

Outline
Programming in C ! Programming with the HAL Library
!

IL2206 Embedded Systems

Programming in C

The programming language C


C has been developed as a systems programming language around 1970 ! C is a sequential imperative language ! C is often viewed as a macro-assembler , since most C-statements can efficiently be mapped on the instruction set of a von Neumann processor ! Java has inherited the large parts of the Csyntax, but is a more abstract language
!
IL2206 Embedded Systems 4

The programming language C


!

C has been designed with respect to an efficient implementation, unnecessary features have been left out
!

! !

There is no Boolean variable, integers are used instead of True and False (0 is False, all other integers correspond to True) There is no garbage collection Programmer can access memory locations that are not declared ...
IL2206 Embedded Systems 5

The programming language C


The C-programmer has a huge responsibility! ! C-code can be very fast ! BUT it is easy to produce bugs, which are not caught by the compiler
!
! ! ! !

Memory leaks Accessing wrong memory locations Assignment instead of comparison ...
IL2206 Embedded Systems 6

Be extremely careful, when you program with C!

Many C-books in the library!


!

If you do not feel very comfortable with C!

There are many books on C in the library! ! The course page gives recommendations
!

IL2206 Embedded Systems

Data Structures in Memory


!

In order to design an efficient program it is often important to know how data structures are located in memory
!

Number of cache misses can often be reduced

IL2206 Embedded Systems

Arryas in memory
An array is located as a sequence in the memory int x = 5; int y = 6; int a[5];
!
0x80 0x84 0x88 0x8C 0x90 0x94 0x98 5 6 x y a[0] a[1] a[2] a[3] a[4]

IL2206 Embedded Systems

Pointers
!

A pointer holds an address in the memory


!

0x80 0x84 0x88 0x8C 0x90 0x94 0x98

5 6

x y a[0] a[1] a[2] a[3] a[4]

A pointer points to a variable

int int int int

x = 5; y = 6; a[5]; *intpointer;

intpointer
10

IL2206 Embedded Systems

Pointers
/* Point to x */ intpointer = &x; /* Set x to 0 */ *intpointer = 0;
0x80 0x84 0x88 0x8C 0x90 0x94 0x98 0 6 x y a[0] a[1] a[2] a[3] a[4]

0x80
IL2206 Embedded Systems

intpointer
11

Pointers and Arrays


An array is located as a sequence in the memory ! Pointers can be used to access array elements /* Point to first array element */ intpointer = a;
!

0x80 0x84 0x88 0x8C 0x90 0x94 0x98

0 6

x y a[0] a[1] a[2] a[3] a[4]

0x88
IL2206 Embedded Systems

intpointer
12

Pointers and Arrays


intpointer = a; is equivalent to intpointer = &a[0]; intpointer = a + 1; is equivalent to intpointer = &a[1];
!

0x80 0x84 0x88 0x8C 0x90 0x94 0x98

0 6

x y a[0] a[1] a[2] a[3] a[4]

Pointer is incremented the size of its datatype (here one word)

0x88
IL2206 Embedded Systems

intpointer
13

Pointers and Arrays


Multidimensional arrays are stored as a sequence of elements, where the rightmost subject (here the column) varies fastest #define ROW 2 #define COL 3 int a[ROW][COL]; ! Pointers can be used to access the array intpointer = a + 4; *intpointer = 27;
!

0x80 0x84 0x88 0x8C 0x90 0x94 0x98 27

a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]

0x90

intpointer
14

IL2206 Embedded Systems

Refreshing C Bitwise Operators


! ! ! ! !

Bitwise complement (~) Bitwise and (&) Bitwise exclusive or (^) Bitwise inclusive or (|) Left shift (<<)
!

0s are shifted in for unsigned data types 0s are shifted in for signed data types the sign bit is shifted in
IL2206 Embedded Systems 15

Right shift (>>)


! !

Refreshing C
Relational, Equality and Logical Operators
Relational and Equality
! ! !

Logical
! ! !

! !

Less than (<) Greater than (>) Less than or equal (<=) Greater than or equal (>=) Equal to (==) Not equal to (!=)

Negation (!) Logical and (&&) Logical or (||)

IL2206 Embedded Systems

16

Storage Classes
!

A variable in C has two attributes:


! !

type (int, char, float, double, !) storage class (auto, extern, register, static)

IL2206 Embedded Systems

17

Storage Class auto


! !

Default storage class for variables declared in a function An automatic variable is only visible in the block it is declared in
!

System allocates memory when entering the block System releases the memory when leaving the block
!

Variable value is lost when leaving the block

int x; /* storage class extern */ int f(int x) { /* both a and b are */ /* of storage class auto */ int a; auto int b; /* a, b are visible here */ /* x is visible here */ } /* a, b are not visible here */ /* x is visible here */
18

IL2206 Embedded Systems

Storage Class extern


!

Default storage class for variables declared outside a function An extern variable is visible in the whole file after its declaration (global variable)
!

System allocates permanent storage for the variable

int x; /* storage class extern */ int f(int x) { /* both a and b are */ /* of storage class auto */ int a; auto int b; /* a, b are visible here */ /* x is visible here */ } /* a, b are not visible here */ /* x is visible here */
19

IL2206 Embedded Systems

The keyword extern


!

The keyword extern is used to tell the compiler to look for the variable or function elsewhere
! !

File1.c int a; File2.c int f(int x) { /* look for a outside */ /* this function */ extern int a; x = a; }
20

in another file in the same file (seldomly used)

Linkers task to combine the different object files to one executable

IL2206 Embedded Systems

Storage Class register


!

register storage class may only be declared inside functions Behaves in the same way as auto, but gives an additional recommendation to compiler that variable should be placed in register Compiler does not have to follow this advice
!

int f() { register int i; for(i=0; i < 1000; i++) a[i] = i; }

Number of registers is limited in CPU

IL2206 Embedded Systems

21

Storage Class static


!

In contrast to auto variables, static variables retain their values


!

permanent storage is assigned to the variable

int counter(void) { static int i = 0; i++; return i; }

IL2206 Embedded Systems

22

The type qualifier volatile


!

The type qualifier volatile indicates that a variable can be changed by other parts of the hardware in the system
!

Variable should not be put in register Variable can still be put in register or cache! Other directives (HAL functions) have to be used to avoid cache coherence problem
IL2206 Embedded Systems 23

Compiler may ignore volatile declaration


! !

More discussion in lecture on acceleration

If memory size is a constraint


!

Several small variables can be packed into a single variable


! ! !

Set of masks Bit-fields Unions

IL2206 Embedded Systems

24

If memory size is a constraint


Set of Masks #define FLAG1 1 #define FLAG2 2 #define FLAG3 4 char flags; /* contains all flags */ if ((flags & (FLAG1 | FLAG3)) == 0) /* True if both flags are 0 */
!
IL2206 Embedded Systems 25

If memory size is a constraint


!

A bit-field is a packed representation, where several small variables are integrated into one variable

struct myfield { unsigned var1 : 4; /* values from 0 to 15 */ int var2 : 3; /* values from -4 to 3 */ } x; x.var1 = 6;

Implementation of bit-field is machine dependent!


IL2206 Embedded Systems 26

If memory size is a constraint


! !

A union defines a set of alternative values that can be stored in the same portion of memory Programmer has responsibility to keep track of the data type stored in a union The size of the union corresponds to the largest data type

union int_or_float { int i; float f; } u;

IL2206 Embedded Systems

27

If memory size is a constraint


int main(void) { u.i = 0; printf("i: %10d f: %16.10e\n", u.i, u.f); u.i = 11; printf("i: %10d f: %16.10e\n", u.i, u.f); u.f = 11; printf("i: %10d f: %16.10e\n", u.i, u.f); return 0; } Output i: 0 f: 0.0000000000e+00 i: 11 f: 1.5414283108e-44 i: 1093664768 f: 1.1000000000e+01
IL2206 Embedded Systems 28

The sizeof operator


As discussed earlier the sizes of C-datatypes are not standardized ! The sizeof operator can be used to print the sizes of each type
!

printf("Size int*:%3u\n, sizeof(int*));

IL2206 Embedded Systems

29

The sizeof operator


!

Sizes of data types on teachers Linux machine


! ! ! ! ! ! !

char : 1 short : 2 int : 4 long : 8 float : 4 double: 8 int*: 8

(64 bit address space!)

IL2206 Embedded Systems

30

Many C-books in the library!


!

If you do not feel very comfortable with C! There are many books on C in the library!

IL2206 Embedded Systems

31

Nios II Programming with the HAL library

Busy Wait I/O


!

Busy Wait I/O is the most basic way to communicate with an I/O-device The processor wait until the I/ O-device has completed its current task Disadvantage: Processor cannot be used for other tasks during the waiting period! This method is also often called polling!

Example: Sending string via serial link


!

Busy Wait I/O Pseudo Code:


Characters = String; While not all characters sent Send next character; While Sender = Busy Wait; Done!

IL2206 Embedded Systems

33

C-Programming Testing of Bits


In order to test specific bits, it is needed to mask the other bits Example: ! Busy Flag: Busy = 1; Non-Busy = 0
!
7 0x1000 0x1001
IL2206 Embedded Systems

5 BF

0 Status Sender Sender Buffer


34

C-Programming Testing of Bits


define Status 0x1000 define Sender 0x1001 char *myString = Hello World; char *current_char;
7 0x1000 0x1001
IL2206 Embedded Systems

5 BF

0 Status Sender Sender Buffer


35

Accessing Memory Locations in C


Symbolic names can be defined for memory locations #define MEM_LOCATION 0x18 ! Functions can be defined to access memory
!

peek can be used to read a memory location (byte) char peek(char *location) {return *location;} ! poke can be used to write to a memory location (byte) void poke(char *location, char newval) {*location = newval;}
!
IL2206 Embedded Systems 36

Accessing Memory Locations in C


Symbolic names can be defined for memory locations #define MEM_LOCATION 0x18 ! Functions can be defined to access memory
!
!

peek can be used to read a memory location (byte) char peek(char *location) Altera provides the {return *location;} HAL library that abstracts from the underlying location (byte) ! poke can be used to write to a memoryhardware! void poke(char *location, char newval) {*location = newval;}
IL2206 Embedded Systems 37

Dont do this!

C-Programming Testing of Bits


Here you should use HAL functions!

while (current_char != \0) { poke(Sender, *current_char++); while ((peek(Status) & 0x20) != 0) ; } /* Mask needed, since other bits */ /* in status register may not be zero */
7 0x1000 0x1001
IL2206 Embedded Systems

5 BF

0 Status Sender Sender Buffer


38

Memory Locations shouldnt be accessed directly!


!

Software shall be flexible


!

Hardware could change

Programmers may make mistakes that the compiler would not do (e.g. memory alignment) HAL (Hardware Abstraction Layer) offers optimized device drivers to access peripheral devices and memory
IL2206 Embedded Systems 39

Customizing a Nios II Core The Tool SOPC Builder


!

Designer can select and configure


! !

CPU(s) peripherals

SOPC builder creates core that can be instantiated on FPGA

Symbolic names are accessible for software designers!

IL2206 Embedded Systems

40

The role of the HAL in a Nios II project


Your program uses the symbolic addresses and values specified in SOPC builder

Reference: Nios II Software Developers Handbook, Chapter 6


IL2206 Embedded Systems 41

The role of the HAL in a Nios II project


Your program uses the symbolic addresses and values specified in SOPC builder

Reference: Nios II Software Developers Handbook, Chapter 6


IL2206 Embedded Systems 42

The system.h file


The system.h file provides a complete software description of the Nios II system hardware ! The system.h file reflects the actual Nios II hardware, which is given by the *.ptf file. ! A new core means a new *.ptf file and a new system.h file
!

IL2206 Embedded Systems

43

The system.h file


!

The system.h file describes each peripheral and provides the following details:
! ! ! !

The hardware configuration of the peripheral The base address The IRQ (interrupt request) priority A symbolic name for the peripheral

If the hardware changes, the source code is still valid, since it uses another correct system.h file

NEVER edit the system.h file!!!


IL2206 Embedded Systems 44

Example of a system.h file


/* * system configuration * */ #define #define #define #define #define #define #define #define #define #define ALT_SYSTEM_NAME "std_2s60ES" ALT_CPU_NAME "cpu" ALT_CPU_ARCHITECTURE "altera_nios2" ALT_DEVICE_FAMILY "STRATIXII" ALTERA_NIOS_DEV_BOARD_STRATIX_2S60_ES ALT_STDIN "/dev/jtag_uart" ALT_STDOUT "/dev/jtag_uart" ALT_STDERR "/dev/jtag_uart" ALT_CPU_FREQ 50000000 ALT_IRQ_BASE NULL
IL2206 Embedded Systems 45

Example of a system.h file


/* * processor configuration * */ #define NIOS2_CPU_IMPLEMENTATION "fast" #define NIOS2_ICACHE_SIZE 4096 #define NIOS2_DCACHE_SIZE 2048 #define NIOS2_ICACHE_LINE_SIZE 32 #define NIOS2_ICACHE_LINE_SIZE_LOG2 5 #define NIOS2_DCACHE_LINE_SIZE 4 #define NIOS2_DCACHE_LINE_SIZE_LOG2 2 #define NIOS2_FLUSHDA_SUPPORTED #define NIOS2_EXCEPTION_ADDR 0x01000020 #define NIOS2_RESET_ADDR 0x00000000 #define NIOS2_HAS_DEBUG_STUB #define NIOS2_CPU_ID_SIZE 1 #define NIOS2_CPU_ID_VALUE 0
IL2206 Embedded Systems 46

Example of a system.h file


/* * uart1 configuration * */ #define #define #define #define #define #define #define #define #define #define #define #define #define #define UART1_NAME "/dev/uart1" UART1_TYPE "altera_avalon_uart" UART1_BASE 0x02120840 UART1_IRQ 4 UART1_BAUD 115200 UART1_DATA_BITS 8 UART1_FIXED_BAUD 1 UART1_PARITY 'N' UART1_STOP_BITS 1 UART1_USE_CTS_RTS 0 UART1_USE_EOP_REGISTER 0 UART1_SIM_TRUE_BAUD 0 UART1_SIM_CHAR_STREAM "" UART1_FREQ 50000000
IL2206 Embedded Systems 47

Example of a system.h file


/* * button_pio configuration * */ #define #define #define #define #define #define #define #define #define #define #define #define #define BUTTON_PIO_NAME "/dev/button_pio" BUTTON_PIO_TYPE "altera_avalon_pio" BUTTON_PIO_BASE 0x02120860 BUTTON_PIO_IRQ 2 BUTTON_PIO_HAS_TRI 0 BUTTON_PIO_HAS_OUT 0 BUTTON_PIO_HAS_IN 1 BUTTON_PIO_CAPTURE 1 BUTTON_PIO_EDGE_TYPE "ANY" BUTTON_PIO_IRQ_TYPE "EDGE" BUTTON_PIO_DO_TEST_BENCH_WIRING 1 BUTTON_PIO_DRIVEN_SIM_VALUE 0x000F BUTTON_PIO_FREQ 50000000
IL2206 Embedded Systems 48

Example: Using the HAL


!

The Parallel I/O devices can be accessed by functions that are defined in altera_avalon_pio_regs. These functions use only symbolic addresses!

#include "system.h" #include "altera_avalon_pio_regs.h" int buttons_pressed(void) { return IORD_ALTERA_AVALON_PIO_DATA(BUTTON_PIO_BASE); } void show_number_on_leds(int x) { IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, x); }
IL2206 Embedded Systems 49

C-Programming Testing of Bits (revisited)


HAL functions used
while (current_char != \0) { IOWR_ALTERA_AVALON_PIO_DATA(SEND_BUF_BASE, current_char); while (IORD_ALTERA_AVALON_PIO_DATA(SEND_STATUS_BASE) & 0x20) != 0) ; } /* Mask needed, since other bits */ /* in status register may not be zero */

7 0x1000 0x1001

5 BF

0 Status Sender Sender Buffer

IL2206 Embedded Systems

50

Programming Interrupt
Foreground Program
Do something! Interrupt Event
!

Interrupt Handler
! ! ! ! !

Save Registers Handle Interrupt Restore Registers Restore PC Clear interrupt disable flag

Interrupt Vector
!

Branch to Interrupt Handler


IL2206 Embedded Systems 51

Registering an ISR with alt_irq_register()


The HAL registers this function pointer in a lookup table. When a specific IRQ occurs, the HAL looks up the IRQ in the lookup table and dispatches the registered ISR. ! The prototype for alt_irq_register() is:
!
int alt_irq_register (alt_u32 id, void* context, void (*isr)(void*, alt_u32));

Read the Altera documentation: Nios II Software Developers Handbook


IL2206 Embedded Systems 52

Registering an ISR with alt_irq_register()


!

The prototype has the following parameters: ! id is the hardware interrupt number for the device, as defined in system.h. Interrupt priority corresponds inversely to the IRQ number. Therefore, IRQ 0 represents the highest priority interrupt and IRQ 31 is the lowest. ! context is a pointer used to pass context-specific information to the ISR, and can point to any sort of ISR-specific information. The context value is opaque to the HAL; it is provided entirely for the benefit of the user-defined ISR ! isr is the function that is called in response to IRQ number id. The two input arguments provided to this function are the context pointer and id. Registering a null pointer for isr results in the interrupt being disabled ! If your ISR is successfully registered, the associated interrupt (as defined by id) is enabled on return from alt_irq_register()
IL2206 Embedded Systems 53

An ISR to service a Button PIO IRQ


#include "system.h" #include "altera_avalon_pio_regs.h" #include "alt_types.h" static void handle_button_interrupts(void* context, alt_u32 id) { /* cast the context pointer to an integer pointer. */ volatile int* edge_capture_ptr = (volatile int*) context; /* * Read the edge capture register on the button PIO. * Store value. */ *edge_capture_ptr = IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE); /* Write to the edge capture register to reset it. */ IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE, 0); /* reset interrupt capability for the Button PIO. */ IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf); }
IL2206 Embedded Systems 54

Registering the Button PIO ISR with the HAL


#include "sys/alt_irq.h" #include "system.h" ... /* Declare a global variable to hold the edge capture value. */ volatile int edge_capture; ... /* Register the interrupt handler. */ alt_irq_register(BUTTON_PIO_IRQ, (void*) &edge_capture, handle_button_interrupts);

IL2206 Embedded Systems

55

What happens?
!
1. 2.

Based on this code, the following execution flow is possible:


Button is pressed, generating an IRQ. The HAL exception handler is invoked and dispatches the handle_button_interrupts () ISR. handle_button_interrupts() services the interrupt and returns. Normal program operation continues with an updated value of edge_capture.
IL2206 Embedded Systems 56

3. 4.

Application Binary Interface


!

The Application Binary Interface describes


! ! !

How data is arranged in memory Behavior and structure of the stack Function calling conventions

The ABI is very important when C/C++ and Assembler interact


Reference: Nios II Processor Handbook, Chapter 7

IL2206 Embedded Systems

57

Representation of Data Types

IL2206 Embedded Systems

58

HAL Standard C Data Types


! !

To increase portability the following HAL standard data types are defined There is no defined size for C-data types in ANSI C
!

An int reflect usually the natural size of integers on the host machine (Kernighan and Ritchie, 1988)

IL2206 Embedded Systems

59

Minimizing Code Size


!

Minimize the design costs


!

have always the hardware implementation in mind


! !

an int requires 4 bytes, a char only 1 byte if only values between 0 and 10 are needed use a char (or even better the corresponding Altera type)

Think Hardware!
IL2206 Embedded Systems 60

Memory Alignment
!

Contents in memory are aligned as follows:


! !

! !

A function must be aligned to a minimum of 32-bit boundary. The minimum alignment of a data element is its natural size. A data element larger than 32-bits need only be aligned to a 32-bit boundary. Structures, unions, and strings must be aligned to a minimum of 32 bits. Bit-fields inside structures are always 32-bit aligned.
IL2206 Embedded Systems 61

Memory Alignment
0x00 0x04 0x08 0x0C 0x10 0x14
Byte Byte Short Short int int Byte Byte Short Short Byte

IL2206 Embedded Systems

62

Register Usage
!

The ABI defines how the C compiler uses registers. If C and Assembler shall work together the ABI must be followed:

IL2206 Embedded Systems

63

Register Usage
!

It is the responsibility of the calling function to save the following registers, the called function may freely use these registers without saving them on the stack:

IL2206 Embedded Systems

64

Register Usage
!

If the called function wants to use the following registers, it has to save them on the stack first

IL2206 Embedded Systems

65

Register Usage
!

There are many other important registers, like the stack pointer, and the return address

IL2206 Embedded Systems

66

Register Usage Stack


! ! !

The stack grows downwards (i.e. to lower addresses) The stack pointer points to the last used slot The frame pointer points usually to the same location as the stack pointer

IL2206 Embedded Systems

67

Writing an assembler function called from C


!

The following has to be written in an assembler function that is called from C


Save stack & framepointer on stack Save return address (r31) on stack Save callee-saved registers that are used in the function Save stack-space for temporary variable ... Move return value into return registers (r2 and r3) Restore callee-saved registers Restore return address (r31) Restore stack and frame pointer

This applies for functions with not more than four 32-bit arguments
IL2206 Embedded Systems 68

C and Assembler A small example (Main.c)


#include <stdio.h> extern int addSub(int, int, int); int main() { int mode, a, b, result; while(1 < 2) { printf("Enter Mode (0 = Sub, 1 = Plus): "); scanf("%d", &mode); printf("Enter two numbers: "); scanf("%d %d", &a, &b); result = addSub(mode, a, b); if(mode == 0) printf("The difference is %d\n", result); else printf("The sum is %d\n", result); } return 0; }
IL2206 Embedded Systems 69

Message to the Linker: External Function

C and Assembler A small example (AddSub.s)


.global addSub .text addSub:

addSub shall be visible outside this function


# # # # # # # # # # Parameter r2: Return Value r4: Mode r5: a r6: b if mode is 0 -> Plus result = a - b goto end of subroutine result = a + b return from subroutine

beq sub br Plus: add Back: ret


!

r4, r0, Plus r2, r5, r6 Back r2, r5, r6

Note: No need to save stack pointer or callee-saved registers (not used) or return address (leaf function, it does not call other functions)

IL2206 Embedded Systems

70

Summary
Good understanding of underlying hardware is critical for design of efficient software ! HAL library provides abstraction from hardware and allows fast adaptation to changes in hardware ! Application Binary Interface defines a standard for communication between C- and Assembler parts
!
IL2206 Embedded Systems 71

You might also like