SBC68系バスへSBC80系ボードをつなぐ

6502SBC68系バスへSBC80系ボードをつなぐ

先日作成した6502CPUマイコンですが、SBC6303ルーズキットSBC6800 Adapterと同じSBC68系バスを装備してみました。
KZ80シリーズで使っているSBC80系バスへ変換するボードがあると、外部駆動できるボードの幅が広がりそう。

SBC68系バスとSBC80系バスの違い

SBC68系バスは以下のようなピン配置となっています。KZ80などのSBC80系バスとピン数はいっしょですが、電源の位置や制御信号が違っています。

SBC6303ルーズキット技術資料

SBC6800 AdapterだとP10〜P17端子のあたりにCPUボードの74138でデコードしたアドレス信号線が出ていたりしますので若干違います。

信号線の変換回路

KZ80用外部ボードではZ80のI/Oアドレス($00〜$FF)をデコードする仕組みはありますが、SBC68系ではメモリーマップドI/OですのでアドレスバスA15〜A8をデコードする追加してあげる必要があります。また、リセット端子もSBC68系バスでは負論理、SBC80系バスでは正論理で反転する必要があります。

アドレスバスA15〜A13のデコードは74HCT138に任せまして、#RD/#WR信号とあわせて74HC139で#IOR/#IOW信号を生成しました。
74HC139の余った部分で#RESET信号をRES信号へ反転させるようにしました。CLK端子にはE(φ2)信号を入れてみました。

KZ80-IOB(I/Oボード)の8255はNG

以前 アドレスデコーダ74HC139に#IOREQを入れて試したときもNGだったのですが、I/Oボード(KZ80-IOB)の8255をつないで試したところNGでした。

SBC68系バスからSBC8080バスへ変換するボード配線はしてみましたが、当然 うんともすんともいいませんでしたw うーむ。ロジアナで動きを探ってみます。 pic.twitter.com/JW5iBvB5D9— KUNI-NET元シソペ (@kuninet) April 29, 2020

実は上記のTweetをしたときには、#WRと#RDの配線が逆だったり、RESの配線端子がずれていたりとヘッポコな状態でした。配線を直してもNGでしたが…(X_X)

FM音源ボードで挑戦

続いて、以前SBC6303でも稼働実績があるFM音源LSI YM2151で試してみることにしました。Arduinoでも演奏できた事例もありますので、ちょっと期待して…

つないだだけでは音楽演奏はできませんので、以前作ったZ80SBC6303のVGMデータ演奏プログラムを見ながら移植します、どちらのプログラムも元は上記のArduino用VGM Playerです。

6502のニーモニックの資料を参照しながら作ったプログラムは以下になります。いつものThe Macroassembler ASでアセンブリできます。

