Apple IIのハードウエア番外編

Wikipedia日本語版のApple IIの記述には誤りが多いのでここでテクニカルなものについて書いておく。

また、ゲームI/Oという2つのA/Dコンバータを備えた入力端子が一系統、標準で実装されており 、 

パドル入力は4つ。以下がAPPLE IIのゲームI/Oと呼ばれるコネクタで、PDL0-3端子に150KΩの可変抵抗を接続できる。

f:id:k_igrs:20200328104459j:plain

 またゲームI/Oのパドル入力はA/Dコンバータによるアナログ入力は行なっていない。

基板上の558タイマーのパルス幅を読み取ることで可変抵抗の抵抗値をソフトウエアで判断している。Wikipedia555 タイマーにも記述あり。

実際の回路は

f:id:k_igrs:20200328105932j:plain

となっておりRに150KΩの可変抵抗が接続され、RC回路の時定数に応じて出力のパルス幅が変化する。

抵抗値が小さいと短いパルス幅、大きいと長いパルス幅になるため、それ(下記PIN 1波形のHigh幅)をソフトウエアで読み取る。

f:id:k_igrs:20200328110547j:plain

APPLE IIのパドルの抵抗値を読み取るROM内ルーチン。

   LDA $C070 #トリガを1パルス出力
   LDY #00   #ループカウンタYレジスタを初期化
   NOP       #トリガ入力後タイマーが安定するまで待つ
   NOP
L1 LDA $C064,X #タイマーが出力するパルスの読み取り(Xには読み取るパドル入力の番号を入れる)
   BPL L2    #パルス(Bit7)が[L]になったらループを終了する
   INY       #カウンタを一つインクリメントする
   BNE L1    #カウンタがオーバーフローしていなければ読み取りを続ける
   DEY       #カウント値の調整(値をFFに)する
L2 RTS       #読み取り終了

 このパルス判定のようなルーチンは6502CPUでの一般的なテクニックのようだ。

 

また、ビデオメモリの実装アドレスは連続しておらず、1ラスタごとに先頭アドレスは二進数の桁上がりで切りの良いアドレスに配置され、飛び石状に配置されている。これは、CRTCの実装を容易なものとした際の副作用である(手抜きとも言える)が、二進数で演算を行うCPUがビデオメモリ上の参照アドレスを演算する際にも(二進数で)切りの良い数字で桁合わせが可能となる(桁合わせの際に、数ステートの命令を省略できうる)というメリットを生じた。  

 この記述は英語版の記事を誤解してるのだろう。おそらく英語版の

This method had no cost overhead to have software calculate or look up the address of the required scanline and avoided the need for significant extra hardware. 

の "need for significant extra hardware. "をビデオ回路だと解釈したのだろうが、英語版では"as described above"と書いており、そこをみれば

This arrangement simultaneously eliminated the need for a separate refresh circuit for the DRAM chips, as the video transfer accessed each row of the dynamic memory within the timeout period. In addition, it did not require separate RAM chips for the video RAM, while the PET and TRS-80 had SRAMs for the video. 

 と書いてあり、簡素化されたのはリフレッシュ回路やビデオ専用メモリとわかる。

"the refresh of the dynamic RAM as a side effect"のside effectは薬の副作用みたいなネガティブな意味ではなく、ここでは余禄や一石二鳥のようなポジディブな意味として記述している。

英語版ではビデオアドレスは複雑化したがソフトウエアでのビデオアドレス算出の高速化と(リフレッシュ回路やビデオ専用メモリなどの)ハードウエアの追加を回避したといっていて、日本語版では原因と結果が逆になっている。

 

なお、ビデオメモリが1バイトあたり7ピクセルとなっているのは、本体のマスタークロックである14MHzの分周に処理を合わせるためで、

Apple IIのハードウエア(3)で述べたように連続で処理するビデオデータの読み出しとビデオ出力が一致しないため7bitとなっているだけで分周に処理を合わせているためではない。

