본문 바로가기

Hacked Brain/embeddedland.net

2. 196을 배워보자

2. 196을 배워보자

http://www.roboblock.co.kr


I. 196의 내부 구조

1. 196의 특징

20MHz operation

RALU

488 byte internal RAM

28개 interrupt source, 16개 interrupt vector

1.4us의 16bit X 16bit multiplication (at 20MHz)

Power down mode, Idle mode

16bit watchdog timer

full duplex serial port

동적 구조의 8bit/16bit external BUS width

Capture 기능이 있는 16bit up/down counter

8/10bit ADC with Sample/Hold

232 byte register file

Register-Register Architecture

PTS(Peripheral Transaction Server)

HOLD/HOLDA protocol

5개의 8bit I/O port

3 PWM output

네 개의 16bit software timer

2. 196 내부 구조

(1) 196KC의 memory 구조

196KC의 memory map을 살펴보면 다음과 같다.

   

external Memory/IO

FFFFH ~ 4000H

 

internal ROM/EP-ROM or external ROM

3FFFH ~ 2080H

 

reserved

   

상위 8개의 interrupt vector table

203FH ~ 2030H

 

EP-ROM security key

202FH ~ 2020H

 

reserved

   

CCB(Chip Configuration Byte)

2018H

 

reserved

   

하위 8개의 interrupt vector table

2013H ~ 2000H

 

port 3, 4

1FFFH

1FFEH

Address/Data BUS

external memory 또는 IO

1FFDH ~ 0200H

 

internal data memory, register file(SP, RAM, SFR, external program code memory)

01FFH

~

0000H

80C196KC internal RAM & SFR

  

여기에서 내부 RAM 중 Register file에 대해 간단히 알아보자.

내부 RAM의 memory map

   

상위 RAM

01FFH ~ 0100H

window를 이용하여 직접 번지 지정으로 data access

Register File

00FFH ~ 001AH

direct, indirect, index addressing 등을 이용하여 data access

SP(Stack Pointer)

0019H ~ 0018H

Stack Pointer로 사용

SFR(Special Function Register)

0017H ~ 0000H

I/O 및 다른 주변 기능을 제어

  


1) Register File

80196은 Register File을 base로 하여 연산을 하는 Register to Register Architecture로 되어있다. register file은 232byte의 내부 RAM(18H~0FFH)을 모두 register로 사용할 수 있으며, 196KC에는 256byte의 추가 RAM을 가지고 있어서 수직 window를 이용하여 사용할 수 있다.

18H~0FFH의 영역을 register file이라고 부르는데, 이 영역은 byte(8bit), word(16bit), long word(32bit)로 access할 수 있다. 이 register file은 RALU(Register/Arithmetic Logic Unit)가 사용하므로 232개의 Accumulator가 있는 것과 같은 효과를 낸다. 즉, 특정 Accumulator를 이용하여 연산을 할 필요가 없으므로 프로그램에 유용하다.

한편, 상위 RAM은 SFR의 window를 이용하여 0100H~01FFH의 256byte의 RAM을 register file로 mapping 시켜서 RALU에서 사용할 수 있다.

2) Stack Pointer

이 곳은 16bit Stack Pointer로 사용되는 부분이다. 사용자가 초기 설정하여 사용한다.

3) SFR(Special Function Registers) & 수평 window

196의 IO를 제어하기 위한 Register이다.SFR을 알아야만 controller에서 IO를 마음대로 휘어잡을 수 있다.

또 196에서는 수평 window를 이용하여 다른 기능의 SFR을 선택할 수가 있다. 아래의 표는 196의 SFR이다.

   

address

수평 window 0

Read

수평 window 0

Write

수평 window 1

Read/Write

수평 window 15

Read

수평 window 15

Write

17H

IOS2

PWMO_CONTROL

PWM2_CONTROL

PWM0_CONTROL

IOS2

16H

IOS1

IOC1

PWM1_CONTROL

IOC1

IOS1

15H

IOS0

IOC0

reserved

IOC0

