Z-80으로 간단한 컴퓨터 만들기 7
5.4. 메모리 쓰기 시험
프로그램 수행시 메모리에 데이터가 잘 써지는지 확인하기 위한 시험을 수행하고, 그 결과를 확인한다. 프로그램은 앞에 작성한 것에서 레지스터 A에 있는 데이터를 메모리의 임의의 어드레스에 쓰도록 다음 한 출을 추가하여 작성한다.
LOOP IN A, (0) : 0번 입력장치에서 데이터를 가져와 reg A에 넣는다.
OUT (0), A : reg A의 데이터를 0번 출력장치로 출력한다.
LD (0010), A : reg A의 데이터를 메모리 어드레스 0010에 써 넣는다.
JP LOOP : LOOP 로 Jump. 무한 루프 수행
위의 프로그램을 Machine Language로 변환하면 다음과 같다.
LOOP IN A, (0) 0000 DB 00
OUT (0), A 0002 D3 00
LD (0010), A 0004 32 10 00
JP LOOP 0007 C3 00 00
000A
위의 프로그램을 5.3 절에 나타낸 절차에 따라 메모리에 입력하고 프로그램을 수행한다. 메모리 주소를 h’0010으로 했는데 실제 프로그램에서는 h’1000으로 입력한다. 이것은 Z80에서 LSB(Least Significant Byte)부터 입력을 받기 때문에 거꾸로 입력하는 것이다. 이제 BUSRQ 스위치를 on 시켜서 프로그램을 중단시키고 Address 스위치를 h’0010으로 만들어 메모리의 데이터를 확인하여 보자. 마지막으로 입력시킨 데이터 값과 같으면 메모리에 정상적으로 write한 것임을 확인할 수 있다. 메모리 주소를 바꾸어 가면서 여러번 시험을 수행하여 메모리에 데이터 써넣는 것이 정상적으로 수행되는지 확인하여 본다.
5.5. 응용 프로그램 시험
이제 응용프로그램을 작성하여 실행하여보자. 우리가 제작한 보드는 입출력장치가 아주 단순하기 때문에 응용프로그램이 아주 제한적이다. 그래서 여기서는 LED를 bit0부터 bit7까지 순차적으로 on/off 시키는 응용프로그램을 작성하여 본다. 그런데 단순히 LED를 on/off 시키는 프로그램을 작성하여 실행시키면 on/off하는 시간이 너무 빨라서 LED 8개가 모두 켜져 있는 것처럼 보일 것이다. 따라서 on/off 하는 시간 간격을 아주 느리게 하여야 한다. 그래서 시간을 지연시키기 위한 Delay subroutine을 만들고 subroutine을 call 하는 프로그램을 작성하여야 한다. 먼저 subroutine을 살펴보자.
DLY PUSH AF : 레지스터 A와 F의 데이터를 Stack으로 옮긴다.
PUSH BC : 레지스터 B와 C의 데이터를 Stack으로 옮긴다.
LD B, #ff : 레지스터 B에 h’ff를 넣는다.
DLY1 LD C, #ff : 레지스터 C에 h’ff를 넣는다.
DLY2 DEC C : 레지스터 C 값을 1 감소 시킨다.
JP NZ, DLY2 : Zero Flag가 0이 아니면 DLY2로 Jump 한다.
DEC B : 레지스터 B의 값을 1 감소시킨다.
JP NZ, DLY1 : Zero Flag가 0이 아니면 DLY1로 Jump 한다.
POP BC : Stack에 있는 레지스터 B,C의 값으로 B,C를 복원한다.
POP AF : Stack에 있는 레지스터 A,F의 값으로 A,F를 복원한다.
RET : 원래의 프로그램으로 돌아간다.
Stack에 데이터를 다시 가져 올 때는 Stack에 데이터를 옮긴 순서의 역순으로 가져 와야 한다. 위 프로그램을 Machine Language로 변환하면 다음과 같다. subroutine은 주소 h’00E8에 써 넣을 것이다.
DLY PUSH AF : 00E8 F5 ;11
PUSH BC : 00E9 C5 ;11
LD B, #ff : 00EA 06 FF ; 7
DLY1 LD C, #ff : 00EC 0E FF ; 7
DLY2 DEC C : 00EE 0D ; 4
JP NZ, DLY2 : 00EF C2 EE 00 ;10
DEC B : 00F2 05 ; 4
JP NZ, DLY1 : 00F3 C2 EC 00 ;10
POP BC : 00F6 C1 ;10
POP AF : 00F7 F1 ;10
RET : 00F8 C9 ;10
위 프로그램의 맨 뒤 칸에는 각각의 명령어를 수행하는데 필요한 클럭수를 표기하였다. 이를 기반으로 이 프로그램을 수행하는데 필요한 총 클럭수를 계산하여 보면
11+11+7+(7+(4+10)*256+4+10)*256+10+10+10=922939 이다. 따라서 0.5usec*922939≃0.46 이므로 약 0,46초의 지연이 발생한다.
메인 프로그램은 다음과 같다.
LD SP, #7FFF : Stack Pointer에 h’7FFF를 써 넣는다,
LD A, #01 : 레지스터 A에 h’01을 써 넣는다.
LOOP OUT (00), A : 레지스터 A 값을 출력한다.
CALL DLY : DLY Subroutine을 call 한다.
RLCA : 레지스터 A 값을 왼쪽으로 circular rotate 시킨다.
JP LOOP : LOOP로 Jump한다. 무한 루프
여기서 circular rotate는 레지스터 값을 한비트 왼쪽으로 shift 시키고 최상위 비트를 최하위 비트로 넣는 것을 의미한다. 위 프로그램을 Machine Language로 변환하면 다음과 같다.
LD SP, #7FFF : 0000 31 FF 7F
LD A, #01 : 0003 3E 01
LOOP OUT (00), A : 0005 D3 00
CALL DLY : 0007 CD E8 00
RLCA : 000A 07
JP LOOP : 000B C3 05 00
위 프로그램을 모두 입력하고 수행시키면 LED의 최하위 비트가 On되었다가 순차적으로 왼쪽 LED로 약 0.46초 간격으로 옮아가면서 점등되는 것을 확인할 수 있다. 위의 프로그램의 A번지 값을 h’0F로 변경하면 오른쪽으로 돌아가는 것을 확인할 수 있다. 그리고 이 프로그램에서 맨 처음에 있는 명령어는 SP에 h’7FFF를 써 넣는 것인데 이것은 우리가 갖고 있는 메모리의 맨 뒤 어드레스가 h’7FFF이기 때문에 h’7FFF로 써 넣은 것이고, 메모리가 있는 어드레스를 아무것이나 써 넣어도 된다. 그런데 SP는 Stack에 데이터가 저장(Push)될 때마다 1씩 감소 되고, 데이터를 가져올(Pop) 때마다 1씩 증가하기 때문에 프로그램 영역과는 멀리 띄어 놓는 것이 좋다.
이제 LED를 왼쪽 방향으로 순차적으로 켜지다가 다 켜지면 순차적으로 꺼지다가 최상위 비트만 남으면 다시 오른쪽으로 순차적으로 켜지고, 다 켜지면 오른쪽으로 순차적으로 꺼지는 것을 반복하는 프로그램을 작성하여 보자. 프로그램은 다음과 같다.
MAIN LD SP, #7FFF : Stack Pointer에 h’7FFF를 써 넣는다,
LD A, #01 : 레지스터 A에 h’01을 써넣는다.
LP1 OUT (00), A : 레지스터 A를 출력한다.
SLA A : 레지스터 A를 왼쪽으로 shift 한다.
ADD A, #01 : 레지스터 A에 1을 더한다.
CP #FF : 레지스터 A와 h’FF와 비교한다(A-h’FF)
JP Z LP2 : 같으면 LP2으로 Jump 한다.
CALL DLY : DLY subroutine을 호출한다.
JP LP1 : LP1으로 Jump 한다.
LP2 OUT (00), A : 레지스터 A를 출력한다.
SLA A : 레지스터 A를 왼쪽으로 shift 한다.
CP #80 : 레지스터 A와 h’80와 비교한다
JP Z LP3 : 같으면 LP3으로 Jump 한다.
CALL DLY : DLY subroutine을 호출한다.
JP LP2 : LP2으로 Jump 한다.
LP3 OUT (00), A : 레지스터 A를 출력한다.
SRA A : 레지스터 A를 왼쪽으로 shift 한다.
CP #FF : 레지스터 A와 h’FF와 비교한다
JP Z LP4 : 같으면 LP4으로 Jump 한다.
CALL DLY : DLY subroutine을 호출한다.
JP LP3 : LP3으로 Jump 한다.
LP4 OUT (00), A : 레지스터 A를 출력한다.
SRL A : 레지스터 A를 왼쪽으로 shift 한다.
CP #01 : 레지스터 A와 h’01와 비교한다
JP Z LP1 : 같으면 LP1으로 Jump 한다.
CALL DLY : DLY subroutine을 호출한다.
JP LP4 : LP4으로 Jump 한다.
위 프로그램을 Machine Language로 변환하면 다음과 같다.
MAIN LD SP, #7FFF : 0000 31 FF 7F
LD A, #01 : 0003 3E 01
LP1 OUT (00), A : 0005 D3 00
SLA A : 0007 CB 27
ADD A, #01 : 0009 C6 01
CP #FF : 000B FE FF
JP Z LP2 : 000D CA 16 00
CALL DLY : 0010 CD E8 00
JP LP1 : 0013 C3 05 00
LP2 OUT (00), A : 0016 D3 00
SLA A : 0018 CB 27
CP #80 : 001A FE 80
JP Z LP3 : 001B CA 24 00
CALL DLY : 001E CD E8 00
JP LP2 : 0021 C3 16 00
LP3 OUT (00), A : 0024 D3 00
SRA A : 0026 CB 2F
CP #FF : 0028 FE FF
JP Z LP4 : 002A CA 33 00
CALL DLY : 002D CD E8 00
JP LP3 : 0030 C3 24 00
LP4 OUT (00), A : 0033 D3 00
SRL A : 0035 CB 3F
CP #01 : 0038 FE 01
JP Z LP1 : 003S CA 05 00
CALL DLY : 003B CD E8 00
JP LP4 : 003E C3 33 00
댓글
댓글 쓰기