コンピュータの一般的なテクニックとして入力と出力が一致しない対処法としてバッファを用いて入力と出力の調停を行い不一致を吸収する手法を用いる。シリアルインターフェースが典型的である。

実際にこの手法を使えば8bit全てのデータを利用することは可能で、分周の処理とは関係がない。

 

8つある拡張スロットは0番と7番が特殊な仕様になっており、スロット0番は内蔵のROMエリアと切り替えができ、 

Apple IIのハードウエア(1)で述べたとおり、内蔵ROMの切り離しは全ての拡張スロット上にあるINHB(正確にはINHの上にー)を[L]にすることで行い、0番とその他のスロットの区別は無い。

以下がROM切替の概念図

f:id:k_igrs:20200328122658j:plain

 

 RAMに置き換えて64KBのメモリエリアを全てRAMにする場合に使用された。

 C000-CFFFまでのエリアはAPPLE IIのシステムに利用されるためメモリとして使用できない。16KByte RAMカードは12KByte +4KByteのバンク切替で使用される。

f:id:k_igrs:20200328123130j:plain

 

MacのターミナルでOS付属の辞書を使う

macOSに標準で付属している辞書をターミナルから使うには

open dict://単語

とすると辞書ソフトが立ち上がり単語の意味を表示する。

また辞書ソフトのAPIを使うとswiftやpythonで作成したスクリプトでターミナル上から辞書をひける。

以下のようなswiftのスクリプトを作成して実行パーミッションをつけて引数に単語を指定して実行する。

>vim dict

#!/usr/bin/swift
import Foundation

if (CommandLine.argc < 2) {
    print("Usage: dictionary word")
}else{
    let argument = CommandLine.arguments[1]
    let result = DCSCopyTextDefinition(nil, argument as CFString, CFRangeMake(0, argument.count))?.takeRetainedValue() as String?
    print(result ?? "")
}

このスクリプトを実行すると

>chmod u+x dict
> ./dict 辞書 じしょ 1【辞書】① 多くの言葉や文字を一定の基準によって配列し,その表記法・発
音・語源・意味・用法などを記した書物。国語辞書・漢和辞書・外国語辞書・百科辞書
のほか,ある分野の語を集めた特殊辞書,ある専門分野の語を集めた専門辞書などの種
類がある。辞典。辞彙(じい)。語彙。字書。字引。② 仮名漢字変換方式のワード-プ
ロセッサーにおいて, 仮名に対応する漢字を登録しておくファイル。あるいは,自動
翻訳システムにおいて,単語間の対応や文法を記録しておくファイル。③ 辞職の意を
記した文書。辞表。「この頃大弐―奉りたれば」〈栄花物語•見はてぬ夢〉
>

のようにターミナル上で辞書が引ける。

このスクリプトvimで利用することで編集中に簡単に辞書を引くことができる。

ホームディレクトリにある.vimrcに以下の記述を追加する。PATHは作成したスクリプト"dict"があるpathを記述する。

command DICT exe ":!PATH/dict ".getreg('"')
command JISYO !PATH/dict <cword>

vimを立ち上げて辞書を引きたい単語上にカーソルを持って行き

:JISYO

とすると単語の意味が表示される。

※単語なのでスペースで区切られている必要がある。

またはビジュアルモードで単語を選択してコピーした後(vを押してカーソルを移動させてyを押す)

:DICT

とするとコピーした単語の辞書が引ける。

Macでインターネットラジオを聞く

ターミナルからインターネットラジオのストリーミング放送を聞くにはmplayerを使用する。

インストールしていない場合はインストールする。

brew install mplayer

 次にラジオ局のプレイリストを入手する。以下のようなサイトにいってプレイリストのダウンロードする。

www.internet-radio.comリンク先から放送しているラジオのプレイリストをダウンロードする。

f:id:k_igrs:20200206155151j:plain

ターミナルで再生するには

mplayer -playlist "ダウンロードしたm3uファイル"

とする。

http://66.70.187.44:9029/listen.pls?sid=1

のようなプレイリストがエラーになる場合はエディタで