IOS0

14H

WSR

WSR

WSR

WSR

WSR

13H

INT_MASK1

INT_MASK1

INT_MASK1

INT_MASK1

INT_MASK1

12H

INT_PEND1

INT_PEND1

INT_PEND1

INT_PEND1

INT_PEND1

11H

SP_STAT

SP_CON

reserved

SP_CON

SP_STAT

10H

PORT2

PORT2

reserved

reserved

reserved

0FH

PORT1

PORT1

reserved

reserved

reserved

0EH

PORT0

BAUD_RATE

reserved

reserved

reserved

0DH

TIMER2(HI)

TIMER2(HI)

reserved

T2CAPTURE(HI)

T2CAPTURE(HI)

0CH

TIMER2(LO)

TIMER1(LO)

IOC3

T2CAPTURE(LO)

T2CAPTURE(LO)

0BH

TIMER1(HI)

IOC2

reserved

IOC2

TIMER1(HI)

0AH

TIMER1(LO)

WATCHDOG

reserved

WATCHDOG

TIMER1(LO)

09H

INT_PEND

INT_PEND

INT_PEND

INT_PEND

INT_PEND

08H

INT_MASK

INT_MASK

INT_MASK

INT_MASK

INT_MASK

07H

SBUF(Rx)

SBUF(Tx)

PTSSRV(HI)

SBUF(Tx)

SBUF(Rx)

06H

HSI_STATUS

HSO_COMMAND

PTSSRV(LO)

HSO_COMMAND

HSI_STATUS

05H

HSI_TIME(HI)

HSO_TIME(HI)

PTSSEL(HI)

HSO_TIME(HI)

HSI_TIME(HI)

04H

HSI_TIME(LO)

HSO_TIME(LO)

PTSSEL(LO)

HSO_TIME(LO)

HSI_TIME(LO)

03H

AD_RESULT(HI)

HSI_MODE

AD_TIME

HSI_MODE

AD_RESULT(HI)

02H

AD_RESULT(LO)

AD_COMMAND

reserved

AD_COMMAND

AD_RESULT(LO)

01H

ZERO_REG(HI)

ZERO_REG(HI)

ZERO_REG(HI)

ZERO_REG(HI)

ZERO_REG(HI)

00H

ZERO_REG(LO)

ZERO_REG(LO)

ZERO_REG(LO)

ZERO_REG(LO)

ZERO_REG(LO)

  

* WSR (Window Select Register)을 이용해서 수평 window를 선택하는 경우

   

7

6

5

4

3

2

1

0

function

X

0

0

0

0

0

0

0

수평 window 0

X

0

0

0

0

0

0

1

수평 window 1

X

0

0

0

1

1

1

1

수평 window 15

  

위의 SFR들을 보면 같은 address에 서로 다른 기능의 Register가 mapping 되어 있는데, 이는 96 계열 controller의 이전 버전과의 호환성 때문에 추가되면서 발생한 것이다. 따라서 특정 register를 선택하기 위해서 WSR을 이용하여 window를 선택하고 register에 access하는 것이다. 또 읽고 쓰는 경우에 따라서도 access되는 address가 달라지므로 주의해야 한다. 이는 고급 사용자에게 매우 중요하다. 자칫하면 실수를 찾을 수 없기 때문이다.

(2) RALU

보통 많은 register가 없는 CPU에서는 연산을 위해서 memory로부터 Accumulator로 data를 가져와야 한다. 그러나 196에서는 변수가 내부 RAM(register)에 있을 경우에는 그럴 필요가 없다. 즉, register가 accumulator의 역할을 한다.

예를 들어 덧셈을 하는 경우 보통의 CPU에서는

MOV AX, 40H

MOV BX, 50H

ADD AX, BX

MOV 40H, AX

라고 해야하지만, 196KC에서는

ADD 40H, 50H

라는 한 줄로 끝나게 된다. (40H와 50H가 내부 변수라면)

