時計を表示してみよう

  • 投稿日:
  • by
  • カテゴリ:

Z80 MBC2には、RTCモジュールを装着できるので、折角だから、時計を表示してみたいと思います。

Z80 MBC2用のCP/MにはRTC.BASという、MBASIC用のサンプルがあるので、RTCからの読み込み方法を知ることができます。ポート1に132を書き込み、ポート0から、データを連続して読み込みます。

読み込まれる順序は、秒、分、時、日、月、年(00-99)、センサーの温度、になります。

RTC.BASは一回読み込んで、それを表示して終わりなので、そうではなく、時計として、時刻を刻み続けるプログラムを書いてみました。ボード上のUSERボタンが押されると終了します。せっかくなので、MBASICだけではなく、Turbo Pascalと、Z80のアセンブラでも書いてみました。

MBASICはBASCOMでコンパイルすることもできます。BASCOM RTCBAS,RTCBAS=RTCBASとしてやって、L80 RTCBAS,RTCBAS/N/EとするとRTCBAS.COMが得られます。

RTCBAS.BAS:

100 PRINT CHR$(12)
110 OUT 1,132
120 S=INP(0):M=INP(0):H=INP(0)
130 D=INP(0):N=INP(0):Y=INP(0)
140 T=INP(0)
150 Y=Y+2000
160 S$=STR$(S):S$=RIGHT$("00"+RIGHT$(S$,LEN(S$)-1),2)
170 M$=STR$(M):M$=RIGHT$("00"+RIGHT$(M$,LEN(M$)-1),2)
180 H$=STR$(H):H$=RIGHT$("00"+RIGHT$(H$,LEN(H$)-1),2)
190 D$=STR$(D):D$=RIGHT$("00"+RIGHT$(D$,LEN(D$)-1),2)
200 N$=STR$(N):N$=RIGHT$("00"+RIGHT$(N$,LEN(N$)-1),2)
210 Y$=STR$(Y):Y$=RIGHT$("0000"+RIGHT$(Y$,LEN(Y$)-1),4)
220 PRINT CHR$(&H1B);"[0;0H";Y$;"/";N$;"/";D$;" ";H$;":";M$;":";S$
230 PRINT T;"C"
240 OUT 1,128
250 IF INP(0)=1 THEN END
260 GOTO 110

文字列処理ならどんとこーい、と、言った感じで、時分秒を二桁に揃えたりするのは、すっきり書けています。BASICのこの文字列操作能力の高さは、かなり便利です。

意外なことに、BASCOMの吐き出すコードは、Turbo Pascalのものよりコンパクトで、わずか9 Recsと1KB程度に収まっています。ただ、コンパイルしてリンクと、2step必要なので、一発でバイナリが得られるTurbo Pascalの便利さは、抜群だと思います。

RTCPAS.PAS:

program rtc;

var y, m, d, hr, mn, sc, t, ps, pt :integer;
var sm, sd, sh, sn, ss :string[2];

procedure readRTC(var y, m, d, hr, mn, sc, t :integer);
begin
port[1] := 132; (* RTC to read *)
sc := port[0];
mn := port[0];
hr := port[0];
d := port[0];
m := port[0];
y := port[0] + 2000;
t := port[0];
end;

begin
ps := -1;
pt := -1;
sm := '00'; sd := '00'; sh := '00'; sn := '00'; ss := '00';
Write(chr(12)); (* Clear screen *)
while true do
begin
readRTC(y, m, d, hr, mn, sc, t);
if ((pt <> t) or (ps <> sc)) then
begin
sm[1]:=chr($30+(m div 10)); sm[2]:=chr($30+(m mod 10));
sd[1]:=chr($30+(d div 10)); sd[2]:=chr($30+(d mod 10));
sh[1]:=chr($30+(hr div 10)); sh[2]:=chr($30+(hr mod 10));
sn[1]:=chr($30+(mn div 10)); sn[2]:=chr($30+(mn mod 10));
ss[1]:=chr($30+(sc div 10)); ss[2]:=chr($30+(sc mod 10));
WriteLn(chr($1b),'[0;0H',y,'/',sm,'/',sd,' ',sh,':',sn,':',ss);
WriteLn(t,'C');
pt := t;
ps := sc;
(* Check USER key *)
port[1] := 128; (* USER key to read *)
if port[0] = 1 then exit;
end;
end
end.