http://66.70.187.44:9029

と修正する。

 

簡単にラジオを聴くため、ダウンロードしたプレイリストをホームディレクトリ以下に分類しておき以下のようなスクリプトを作成してFinderの選択ウインドウからプレイリストを選択できるようにする。

#!/bin/bash

urlname=`osascript -s o -e '
  tell application "Finder"
    activate
    set fn to choose file
    set filePath to POSIX path of fn
  end tell
'`

echo "$urlname"|grep "execution error" >/dev/null

if [ "$?" -eq 0 ]; then
        exit 0
else
        mplayer -playlist "$urlname"
fi

 

 

MacのFinderのTab(タブ)を自動で開く

Macで作業している時Finderのタブを複数開いて作業をしているが、タブを開いて目的のフォルダまで移動するのが面倒くさい。

どうにか自動でできないか調べたところ、AppleScriptを実行すればよいとわかった。

キーボードで、新しいTabを開く操作や選択したフォルダを開く操作をAppleScriptで実行する。

注意すべき点は

 エディタでAppleScriptを作成して実行パーミッションをつけてターミナルから実行する。

 初めに新しいタブを開くコマンド+tのショートカットと、ファイルを開くコマンド+oのショートカットのサブルーチンをスクリプトの最後にでも記述しておく。

on newTab()
        tell application "System Events" to keystroke "t" using command down
        delay 0.5
end newTab

on openKeysDown()
        tell application "System Events" to keystroke "o" using command down
        delay 0.5
end openKeysDown

 最初のフォルダを開く。フォルダ名はトップからのパスで記述し、パスは":"で区切る。

#!/usr/bin/env osascript

# 始めのfolderを開く
tell application "Finder"
        activate
        open folder "TOP:初めに開くフォルダ"
end tell

タブを開いてhomeディレクトリにリンクしたディレクトリをオープンする。

tell application "Finder"
    my newTab()
    select file "TOP:user:linkdir"
    delay 0.5
    my openKeysDown()
end tell

リンクしたディレクトリを開いた後は

select folder "パスを含めたフォルダ名"
delay 0.5
my openKeysDown()

で順にフォルダを開いていく。あとはタブを開く→リンクを開く→フォルダを順に開いていくの繰り返しとなる。

今更Z280MPUを調べて見た

8bitCPUでは大人気のCPUだったZ80の機能強化版として1987年にリリースされたのがZ280。しかしながら市場は16bitに移行しつつあり時期が遅すぎたことで採用するメーカーも現れずに消え去ったのでした。

リリースされた時期が遅れたのは開発に難航したからだろうと推察されます。事実仕様をみるとZ80MMUをくっつけただけではなくモダンなOSが実装できる機能が加えられており、EDAツールが碌に存在しなかった時代では無理も無いかなと。

拡張された主な機能をみると、

  • Z80とオブジェクトコードレベルでコンパチブル
  • キャッシュと、それを有効に使えるメモリアクセスの追加
  • マルチタスク用の機能の追加
  • HLレジスタを8ビット時のAレジスタと同様の16bitレジスタとして使えるようになった。
  • 乗算、除算命令の追加
  • 新規アドレッシングモードの追加
  • MMUを利用した24bitの物理アドレスの追加
  • 3ステージのパイプライン
  • バスの16bit化

従来のZ80システムに載せられることができるようにバス幅を8bit/16bitで使用しているかを示すB/Wb(Byte/Word)端子が追加されています。IOポート等はこの端子とA0をデコードすることで8bitのシステムと互換性がとれます。

 

これが1980年代初期に出ていれば始めは高速で広いメモリ空間を持つZ80として利用し、メモリや外部記憶装置が安くなればUnix LikeなOSを利用するといったシナリオも考えられ歴史が変わったかも。

 

Z280の機能を見ていきます。

キャッシュメモリ

キャッシュメモリの導入はプロセッサの高速化では定番です。単にキャッシュメモリを導入するだけでは無くキャッシュを有効に活用できるメモリアクセスが必要となります。

