Posts Tagged with "Ultra96"

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.

6809の割込み動作

posted by sakurai on August 14, 2019 #148

メインCPUとサブCPUはお互いに割込みを掛け合います。メインCPUからは通常、サブCPUのbusyを確認し、readyであればサブCPUをHALTし、共有メモリにコマンドを書き込んだ後、HALTをネゲートします。サブCPUはすぐにbusyにした後、コマンドを解析し、処理を行います。

これが通常シーケンスですが、例えば時間のかかる処理をサブCPUがやっていた場合に中止させたい時には割込みをかけるしかありません。これをCANCEL割込みといいます。逆に、サブCPUからメインCPUに用事がある場合にはATTENTION割込みをかけます。

さて、メインCPUの割込みの一つにタイマー割込みがあり、これをシミュレーションしてみます。タイマー割り込みはIRQに接続されているため、IRQ割り込みハンドラをプログラムします。IRQは全レジスタのセーブリストアが自動で行われます。割り込みハンドラでは、まずタイマ割り込み要因のクリアを行った後、要因レジスタは負論理であるため、反転してメモリに書きだした後でRTIで元の命令列に戻ります。

1000         stack  equ   \$1000
2000         ustack equ   \$2000
FE00         start  org   \$fe00
           
FE00 10CE1000        lds   #stack
FE04 CE2000         ldu   #ustack
FE07 8EFD02         ldx   #\$FD02     ; IRQ Mask Reg
FE0A 86FF          lda   #\$FF      ; Timer IRQ unmask
FE0C A784          sta   ,X       ; Timer IRQ enabled
FE0E 20FE          bra   *
           
FE10         firq  equ *
FE10         irq   equ *
FE10 8EFD03         ldx   #\$FD03     ; IRQ event reg
FE13 A684          lda   ,X       ; IRQ clear
FE15 8AFB          ora   #\$FB
FE17 70FE17         eora   #\$FF
FE1A B73000         sta   \$3000
FE1D 3B           rti
           
FFF6             org   \$fff6
FFF6 FE10          fdb   firq
FFF8             org   \$fff8
FFF8 FE10          fdb   irq       ; Timer IRQ
FFFE             org   \$fffe
FFFE FE00          fdb   start
           
0000             end

まずリセット後にFD02をライトし、割込みマスクを許可します。'1'をライトすると許可となります。

図%%.1
図148.1 割込みイネーブルのタイミングチャート

次にタイマー割込みがかかるとスタックに全レジスタを退避します。PC, US, IY, IX, DP, B, A, CCの12バイトです。

図%%.2
図148.2 レジスタ退避のタイミングチャート

次に\$FFF8から2バイトをフェッチします。ところが、\$FFF8の示すアドレスにジャンプする前に再度全レジスタをスタックに退避しています。

図%%.3
図148.3 割込みベクタフェッチのタイミングチャート

割込みが入った場合、直ちに割込みマスクがかからなければ、無限に割込みが入るので、これはCPUのIRQマスクのバグと思われます。


左矢前のブログ 次のブログ右矢

posted by sakurai on August 9, 2019 #144

アドレスデコード及びレジスタ類を実装していきます。FM-7のI/Oの情報は参照場所にあります。メインシステムI/Oアドレスマップはその1から、サブシステムI/Oアドレスマップはその7からです。

メインシステム

FM-7メインシステムは64KbitDRAMが存在するため、フルデコードされています。

  • $FD00 R キーボードデータ bit8
  • $FD00 R キーボードデータ bit7-bit0
  • $FD02 W 割込み(IRQ)マスクレジスタ(タイマ、キーボード)
  • $FD03 R 割込み(IRQ)フラグレジスタ(タイマ、キーボード)
  • $FD04 R 割込み(FIRQ)フラグ (ブレーク、アテンション)
  • $FD05 R サブ状態 (busy)
  • $FD05 W サブ・Z80制御 (HALT, Cancel, Z80)
  • $FD37 W マルチページレジスタ (リセット時イネーブル)
  • $FD38 R パレットレジスタ0から読み出し(初期値=黒)
  • $FD38 W パレットレジスタ0へ書き込み
  • $FD39 R パレットレジスタ1から読み出し(初期値=青)
  • $FD39 W パレットレジスタ1へ書き込み
  • $FD3A R パレットレジスタ2から読み出し(初期値=赤)
  • $FD3A W パレットレジスタ2へ書き込み
  • $FD3B R パレットレジスタ3から読み出し(初期値=マゼンタ)
  • $FD3B W パレットレジスタ3へ書き込み
  • $FD3C R パレットレジスタ4から読み出し(初期値=緑)
  • $FD3C W パレットレジスタ4へ書き込み
  • $FD3D R パレットレジスタ5から読み出し(初期値=シアン)
  • $FD3D W パレットレジスタ5へ書き込み
  • $FD3E R パレットレジスタ6から読み出し(初期値=黄)
  • $FD3E W パレットレジスタ6へ書き込み
  • $FD3F R パレットレジスタ7から読み出し(初期値=白)
  • $FD3F W パレットレジスタ7へ書き込み