또한 196은 덧셈과 뺄셈, 곱셈, 논리 연산 명령에 세 개의 operand가 있기 때문에, 예를 들어 60H=40H-50H(40H의 내용에서 50H의 내용을 뺀 후 60H에 그 내용을 저장한다.)의 경우

SUB 60H, 40H, 50H

로 한 줄에 끝낼 수가 있다. 이 때문에 같은 속도의 다른 CPU보다 연산속도가 두 세배 빨라지고 memory 효율은 10~30%정도 좋아질 수 있다.

II. 196 Assember

II-I. Assembler를 시작하기 전에

1. Assembler 기초

어셈블리어는 기본적으로 mnemonic + operand로 한 명령이 구성된다. 예를 들면 다음과 같다.

START: ADD AX, #40H

label mnemonic operands (AX는 variable)

mnemonic이란 명령의 종류를 말하는 것이고, operand란 명령 실행의 대상이 된다. 이렇게 만들어진 한 명령 단위는 Assembler에 의해서 OP code로 변환되어 object file이 만들어진다. 이는 다시 ROM이나 RAM에 들어갈 수 있는 실행 가능한 code(기계어)로 변환되어 실행되게 된다.

operand는 mnemonic에 따라 달라진다. 두 개인 것도 있고, 한 개인 것도 있고, 없는 것도 있다. 또한 이들은 CPU마다 다르다. 그러나 그 기본적인 구조는 비슷하기 때문에 한 종류의 어셈블리어를 알고 있다면 다른 어셈블리어를 배우기는 그리 어렵지 않다.

Programming할 때 Assembler를 반드시 쓰라는 법은 없다. C를 써도 되고 C++을 써도 상관없다. 그러나 Hardware에 접근하기 위해서는 Assembler는 필수이고, 이를 알아야만 hardware를 효율적으로 사용할 수 있고, 최적의 code를 만들 수가 있다. 그러므로 속도를 위한 hardware라면 C보다는 assembler가 더 좋을 것이다.

한편 같은 CPU라도 여러 종류의 assembler가 있을 수 있다. 물론 대부분은 비슷하나 약간씩 다른 점도 있으므로 자신이 어떤 assembler를 사용하는지 알고 사용해야 한다. 예를 들어 8x86계열이라면 MASM(Macro Assembler)이 유명할 것이다.

이후부터는 intel에서 제공하는 asm96을 이용하여 어셈블리어 프로그램 개발과정에 살펴보겠다. (196 assembler는 http://www.postech.ac.kr/downarea/asm/ic96.zip 에서 가져가기 바람.) 아래 그림은 program의 개발 과정이다. source program은 어셈블리어에 의해서 만들어지고 이는 어셈블러에 의해 Assemble된다. 여기서 list file을 얻을 수 있다. 여기에서 만들어진 object file은 oh나 hex2bin등을 통해서 hex file이나 bin file등의 code로 만들어진다.

                                       

2. 196 Assembler

우선 일반적인 사항들에 대해서 살펴보자.

(1) 이름(Label, varible,...)으로 사용할 수 있는 문자

모든 ASCII 문자는 사용 가능하고, 대소문자의 구분은 없다. 그러나 이름에서 첫 번째 문자로는 0~9의 숫자를 사용할 수 없고 다음 문자는 제한 없다. 길이는 최대 31문자이다.

(2) 숫자 표기

   

진수

추가 사항

example

2 (binary)

B (b)

11000011B

8 (oxta)

O, Q (o, q)

145O

10 (decimal)

D, d 혹은 없어도 됨

95

16 (hexa)

H, h

9FH, 0F0H

  

16진수의 경우 lable이나 이름과 숫자를 구별하기 위해서 처음에 A~F로 시작하는 경우에는 앞에 0을 하나 더 써준다.

(3) 문장

위에서 설명한 것과 같다.

LOOP: ORB TEMP, #'A' ; Temp에 'A'의 ASCII 값 더함

lable mnemoic operands comment

(4) Lable, Variable, Number

1) Lable