そのため4ワードのメモリ一度にリードするバーストアクセスができるようになっています。ひとかたまりのメモリデータを読み込みon-cacheで実行出来るようになり、パイプラインを有効に活用できるようになります。

メモリインターフェースはDRAMのページモード(同一ロウアドレスではカラムアドレスだけでアクセスできる。)を利用できる様に設計することになるでしょう。

f:id:k_igrs:20200101182805j:plain

バーストアクセスタイミング

 

マルチタスク用の機能

Z280はマルチタスクに必要なハードウエアとソフトウエアの機能を搭載しています。

MMUがシステム用とユーザー用の2セット用意されておりOSがユーザープログラムから影響を受けない様になっています。システムとユーザーの切り替えはMMU Master Control Registerで設定します。どのモードかはMaster Status Registerで確認できます。

ユーザー空間で実行するプログラムはシステムに影響するようなI/O命令は特権命令となっており、実行するとI/O Trap割り込みが発生しシステムプログラムに移行します。

ユーザープログラムがシステムプログラムにアクセスするためにはSC(System Call)命令を実行します。この命令が発行されるとシステム用のスタックポインタに実行時のプログラムカウンタとMaster Status Resisterの値と16ビットの任意の引数を積んでSC Trapを発生させます。

またマルチタスクMMUを使用する為の割り込みモード3が追加され便利な割り込みトラップ(割り込み)が使用できるようになっています。

このようにZ280は本格的なマルチタスクを実行できる機能を備えています。

 

MMUの機能

Z280のMMUはユーザー/システムの2セット用意されており16bitのアドレスを24bitに拡張しています。

f:id:k_igrs:20200102085903j:plain

MMUによるアドレスの拡張

MMUテーブルはアドレス上位4bitで一つ選択され、テーブルの16bitのデータ中、12bitが拡張するアドレス、4bitがMMUアトリビュート(Write Protect,変換、変更の有無,キャッシュの有無)となります。

また命令実行中にページフォルトが発生すると、その命令は中止されシステム用のスタックに実行アドレスを格納してAccess Violation Trapを発生させます。OSはTrapが発生したらMMU Master Control Registerでどのページで発生したかを確認しMMUテーブルを書き換えた後、ページフォルトを発生させた命令を再実行させます。

この様に6809+MMUの様な簡易的なアドレス拡張ではなく本格的な仮想記憶の機能を備えています。

 

・拡張された命令

Z280で拡張された主だった命令を見ていきます。

Z280ではZ80とオブジェクトコンパチブルにするためZ80の未定義領域に命令を追加しています。

アドレッシングモードの拡張

アドレッシングモードではPC(プログラムカウンタ)相対とSP(スタックポインタ)相対が追加されています。

PC相対アドレッシングは16bitまで指定でき6809の様なリロケータブルなプログラムの作成が可能となっています。

SP相対アドレッシングではスタックポインタに積んだデータのアクセスが簡単に行える様になりました。このアドレッシングが追加されたのはOSのカーネルがトラップ発生時にスタックの情報を簡単取り扱える様にする為でしょう。

 

16bitロード命令

HL,IX,IYレジスタが16bitのポインタとしてメモリアクセスができる便利な命令が追加されています。

  • LDW (addr),nn
    addrに指定したメモリに16bitの直値nnを代入する
  • LDW <addr>,nn
    実行した命令からaddrを加算したアドレスに直値nnを代入する
  • LDW HL,(IX or IY or HL+dd)
    IX,IY,HLレジスタにdd(16bit)を加算したアドレスの値をHLレジスタに代入する
  • LDW IX or IY,(IX or IY or HL+dd)
    IX,IY,HLレジスタにdd(16bit)を加算したアドレスの値をIX,IYレジスタに代入する
  • LDW HL,(HL+IX or HL+IY or IX+IY)
    HL+IX or HL+IY or IX+IYの演算した結果のアドレスの値をHLレジスタに代入する。
  • LDW IX or IY,(HL+IX or HL+IY or IX+IY)
    HL+IX or HL+IY or IX+IYの演算した結果のアドレスの値をIX or IYレジスタに代入する。
  • LDW HL,<addr>
    実行した命令のアドレスにaddrを加算したアドレスの値をHLに代入する
  • LDW IX or IY,<addr>
    実行した命令のアドレスaddrを加算したアドレスの値をIXまたはIYに代入する
  • LDW HL,(SP+dd)
    スタックポインタの値からdd(16bit)を加算したアドレスの値をHLに代入する
  • LDW IX or IY,(SP+dd)
    スタックポインタの値からdd(16bit)を加算したアドレスの値をIXまたはIYに代入する

