RAMが仲間になった!
東芝のSRAM、TC55257DPL-85Lです。これ1個で32kBあり、アクセスタイムも85nsとおそらく速い部類で、やはりZ80基準だと未来のデバイスなのでしょう。まぁ、気にせず組み込んでいきます。
ROMとRAMでチップが1個ずつだけあって、それぞれに32kBのアドレス空間を持たせたいので、アドレスデコードは単に最上位bitのA15を両者のCEに振り分ければよいですね。CEというのはチップイネーブル、あるいはCSでチップセレクトと呼ばれる信号で、メモリチップはこの信号がアクティブ(普通はLレベル)の時だけアクセスが可能です。
ROMのCE# = A15 | MREQ# RAMのCE# = !A15 | MREQ#
これでアドレスが0000H~7FFFH(A15が0)ならROM、8000H~FFFFH(A15が1)ならRAMへのアクセスとなります。MREQはZ80CPUがメモリアクセスを行うときにアクティブにする信号で、メモリがROM1個の時はこれとCEを直結するだけでOKでした。逆にメモリチップが多くなる場合、CPUから出るMREQとアドレスを元にどうやって各チップのCEを作り出すか(これをアドレスデコードと呼ぶ)がシステム設計の重要なポイントになるのだと思います。ここにさらに踏み込むと、Z80のアドレス空間を超える容量のメモリを扱ったり(バンク切り替え)、I/Oポートをメモリのアドレス空間にマッピングしたりなどが可能のようです。
プログラムは、RAMを無理やり使ってみる処理と、RAMがないと不可能な処理を試してみます。
PIOAD: equ 0 PIOAC: equ 1 RAM: equ 0x8000 STACK: equ 0xf000 org 0 ; ; CPU初期設定 ld sp,STACK ; ; PIO初期設定 ld a,0b11001111 ;ビットモード out PIOAC,a ld a,0b00001111 ;出力4bit/入力4bit out PIOAC,a ; ; サブルーチンをRAMに転送 ld hl,_DELAY ; 転送元アドレス ld de,RAM ; 転送先アドレス ld bc,0xff ; 転送サイズ ldir ; ; Lチカ速度設定(入力ポートから読み込む) SPEED: equ RAM + 0x100 in a,PIOAD sla a sla a sla a sla a or 0b00001111 ld (SPEED),a ld a,0 ; ; LEDチカチカ本体 BLINK: out PIOAD,a inc a call DELAY jp BLINK ; ; 遅延サブルーチン(RAMに置く) DELAY: equ RAM _DELAY: push af ld a,(SPEED) ld b,a _LOOP: djnz _LOOP pop af ret
ちょっと長くなってきました。やってることは変わらずLチカです。
- RAMを無理やり使ってみる処理
- 点滅を遅延させる処理をRAM領域にコピーし、そこで実行されるようにした
- RAMがないと不可能な処理
- サブルーチン(スタックが使えないとリターンができない。また、コール元のレジスタ退避にもスタックを使う。スタックは当然、RAMが必要)
- メモリへのデータ保存(起動時にPIO入力ポートの信号を読み、点滅速度設定としてRAM領域に保存)
アセンブルして、ROMに焼いて、電源投入。無事にチカチカしていますが、果たして想定通りの動作になっているのでしょうか。また実行速度を調べて確認してみます。
; ; LEDチカチカ本体 0027: D300 [11] BLINK: out PIOAD,a 0029: 3C [15] inc a 002A: CD0080 [32] call DELAY 002D: C32700 [42] jp BLINK ; ; 遅延サブルーチン(RAMに置く) 8000: DELAY: equ RAM 0030: F5 [11] _DELAY: push af 0031: 3A0081 [24] ld a,(SPEED) 0034: 47 [28] ld b,a 0035: 10FE [ 8|13] _LOOP: djnz _LOOP 0037: F1 [18] pop af 0038: C9 [28] ret
djnz
がちょっとややこしいですね。これはBレジスタをデクリメントして0なら次の行(8クロック)、0以外なら相対ジャンプ(13クロック)という命令です。(SPEED)に保存されている設定値を 0xff だとすると、DELAYサブルーチン1回のコールは 28+13*254+8+20=3358クロック。明滅1回が (42+3358)*256=870400クロック。1クロック=250nsから秒に直して逆数を取ると秒間約4.6チカの点滅です。プログラムが正しく動いていれば、この速度でLチカしてるはず。
お見事!
楽しすぎますね、これ。
もちろんプログラムは1発動作なんてことはなく、ROMが10回くらいライタとボードを往復しました。RAMが加わって本格的にコンピューターっぽいものが出来上がってきたので、ソフトウェアの開発環境をどうするかという問題が浮上してきたように思います。ブートローダーを作ってトライ&エラーの時間を短縮するか、もう割り切ってエミュレーターで動作確認してしまうか…悩みどころです。