8051( 중급 4부 - define ) |
어셈블리에서는 EQU라는 pseudo command가 있다.
그와 비슷한 기능을 하는 것이 C 언어에서는 define이다.
4부에서도 실제 target 보드에 직접 시험을 하는것은 아니고 컴파일만 해서 그 결과를 살펴 보기로 한다.
다음 프로그램을 보자.
#include |
위 프로그램에서 특이한 부분은 write_byte_io(), read_byte_io(), write_io(), read_io() 이다.
이 부분을 알기 위해서는 컴파일시 include되는 io320.h 화일을 볼 필요가 있다.
io320.h에 정의된 내용 #define write_io( address, value ) ((( char *)0x010000 )[ address ] = value ) #define read_io( address ) ((( char *)0x010000 )[ address ] ) #define read_code( address ) ((( char *)0x020000 )[ address ] ) |
위의 내용은 define 함수라고 한다. 즉 실제 C 함수는 아니고 어셈블러에서의 macro 기능과 유사한것이다.
이와 같이 간단한 기능을 갖는 함수를 사용할 경우 define 함수를 이용하면 일반 함수 사용보다 훨씬 코드도 줄어 들고 powerful한 기능을 수행할수 있다.
여기에서 ICC8051 컴파일러에 정해진 부분을 유념해야 한다.
즉 code를 다룰때는 0x02 segment를,
xdata를 다룰때는 0x01 segment를,
R0를 이용한 인덱스 i/o를 다룰때는 0x03 segment를 사용
토록 정해져 있다.
8 bit CPU에서는 2 byte의 address( 0x0000 ~ 0xFFFF )로 표현이 되기 때문에 어셈블러상에서는 segment, offset 개념이 필요치 않으며
16 bit CPU에서는 64 Kbytes의 offset과 상위 1 byte를 표현하는 segment 개념을 필요로 한다.
일례로 들면 8086 CPU에서 segment = 0x1000, offset = 0xFF00 이라 한다면 실제적인 address는 0x10FF00이 된다.
하지만 8051 CPU는 8 bit CPU 이므로 segment 개념을 MOVC, MOVX 명령을 활용하는 방법으로 사용이 된다.
그래서 MOVC 명령( code memory를 읽어 들이는 명령 )에서의 segment는 0x02이며
DPTR을 사용하는 MOVX 명령에서는 0x01 segment를, R0를 사용하는 MOVX 명령에서는 0x03 segment를 사용하도록 되어 있다.
위의 프로그램을 컴파일 해 보자.
#################################################################################################### # # # Micro Series 8051 C-Compiler V4.20C/DXT 22/Mar/102 08:05:11 # # # # Memory model = tiny # # Source file = pdata.c # # List file = pdata.lst # # Object file = pdata.r03 # # ASM file = pdata.s03 # # Command line = -mt -L -q -P -a PDATA PDATA # # # # (c) Copyright IAR Systems 1991 # #################################################################################################### \ 0000 NAME pdata(16) \ 0000 RSEG CODE(0) \ 0000 PUBLIC main \ 0000 $DEFFN main(1,0,0,0,0,0,0,0) \ 0000 EXTERN ?CL8051T_4_20_L17 \ 0000 RSEG CODE 1 #include |
위의 경우는 외부 I/O나 code memory를 사용키 위한 define 함수이다.
그러면 일반적으로 사용자가 만들어서 쓰는 define 함수를 보기로 하자.
#include |
위의 COM1_ready() 라는 define 함수와 COM1_rdy() 라는 사용자 함수는 100% 동일한 기능이다.
다음은 컴파일 결과 이다.
6 char COM1_rdy( void ) { \ 0000 COM1_rdy: 7 if( Tail == Head ) return -1; \ 0000 E503 MOV A,Tail+1 \ 0002 6501 XRL A,Head+1 \ 0004 7004 JNZ ?0006 \ 0006 E502 MOV A,Tail \ 0008 6500 XRL A,Head \ 000A ?0006: \ 000A 7003 JNZ ?0001 \ 000C ?0000: \ 000C 7FFF MOV R7,#255 8 else return 0; \ 000E 22 RET \ 000F ?0001: \ 000F 7F00 MOV R7,#0 9 } \ 0011 ?0002: \ 0011 22 RET 10 void main( void ) { \ 0012 main: 11 COM1_ready(); \ 0012 E503 MOV A,Tail+1 \ 0014 6501 XRL A,Head+1 \ 0016 7004 JNZ ?0007 \ 0018 E502 MOV A,Tail \ 001A 6500 XRL A,Head \ 001C ?0007: \ 001C 7004 JNZ ?0004 \ 001E ?0003: \ 001E 7F00 MOV R7,#0 \ 0020 8002 SJMP ?0005 \ 0022 ?0004: \ 0022 7FFF MOV R7,#255 \ 0024 ?0005: 12 COM1_rdy(); \ 0024 120000 LCALL $REFFN COM1_rdy 13 } |
사용자 함수와 define 함수의 컴파일 결과 차이점은 define 함수쪽에는 LCALL 과 RET 명령이 불필요하다는 점이다.
그래서 stack 도 사용이 되지 않게 된다.
큰 차이점이 없다 하더라도 자주 조회하는 함수 인 경우라면 define 함수쪽이 스피드 면에서유리한건 사실이다.
매번 호출하는 곳마다 어셈블리의 MACRO 기능처럼 나열이 되기 때문에 CODE가 커지게 된다.
'Programming > 8051' 카테고리의 다른 글
8051( 중급 6부 - RS485 ) (0) | 2009.11.29 |
---|---|
8051( 중급 5부 - pre-processor ) (0) | 2009.11.29 |
8051( 중급 3부 - 함수 ) (0) | 2009.11.29 |
8051( 중급 2부 - C 프로그램 맛보기 ) (0) | 2009.11.29 |
8051( 중급 - 1부 ) (0) | 2009.11.28 |