以降は上記のsrcとdistが逆の命令です。

  • LDW HL,(HL+IX) LDW HL,(HL+IY) LDW HL,(IX+IY)
  • LDW IX or IY,(HL+IX) LDW IX or IY,(HL+IY) LDW IX or IY,(IX+IY)
  • LDW (IX or IY or HL+dd),HL
  • LDW (IX or IY or HL+dd),IX or IY
  • LDW <addr>,HL
  • LDW <addr>,IX or IY
  • LDW (SP+dd),HL
  • LDW (SP+dd),IX or IY
  • LDW (HL+IX),HL LDW (HL+IY),HL LDW (IX+IY),HL
  • LDW (HL+IX),IX or IY LDW (HL+IY),IX or IY LDW (IX+IY),IX or IY

乗除算命令

8bitまたは16bitの乗除算命令が追加されています。

8bit Aレジスタとソース(レジスタ、メモリ)の乗算結果をHLレジスタに代入します。符号付きと符号なし(MULTU)があり。

使用例)

16bit HLレジスタとソースレジスタ、メモリ)の乗算結果をDEHLレジスタに代入します。符号付きと符号なし(MULTUW)があり。

使用例)

 32bit DEHLレジスタとソースレジスタ、メモリ)の除算結果をDEHLレジスタに代入します。

演算結果が16bit未満の時はHLに商をDEに余りを格納します。

演算結果が16bitを超える時はDEHLは変更せずOverFlow flagを1にして除算例外割り込みが発生します。

ゼロで割るとOverFlow flagを1にしてSing flagを0にして除算例外割り込みが発生します。

使用例)

乗算と同様に8bitの除算と符号なしの除算もできます。

8bit時はHLレジスタの値をソースレジスタやメモリの値で除算し商をAレジスタ、Lレジスタに余りが格納されます。

16bitのINC,DEC

対象のメモリ16bitのデータに対してインクリメント、デクリメントができる様になりました。2byteメモリデータの+1.-1が1命令でできます。

Z80の時の様に

  1. LD HL,(addr)
  2. INC HL
  3. LD (addr),HL

のようにしなくても良くなっています。またIX,IYレジスタのインクリメント、デクリメントも追加されています。

使用例)

INCW (HL)

INCW (2000H)

DECW (IX+20H)

DECW <0400H>

INCW IX

DECW IY

JUMP,CALLの相対アドレッシング対応

Z80では相対JUMP命令は8bitでしたが、Z280ではJUMP,CALL命令が16bitのPC相対アドレッシングに対応したことによりどのアドレスからも実行できるプログラムが作成できる様になりました。

使用例)

  • 条件付きジャンプ
    JP NZ,<label1>
  • 無条件ジャンプ
    JP <label2>
  • 条件付きサブルーチ実行
    CALL  C,<label3>
  • 無条件サブルーチン実行
    CALL <label4>

16bit COMPARE命令

Z80ではAレジスタとの8bitの比較でしたがZ280ではHLレジスタとの16bitの比較ができるようになりました。

使用例)

  • レジスタとの比較
    CPW HL,BC
  • IX,IYレジスタとの比較
    CPW HL,IY
  • 直値との比較
    CPW HL,1234H
  • メモリとの比較
    CPW HL,(6000H)
  • IX,IYレジスタ間接アドレスの値との比較
    CPW HL,(IX+300H)
  • PC相対アドレスの値との比較
    CPW HL,<200H>