図144.1にメインシステムブロック図を示します。今回はアドレスデコーダとそれからアクセスされるレジスタを分離して設計しました。モジュラー化のためです。図では上方左側にアドレスデコーダ、上方右側にレジスタが配置されています。

図%%.1
図144.1 メインシステムブロック図

サブシステム

FM-7サブシステムはフルデコードされていません。

  • $D400 R キーボードデータ bit7-bit0
  • $D401 R キーボードデータ bit8
  • $D402 R キャンセルIRQ ACK
  • $D404 R メインCPUへのアテンションIRQ
  • $D408 R CRT ON
  • $D408 W CRT OFF
  • $D409 R VRAM Access Set
  • $D409 W VRAM Access Reset
  • $D40A R Ready
  • $D40A W Busy
  • $D40D R INS LED ON
  • $D40D W INS LED OFF
  • $D40E W VRAM Offset Address bit13-8
  • $D40F W VRAM Offset Address bit7-0

図144.2にサブシステムブロック図を示します。図では真ん中にアドレスデコーダとレジスタを階層ブロックにしたモジュールが配置され、その内部左側にアドレスデコーダ、右側にレジスタが配置されています。

図%%.2

図144.2 サブシステムブロック図

左矢前のブログ 次のブログ右矢

posted by sakurai on August 8, 2019 #143

もう少し詳しく見てみます。HALTREQがアサートされたのは、たまたま\$E021のblo命令の第1バイト\$25をフェッチした直後でした。図143.2に示すように、blo命令の\$25と\$F4のフェッチの間に入ったことになります。

図%%.1
図143.1 HALTREQアサート時バスサイクルと内部状態
図%%.2
図143.2 アセンブルリスト

HALTREQが"blo l2"命令の間であるため、すぐにはHALTステートに遷移せず、blo命令の第2バイトである\$E022の\$F4のフェッチが行われます。

図%%.3
図143.3 blo第2バイトフェッチ

前稿で新設したhalt_save_stateは、HALTに入る直前のステートを保存するようにしたため、HALTステートに入るまではサイクル毎に書き換えられています。

図%%.4
図143.4 ステートセーブレジスタ更新

分岐命令をデコードし分岐が実行された後に、アドレスが分岐先である\$E017に変化しています。分岐命令はPCを変更するだけであり、これで分岐命令の実行は完了です。

図%%.5
図143.5 分岐先アドレス出力

分岐命令フェッチの前で新設のHALTステート(\$40)に遷移し、次のサイクルでHALTACKがアサートされています。HALTステートに遷移したので、halt_save_stateは、HALTステートの前の値(\$09)を保持し、更新は止まります。

図%%.6
図143.6 HALTステートへの遷移

一方、HALTREQネゲート時の状態を観測すると、前稿でも見たように、内部ステートが回復され、分岐先である\$E017、\$E018の命令を順次フェッチしています。このように分岐先命令のフェッチが実行されており、命令の切れ目、具体的には分岐命令の実行後にHALTに入り、分岐命令の実行前にHALTから出る動作を正しく実行しているようです。

図%%.6
図143.7 HALTREQネゲート時バスサイクルと内部状態

左矢前のブログ 次のブログ右矢

posted by sakurai on August 6, 2019 #142

前稿のコードを追加し、シミュレーションしたところ、HALTをアサートしてもHALTステートへの遷移ができないことが判りました。前稿のコードのように、外部信号により内部フラグを立て、内部フラグが立っていたらすぐにstateをHALTステートに遷移させたのですが、別の要因によりstateが上書きされてしまうようです。

そこで、同種と思われるNMIのコードのように、HALTステート遷移を「NMIの内部フラグを見てNMIステートに遷移する場所」に移動したところ、正しく動作しました。シミュレーション結果を見ると、HALTがかかっても直ちにstateを遷移するのではなく、継続したバスサイクルを終了した命令の切れ目でHALTがかかっていることがわかります。