`;
; YM2151 PLAY
;  Universal Minitor for 6502 & SBC68toSBC80 Adapter
;

	CPU	6502

TARGET:	EQU	"6502"

;
;;; Functions
low	function	x,(x & 255)
high	function	x,(x >> 8)
;
;
MUSIC       EQU     $1000
OPM_ADDR    EQU     $8040
OPM_DATA    EQU     $8041

;
        org $0200
MAIN:
        LDA     #low(MUSIC)
        STA     MUSIC_PTR
        LDA     #high(MUSIC)
        STA     MUSIC_PTR+1
LOOP:
        LDY     #0
        LDA     (MUSIC_PTR),Y
        CMP     #$54
        BEQ     PLAY
        CMP     #$61
        BEQ     WAIT1_S
        CMP     #$62
        BEQ     WAIT2_S
        CMP     #$63
        BEQ     WAIT3_S
        CMP     #$64
        BEQ     WAIT3_S
        CMP     #$66
        BEQ     END_RTN
;
        CMP     #$70
        BEQ     WAIT4_S
        JMP     CHK_WAIT_S
;
NEXT:
        JSR     ADD_PTR
        JMP     LOOP
;
END_RTN:
        BRK
;
; SUB ROUTINE JUMP
;
PLAY:
        JMP     PLAY_S
;
ADD_PTR:
        LDA     #1
        CLC
        ADC     MUSIC_PTR
        STA     MUSIC_PTR
        LDA     #0
        ADC     MUSIC_PTR+1
        STA     MUSIC_PTR+1
        RTS
WAIT1_S:
        INY
        LDA     (MUSIC_PTR),Y
        STA     WAIT_CNT
        INY
        LDA     (MUSIC_PTR),Y
        STA     WAIT_CNT+1
        JSR     WAIT
        JSR     ADD_PTR
        JSR     ADD_PTR
        JMP     NEXT
;
WAIT2_S:
        LDA     #low(735)
        STA     WAIT_CNT
        LDA     #high(735)
        STA     WAIT_CNT+1
        JSR     WAIT
        JMP     NEXT
;
WAIT3_S:
        LDA     #low(882)
        STA     WAIT_CNT
        LDA     #high(882)
        STA     WAIT_CNT+1
        JSR    WAIT
        JMP     NEXT
;
CHK_WAIT_S:
        CMP     #$80
        BCS     WAIT4_EXIT
WAIT4_S:
        AND     #$0F
        CLC
        ADC     #1
        STA     WAIT_CNT
        LDA     #0
        STA     WAIT_CNT+1
        JSR    WAIT
WAIT4_EXIT:
        JMP     NEXT
;
WAIT:
        JSR     WAIT_1MS
        SEC
        LDA     WAIT_CNT
        SBC     #1
        STA     WAIT_CNT
        LDA     WAIT_CNT+1
        SBC     #0
        STA     WAIT_CNT+1
;
        LDA     WAIT_CNT
        CMP     WAIT_CNT+1
        BNE     WAIT
WAIT_EXIT:
        RTS
WAIT_1MS:
        LDA     #$E0
        STA     WAIT_1MS_CNT
WAIT_1MS_LOOP:
        DEC     WAIT_1MS_CNT
        NOP
        NOP
        BNE     WAIT_1MS_LOOP
        RTS
;
;
PLAY_S:
        INY
        LDA     (MUSIC_PTR),Y
        STA     WK_ADDR
        INY
        LDA     (MUSIC_PTR),Y
        STA     WK_DATA
;
WRITE_OPM
        LDA     OPM_DATA
        CMP     #$80
        BEQ     WRITE_OPM
;
        LDA     WK_ADDR
        STA     OPM_ADDR
        NOP
        NOP        
        NOP
        NOP     
        LDA     WK_DATA
        STA     OPM_DATA
        JSR     ADD_PTR
        JSR     ADD_PTR
        JMP     NEXT
;
; Work Area
;
        org  $30
MUSIC_PTR RMB 2
WK_ADDR  RMB 1
WK_DATA  RMB 1
WAIT_CNT RMB 2
WAIT_1MS_CNT RMB 1
SUB_PTR  FDB    SUB_PTR_TBL
;
        END`

そんなに長いプログラムではないものの、6502CPUのニーモニックに慣れていないもので半日ぐらいウンウン言ってました。コーディングしてみて気がついた点としては…

  • アキュームレーターのインクリメント命令が無い
  • インデックスレジスタのインクリメント命令(INY)が255を超えてもキャリーフラグが立たない
  • 加算命令、減算命令にキャリー付きしかないので、加算前はキャリークリア、減算前はキャリーセットが吉
  • M6800 CPUも同じですが、条件分岐ジャンプが相対ジャンプなのですぐ127バイトの壁を超えて飛べなくなってしまう
  • やっぱり間接アドレス用に16bitレジスタが1つは欲しいw メモリーの16bitデータの加算命令があればなぁとか…

ボードの回路データや、上記のプログラム等はgithubにUPしました。

サンプル音楽を演奏、鳴った!!

KZ80-YM2151FM音源ボードのリポジトリにも添付しているサンプルVGMデータで鳴らしてみました。無事音楽が鳴りました!! やった〜。

6502マイコン+FM音源ボード KZ80-YM2151 いい感じで鳴りました。WAITルーチンで アキュームレータから -1するときにキャリーフラグの操作を間違えてました。引き算のときにはキャリーをセットしておくんですね。 pic.twitter.com/mzQI8WOZB1— KUNI-NET元シソペ (@kuninet) May 5, 2020

これで、SBC68系からSBC80系バスへの変換ボードの回路が良さげな感じということがわかりましたので、今後 他のKZ80シリーズとして作ったボードを接続してみたいと思います。