加算、減算

Aレジスタを使用した8bitの加減算ではZ280の新規アドレッシングモードが追加されています。

使用例)

PC相対アドレスの値との加算

ADC A,<400H>

またフラグ無し16bitの加減算では新規アドレッシングモードの追加の他に直値の演算が可能になっています。

例) HLレジスタに1234Hを加算

ADDW HL,1234H

 

とりあえず目についた追加命令は以上です。総じてZ80で不足していたレジスタやメモリの操作が充実しています。

Z80がAレジスタを中心に8bitの処理を行うCPUとすれば、Z280はHLレジスタを中心に16bitの処理を行うCPUといえるでしょう。

Z80では実行ステート数が増える為、高速化のため避けていたインデックスレジスタIX,IYの使用もバスの16bit化とキャッシュ+パイプラインが実装されたことにより積極的に使えます。キャッシュやパイプラインを意識したコンパイラを使用すればZ80Aの5-10倍の処理能力がありそうです。

 

以上のようにZ280は8bitCPUとしては非常に強力なものとなっていますがリリース時期が遅すぎました。おそらくチップの仕様から見てザイログ社はZ280を通信、印刷をマルチタスクで実行する必要があるネット端末の様な組み込み用に利用されること考えていたのではないでしょうか。

linuxでdvd discをiso化する

dvdレコーダーで焼いたdiscをlinux(debian系)でiso化するための備忘録。

dvdのファイルにアクセスするためのパッケージの追加

sudo apt update
sudo apt install libdvd-pkg
sudo dpkg-reconfigure libdvd-pkg

iso化

sudo dd if=/dev/dvd of=dvdvideo.iso

作成したisoのマウント

mkdir mnt
sudo mount -o loop -t iso9660 dvdvideo.iso ./mnt/

マウントの解除

sudo umount mnt

Macでどうぶつの森 Wii/ゲームキューブ用エミュレータdolphin

ゲームキューブ版のどうぶつの森+をやりたくなったが本体のコントローラが故障してしまい入力が不可となってゲームができなくなった。

そこでMacでゲームをするためクロスプラットホームのWii/ゲームキューブエミュレータdolphinを使ってみた。

ゲームの実行まで

まず、dolphinをインストール。

> brew cask install dolphin

だが、簡単にゲームを実行することはできない。ゲームディスクがMacで読めないからだ。(読めるディスクドライブもあるらしい)

そこでゲームディスクをWiiを使ってisoイメージにした。Wiiに非公認のソフトをインストールすることになるので不具合が発生しても自己責任で。

iso化についてはWii 4.3J対応! LetterBomb使い方 | ゲームの小ネタメモ帳 > WiiWii本体からのリッピングを参照して行う。

今回は

  • Wii本体。システムのバージョンが4.3Jに更新済みのもの
  • MicroSDカード。FAT32でフォーマット済みのもの
  • 外付けUSBハードディスク。NTFSでフォーマット済みのもの

を準備してゲームディスクをisoイメージにした。

ゲームの設定

 ゲームキューブどうぶつの森+iMac(2013model)でも快適にプレイできている。

設定に関してはデフォルトのままで良いと思うが以下の設定は変更する。

  • ビデオの設定で「一般」の「表示設定」の垂直同期(V-Sync)にチェックを入れる。→スクロール時画面が乱れなくなる。
  • 「高速化(Hacks)」の「External Flame Buffer」をRealにする。→ファミコンが正常に表示される。

ゲームプレイ

ゲーム入力には「Logicool G ゲームパッド F310r ダークブルー PC ゲームコントローラー Xinput F310」を使用している。振動機能がないけど安いし。

MacでPC用のUSBゲームパッドを使用するにはXbox 360 Controller Driverが必要かも。以下からダウンロードしてインストールしておく。

github.comdolphin上でのゲームは快適である。魚釣りもエミュレータのステータスセーブ・ロードを使えば釣るのが難しい魚でも確実に釣れるしね。