Lable은 jump나 call할 때의 subroutime 혹은 address의 이름이며 위에서처럼 뒤에 ':'을 붙인다. 그렇지 않으면 assembler는 lable을 구별할 수 없다.

2) Variable

실제 값의 위치를 나타내기 위해 사용한다.

예) TEMP: DCB 155

TEMP1: DSB 15

(C에서의 변수 선언과 같음 - int temp;)

3) Number

숫자로서 EQU(Equate)나 SET을 사용하여 정의하고 쓴다.

예) RADIUS EQU 450

(C에서 define과 같음)

(5) Asm96 지시어

   

지시어

function

example

Module level을 정의하는 지시어

MODULE

module에 대한 정보 제공

ABC MODULE STACKSIZE(100)

PUBLIC

public symbol을 정의

ACC

EXTRN

외부 참조 symbol을 정의

ACD

END

end of program

END

Location counter를 정의하는 지시어

CSEG

code segment 정의

CSEG AT 2080H

DSEG

data segment 정의

DSEG AT 8000H

RSEG

overay되지 않는 register segment 정의

RSEG AT 0020H

OSEG

overay되는 register segment 정의

OSEG AT 0100H

ORG

시작 address를 정의(Origin)

ORG 8200H

Symbol을 정의하는 지시어

EQU

symbol 정의 (재정의가 불가능)(Equate)

ESC EQU 0

SET

symbol 정의 (재정의가 가능)

BEEP SET 0모

Code를 정의하는 지시어

DCB

변수를 byte로 정의(Define Code in Byte)

DCB 33H, 'HI'

DCW

변수를 word로 정의(Define Code in Word)

DCW 4444H

DCL

변수를 long word로 정의(Define Code in Long word)

DCL 12345678H

DCR

변수를 실수로 정의(Define Code in real)

DCR 3.14159

조건 어셈블리 지시어

IF

조건 어셈블리 블럭 시작

 

ELSE0

조건 어셈블리 블럭을 대체

 

ENDIF

조건 어셈블리 끝

 

  

196 어셈블러는 명령(mnemonic)의 기능에 따라 몇몇 명령군으로 나누어 볼 수가 있다. 이에 따라 나누어 보면 다음과 같다.

데이터 전송 명령

산술 연산 명령

논리 연산 및 shift 명령

branch 명령

Stack과 subroutine 및 system 제어 명령

또 Bit, Byte, Word, Long word에 따라 명령도 약간씩 달라지므로 주의해야 한다.

다음 시간부터는 이 순서에 따라 어셈블리어를 배우도록 하자.

다음은 예제이니 읽어보고 위에서 배운 것들을 참고하여 분석해보자.

(앞쪽 생략)

north equ 40h ; 방향정보

west equ 0

east equ 80h

south equ 0c0h

CSEG AT 8004H ; AD interrupt

ljmp AD_SERVICE

CSEG AT 800CH ; HSO interrupt

ljmp HSO_SERVICE

CSEG AT 8014H ; Software timer interrupt

ljmp SOFT_TIMER

;CSEG AT 801CH ; extint

; LJMP EXTI_SERVICE

CSEG AT 8030H ; Timer2 overflow interrupt

ljmp timer2_service

CSEG AT 8200H

START: LDB IOC0, #00000000B ; all hsi unit is disable, select P2.3, P2.5

LDB IOC1, #01111010B ; HSO4, HSO5 enable, select ACH7 as exint1 input,

; timer2 overflow interrupt enable

LDB IOC2, #10010100B ; Fast mode AD enable, timer2 normal increasing mode

LDB WSR, #1

LDB IOC3, #000000001B ; timer2 clock source internal

CLRB WSR

CLRB IOPORT1 ; port initialize

CLRB IOPORT2

ldb ax, #0ffh ; 벽 정보 초기화

clrb ch

clrdl: stb ch, data_location[ax]

djnzw ax, clrdl

EI

restart: ldb current_dir, #north ; set direction (forward, absolute)

ldb current_xy, #0 ; set current coordinate (x, y = 0, 0)

ldb target_xy, #44h ; set destination