Turbo Pascal 3なんて、いつ以来だろう、と思いますが、まあ、たっぷり30年近く触ってないと思います。しかし、Word Master互換のキーアサインのスクリーンエディタとコンパイラをまとめて提供しており、使い勝手の良さは抜群でした。特に、CP/Mのコンパイラは、コマンドラインが難解で、Makeなどのユーティリティもなく、SUBMITによるバッチでのコンパイル→リンクが多く用いられていたなど、いろいろ面倒でしたから、Turbo Pascalの便利さときたら! おまけに値段もお安め(29,800円(当時は消費税なし)とかだったと思う)だったので、これははやらないわけはなく、実際、かなりはやっていたと記憶しています。

PC-9801のMS-DOSにも提供されていましたし、その後4.0も提供されていました。

コンパイルは1-PASS(Pascalは言語仕様が1-Passを前提としている)でこれまた高速でした。ただし、吐き出されるコードはそれほど効率がいいわけでもなく、実際、この程度のコードでもライブラリ込みとはいえ71Recsと最大のサイズでした。9000byte超えてますから。

RTCMBC2.MAC:

        .Z80
ASEG
ORG 0100H
BIOS EQU 0005H

START:
JP MAIN
CLS: DB 12,'$'
MSG: DB 1BH,'[0;0H'
YEAR: DB '2000/'
MON: DB '00/'
DATE: DB '00 '
HOUR: DB '00:'
MIN: DB '00:'
SEC: DB '00',0DH,0AH,'$'
TEMP: DB ' C$'

RESET: DB '2000/00/00 00:00:00',0DH,0AH,'$'
RTEMP: DB ' C$'

PSEC: DB -1

CHKBTN:
LD A,128
OUT (1),A
IN A,(0)
RET

DIV10:
LD B,0
DIV10L0:
INC B
SUB 10
JP NC,DIV10L0
DEC B
ADD A,10
RET

RESTORE:
PUSH HL
PUSH DE
PUSH BC

LD DE, RESET
LD HL, YEAR
LD B,2
RSTL0:
LD A,(DE)
LD (HL),A
INC DE
INC HL
CP '$'
JP NZ,RSTL0
DJNZ RSTL0

POP BC
POP DE
POP HL
RET

U2STR:
CALL DIV10
ADD A,'0'
LD (HL),A
DEC HL
LD A,B
OR A
JP NZ,U2STR
RET

MAIN:
LD C,9
LD DE,CLS
CALL BIOS
LOOP0:
CALL CHKBTN
CP 1
RET Z

LD A,132
OUT (1),A

IN A,(0)
LD HL,PSEC ; check if sec is updated.
CP (HL)
JP Z,LOOP0
LD (HL),A
LD HL,SEC+1
CALL U2STR

IN A,(0)
LD HL,MIN+1
CALL U2STR

IN A,(0)
LD HL,HOUR+1
CALL U2STR

IN A,(0)
LD HL,DATE+1
CALL U2STR

IN A,(0)
LD HL,MON+1
CALL U2STR

IN A,(0)
LD HL,YEAR+3
CALL U2STR

IN A,(0)
LD HL,TEMP+2
CALL U2STR

LD C,9
LD DE,MSG
CALL BIOS
LD C,9
LD DE,TEMP
CALL BIOS

JP LOOP0

END

ソースコードは長いですが、実行イメージは最小です。STAT.COMによれば、2Recs = 256バイトです。また、ボタンへの反応もいいですし、BDOSもCCPも破壊しないのでJP 0ではなくRETで復帰するので、復帰も迅速です。

ま、この程度の処理なら、高級言語の方が可読性も生産性も高いということなんでしょうけれど。