つまり、前稿のようにすぐにstate遷移させても上書きされてしまい、NMIのように命令の切れ目で判定して遷移させるのが正しいということです。

図%%.1
図142.1 HALTREQアサート時

HALTREQがアサートされてから、次のサイクルで内部フラグが立ちますが、数サイクル遅延した後にHALTステートに入っています。その後HALTACKが出力されます。

図%%.2
図142.2 HALTREQネゲート時

一方、HALTREQがネゲートされると、次のサイクルで内部フラグが落ち、次のサイクルでHALTACKが落ちると同時にHALTステートに入る前に保存されていたステートから再開します。こちらは遅延していません。


左矢前のブログ 次のブログ右矢

posted by sakurai on August 5, 2019 #141

さて、サブシステムの共有メモリを実装する際には、実機では図141.1のようにメインCPUがサブCPUをHALTさせてアクセスしています。前稿のように、共有メモリは128ByteとなっていてメインCPUとサブCPUの間に物理的な128Byteのメモリがあるように思えますが、実態はサブCPUの物理メモリ(MB8416, 2KB SRAM)の半分しか使用しておらず(\$D000~\$D3FFの1KB SRAMとして使用)、さらにそのうちのメインCPUから見える窓が128Byteであり、メインCPUが使用する際にはHALTをかけてサブCPUのバスを開放し、メインCPUがアクセスするという構造のようです。

図%%.1
図141.1 共有メモリ回路図

物理メモリのMB8416がシングルポートで同時にアクセス不可であるため、HALTによりバスを開放させています。FPGA実装では、デュアルポートRAMが可能なので同時アクセス可なのですが、同時にアクセスすると、サブCPUがコマンドを読み出し中に、メインCPUが書き換えてしまうという論理的なデータ競合の問題が起こります。従って、メインCPUとサブCPUの論理的な同期化のために、HALT信号が必要です。

ところが、図138.2をみてもわかるように、本IPの信号はLSIの6809と異り、HALT端子がありません。従って、HALTREQ、HALTACK端子を実装します。

IPの6809のソースを追うと、FSMの最初に割込み受信のコードが存在します。その辺に以下のような疑似コードを挿入します。HALTREQ信号をhaltreq変数に入れているのは、HALTREQ信号を見るのは一か所にしたかったためです。逆に複数個所でHALTREQ信号を見ると、状態の不一致が起きる可能性があります。

もしHALTREQ信号がHならば、
 haltreq変数をHにし、
 現stateがSEQ_HALTで無い場合にのみ、stateを戻りステートとして保存し、
 次のサイクルでSEQ_HALTに移行
そうでなければ
 haltreq変数をLにする

SEQ_HALT:
 もしhaltreq変数がHならば、
  HALTACKをHにし、
  次のサイクルでSEQ_HALTに移行
 そうでなければ、
  HALTACKをLにし、
  次のサイクルで戻りステートに移行

これをVerilogで記述すれば、

図%%.2
図141.2 Verilogコード

となります。


左矢前のブログ 次のブログ右矢

ROMからCOE

posted by sakurai on August 2, 2019 #140

ROMデータからCOEデータを作成するスクリプト。

#! /usr/bin/bash -f
FILE_NAME=\${1}
FILE=\${FILE_NAME%.*}
echo 'memory_initialization_radix=16;' > \$FILE.coe;
echo -n 'memory_initialization_vector=' >> \$FILE.coe;
od -An -t x1 -v \$FILE_NAME >>\$FILE.coe
echo ';' >> \$FILE.coe

これにより、

-rwxrwx--- 1 root vboxsf 1631 7月 25 16:56 boot_bas.coe
-rwxrwx--- 1 root vboxsf 1631 7月 25 16:57 boot_dos.coe
-rwxrwx--- 1 root vboxsf 97279 7月 25 16:57 fbasic30.coe
-rwxrwx--- 1 root vboxsf 31423 7月 25 16:59 subsys_c.coe

の4つのファイルを作成し、FPGAに組み込みます。


左矢前のブログ 次のブログ右矢

6809デュアルCPUシステム

posted by sakurai on August 1, 2019 #139

アドレス空間

6809デュアルCPUシステムの、メインCPU及びサブCPUのそれぞれのアドレス空間を示します。

図%%.1
図139.1 メイン・サブCPUアドレス空間

これは、FM-7仕様のアドレス空間であり、FM-7用のソフトウェアを動作させることを目的としています。

これとネットで入手したROMデータの対比表です。ROMのアドレスをグレーで表記しています。

図%%.2
図139.2 メモリマップ

左矢前のブログ 次のブログ右矢

6809サブシステム回路図

posted by sakurai on July 30, 2019 #138

Vivadoによる6809サブシステム回路図です。

図%%.1
図138.1 6809サブシステム回路図

注意としては、下図のようにCPU RESETが負論理で現れますが、正論理なので与えるリセットの論理に注意します。

図%%.2
図138.2 6809CPU付近回路図

前稿のプログラムを6809で実行した結果を下図に示します。6809は2MHzで動作させています。

図%%.3
図138.3 実行結果

画面書き換えが上から下に進むのがはっきり見えますが、これは2MHz動作の6809だからであり、8MHzに上げて見ると書き換えがほとんど見えなくなるほど速くなりました。


左矢前のブログ 次のブログ右矢

6809 (2)

posted by sakurai on July 29, 2019 #137

次に、

$ cat header.coe > rom.coe; od -An -v test.o >>rom.coe; echo ';' >> rom.coe

ただし、header.coeは、

memory_initialization_radix=16;
memory_initialization_vector=

これを実行すると、

memory_initialization_radix=16;
memory_initialization_vector=
4f 8e 00 00 a7 80 4c 8c 3e 7f 25 f8 8e 40 00 a7
80 4c 8c 7e 7f 25 f8 8e 80 00 a7 80 4c 8c be 7f
25 f8 20 dd 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 :
 :
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 c0 00
;

というテキストファイルのCOEファイルが生成されるので、これをROMデータとしてFPGAに組み込みます。

本プログラムはVRAMのアドレスにデータを書き込み、次のアドレスに別のデータを書き込みという処理を繰り返し、VRAMをランダムなデータで埋めるものです。RGBで異なるデータを書き込むために、カラフルな縞模様を表示します。


左矢前のブログ 次のブログ右矢

6809

posted by sakurai on July 26, 2019 #136

さて、目的はレトロコンピュータの設計ですが、そのために8bit CPUを搭載します。ここでは使用するソフトウェアの関係上6809を取り上げます。入手元はOpen Coresで、VivadoにはRTLとして取り込みます。
https://opencores.org/projects/6809_6309_compatible_core

開発ツールが必要ですが、6809アセンブラを以下から入手します。
https://www.6809.org.uk/asm6809/

画面表示用のサンプルソースファイルをテキストエディタで、

VRAMB equ \$0000
VRAMR equ \$4000
VRAMG equ \$8000
;
start org \$c000
;
 clra
l1 ldx #VRAMR
l2 sta ,x+
 inca
 cmpx #VRAMR+16000-1
 blo l2
;
 ldx #VRAMG
l3 sta ,x+
 inca
 cmpx #VRAMG+16000-1
 blo l3
;
 ldx #VRAMB
l4 sta ,x+
 inca
 cmpx #VRAMB+16000-1
 blo l4
 bra l1
;
 org \$fffe
 fdb start
;
 end

として、以下のようにアセンブルします。

asm6809 --bin test.asm -l test.lst -o test.o

以下のアセンブルリストのようにアセンブルされ、合わせてバイナリファイルが生成されます。

0000         VRAMB  equ   \$0000
4000         VRAMR  equ   \$4000
8000         VRAMG  equ   \$8000
           ;
C000         start  org   \$c000
           ;
C000 4F           clra
C001 8E0000     l1   ldx   #VRAMR
C004 A780      l2   sta   ,x+
C006 4C           inca
C007 8C3E7F         cmpx  #VRAMR+16000-1
C00A 25F8          blo   l2
           ;
C00C 8E4000         ldx   #VRAMG
C00F A780      l3   sta   ,x+
C011 4C           inca
C012 8C7E7F         cmpx  #VRAMG+16000-1
C015 25F8          blo   l3
           ;
C017 8E8000         ldx   #VRAMB
C01A A780      l4   sta   ,x+
C01C 4C           inca
C01D 8CBE7F         cmpx  #VRAMB+16000-1
C020 25F8          blo   l4
C022 20DD          bra   l1
           ;
FFFE             org   \$fffe
FFFE C000          fdb   start
           ;
0000             end


左矢前のブログ 次のブログ右矢


ページ: