November 2008アーカイブ


AVRのプログラマを作り、ブレッドボード上でプログラムできることを確認したので、いよいよ(?)まともにSDカードリーダを作り始めました。

回路図

回路図は以下のようになっています。

20081130-AVR_SD.PNG

SDカードが3.3V動作なので、途中で電圧変換をしなくて済むようにAVRはATmega8Lを使います。きわめて簡単な回路ですね。

一応説明をすると、入力の5Vは48M033Fで3.3Vに降圧しています。 ^A7と^IORQのORを割り込み入力とします。 A6~A3はすべてORをとってPB0に入力しており、I/O空間はA2~A0の3ビット分を予約しています。 PC側からみれば、ポート00~ポート07までを使います。

SDカードとの入出力はmega8Lに搭載されているSPIをそのまま使います。 同時に、ISPにも接続することにより、PC-6001からの電源をもらってプログラムできるようにしてあります。 プログラムを行う際はリセット端子がPCからの入力では都合が悪いので、スイッチをつけています。

ハード実装

手抜き実装で、プルアップ抵抗をまだ入れていませんが、とりあえず実装したものはこんな感じです。 一応この程度でも動くことはブレッドボード上で確認してあります。

20081130-AVRSD-card.jpg

中央下部に空間を空けてあるのは、あとでBIOS ROMを入れることを考えているためです。

簡単なテストプログラムを作って試してみているのですが、今のところPC本体がちゃんと起動しません...。

日本でのインフルエンザの予防接種が有料なのは、日本では「予防医療」に対して保険が利かないからだということを聞いたことがあります(子供の日本脳炎等は別途定めがあるのでしょうが)。また、「病気の治療ではないもの」に対しても一般的に保険は利きません。そのため、お産は自腹なんですね。

会社によっては、健康保険組合が補助を出したり付属の病院で無料接種をしたりしているところもあるでしょう。そういうところを上手に選べば節約できるかもしれません。

イギリスでは、インフルエンザの予防接種は基本的に無料です。GP(General Practitioner: ホームドクターみたいなところ)で打ってもらうことができます。また、会社にドクターを呼んで集団接種することもあります。そういえば、私が子供の頃は、インフルエンザの予防接種は学校で一斉にやっていたような? あれはいつからなくなったのでしょう?

ちなみに、アメリカではインフルエンザの予防接種のことを"flu shot"といいますが、イギリスでは"flu jab"といいます。

Scalaを始めたばかりでJavaで書いてたことをどう書くのかよく混乱するので、メモ。

項目JavaScala
クラスオブジェクトFoo.classclassOf[Foo]
例外ハンドリングtry { .. }
catch (Ex1 e) { .. }
catch (Ex2 e) { .. }
try { .. } catch {
case e1: Ex1 => ..
case e2: Ex2 => ..
}
リスト/配列作成list = new ArrayList() list = List[T]()
array = Array[T]()
リスト追加N/Alist = list ::: List(x)
配列追加list.add(x)array ++ List(x)
マップ作成map = new HashMap()map = Map.empty
マップ追加map.put(x, y)map += x -> y
シングルトンstaticでメンバに保持object { ... }
イテレーションfor (i : list) ...list foreach (i=> { ... })
キャスト(Foo) barbar.asInstanceof[Foo]
型判定foo instanceof Foofoo.isInstanceof[Foo]
内部型Foo.BarFoo#Bar
シングルトンの型N/Aobj.type
型パラメータ制約class Foo<T extends Bar>class Foo[T <: Bar]
(逆もclass Foo[T >: Bar]で可能)
オブジェクトObjectAny (primitiveを含む場合)
AnyRef

なんかまだまだあった気がするけど、気付いたら追加しよう。 なお、必ずしもsemanticalに同一ではないので注意してください。

Scalaを使ったフレームワークにspecsというのがあります。 Behaviour-Driven Design frameworkといっています。

乱暴な言い方をすれば、Test driven developmentと、Domain driven designを融合したもの、という感じです。 Test drivenといえばJUnitなどですっかりおなじみですが、specsはScalaの特徴を生かして、仕様がより自然に(ノイズが少なく)書けることが特徴でしょう。

Domain driven designは、特定の技術を表すものではなく、設計の考え方です。複雑なソフトウェアの設計をドメイン知識をうまく使いながら行おうといういうものと思われます。 比較的新しい考え方のようで、OOPSLA 2007でBoFが開かれたそうです。

そんな感じなので、specsにはドメイン知識としての仕様を記述して、それをチェックする機能が備わっています。

specsはScalaをベース言語としているので、当然普通にJavaとして動作するのですが、DSLのコンテキストで考えたときに、テストだけではなく純粋に動作する仕様としてどのように考えられているのか、という点についてはまだよくわかっていません。 もともと仕様をデザインするためのもの(design framework)なので、そのままの形で実稼動するソフトウェアにするのは本来の目的ではないのかもしれません。

でも、これをJUnitのように純粋なテストのためのフレームワークと考えるのもまた違うような気がします。 Scalaの言語機能を考えると、もっとポテンシャルがあるように思います。

というわけで、まだまだ勉強中なのですが、specsのソースコードはScalaの勉強にはいいですね。

遅々として進んでない(汗)AVR関連作業ですが、とりあえず現状の実験環境はこんな感じです。

AVR-BreadBoard.jpg

写真の左側から、シリアルケーブル、9pin DSUBを0.1inchピッチに変換する基板(緑色)、COM-ISP変換(ユニバーサルボード)、そして実験用のブレッドボードです。 DSUB変換基板とCOM-ISPはピンヘッダ&コネクタで接続しています。 まぁ、これは9pin DSUBでユニバーサルボードに挿さるものが見つからなかったため、変換基板を使いまわそうとしただけで、単なる趣味です。

COM-ISPからは、6本の線を直接AVRのピンにつなぐことによってプログラムができるようにしています。 ブレッドボードにわざわざISPヘッダなんてつけても意味ないですからね。

ISP(In System Programming)なので、ブレッドボード上では好きに回路を組んで実験ができます。

私は回路図を書くのは嫌いではないですが、実際に作るのは苦手なので、このような環境で少しづつ実験をするのですが、それなりに複雑なプログラムを動かそうとすると大変です。 ATmega8は28ピンで、それなりに入出力が多いので、それをどのように「インクリメンタルに」作っていくかが悩みどころです。

ソフトウェアでは、少しづつ作って動作を確認しながら規模を大きくしていくのは常道ですが、ハードウェアで似たようなことがどれくらいできるのか、試行錯誤しています。

AVRメモ

| | コメント(0) | トラックバック(0)

AVRの実デバイスを使った実験を始めたので、メモ。 なお、ATmega8/AVR Studio 4.14/WinAVR 20080610を使っています。

リセットポートを使う場合の注意

リセットポートに値を出力設定しないように注意。 たとえば、mega8の場合、PC6(RESETを兼ねる)の値を出力設定にしてしまうと、正常動作しない。 具体的には、DDRCのビット6を0にしておく。

1ポートのみ出力する、反転する

PORTCの5番ピンの例。 出力する場合は、

PORTC |= _BV(PC5);
PORTC &= ~_BV(PC5);

ここで、アセンブラ出力ではsbi/cbiが使われているようです。 これらの命令は2クロックかかるので、1ポートのみという制約がなければ、1クロックのoutの方がいい場合もあります。 反転する場合は、

PORTC ^= _BV(PC5);

このアセンブラ出力は次のようになります。

in	r24, 0x15
ldi	r25, 0x20
eor	r24, r25
out	0x15, r24

割り込みルーチン

割り込みルーチンはISRで記述しますが、先立ってmainなどで割り込みモードの設定と割り込み許可を行っておく必要があります。 ここでは外部割込みINT0で説明します。

// interrupt service routine for INT0
ISR(INT0_vect) {
  ...
}
int main(void) {
  // interrupt enable for INT0
  GICR |= _BV(INT0);
  // interrupt condition: down edge
  MCUCR |= _BV(ISC01);
  sei();
  ...
}

MCUCRの設定では、立ち下がりエッジの場合はISC01=1, ISC00=0ですが、初期値が0なので、ISC00の設定を省略しています。

AVRは割り込みハンドラに分岐する前に、割り込み禁止にします。 アセンブラ出力では、割り込みルーチンISRからは自動的にretiでリターンしているため、明示的な割り込み再許可は不要のようです。

逆に言うと、デフォルトでは多重割り込みはできません。 ただ、調べてみた限りでは、割り込み要求はキューイングされており、割り込み処理中の要求は、今の割り込み処理終了後にトリガされているようです。

USB-シリアルアダプタでの書き込み

秋月で買ったUSB-シリアルアダプタ、Prolific USB-to-Serial Comm Portというものを使用しています。 これに、COMポート制御ISPアダプタを作成・接続しています。

読み書きはかなり遅く、mega8のEEPROM(512バイト)の読み込みに2分18秒ほどかかります。また、208バイトのプログラム(消去、書き込み、べりファイ)に2分37秒程度です。


反応進行!

| | コメント(0) | トラックバック(0)

私は昔、東急沿線住民でしたが、普段、乗り降り階段の位置の関係で運転席(運転士または車掌が乗務してます)の近くに乗っていました。 そこでいつも運転士さんが言っていることで謎がありました。 出発する際によく「はんのう、しんこう!」と言うのです。 「出発進行」ではありません。 「しんこう」は「進行」だろうけど、「はんのう」は何だろう。「反応」だろうか、反応とは何だ?


と思って調べてたら、「反応進行」とは「出発反応標識が点灯しているので出発できることを確認する動作(喚呼: 声に出して確認すること)」だったのですね。 ちなみに「出発進行」は出発信号機が進行状態になっていることの喚呼ですが、必ずしも出発信号機が運転士から見えやすい位置にあるとはとは限らないので、そのような場合に出発反応標識が設置されているそうです。 詳しいことはWikipediaへ。

私はこのセリフ、東急以外で聞いたことがありません。 とは言っても、私が私鉄系で日常乗っていたのは東急と京王のみなので、他の会社では似たようなことがあるのかもしれません。

ついでに言うと、「しょうかいひねがいます」というのも意味不明でした。 「小回避」だと思ってたんですが、「小開扉」のことなんですね。 駅で出発前に扉を閉めたとき、扉に体や物が挟まったりしたときに、挟まっている車両のドア(車体側面上方についている赤いランプが消えない)のみを開くことができるそうで, その操作のことを言うそうです。

グリーンハウスからPATAの1.8インチSSDが出ました。プレスリリースも出ています。
VAIO UやLoox U/Pなどで少し古いタイプのパラレルATA 1.8インチHDD搭載機種のオーナー(私もです)に朗報でしょう。

容量は16~32GB(SLC)、16~64GB(MLC)で、直販サイトによると価格は32GB(GH-SSD32GP-1S: SLC)で49,800円、64GB(GH-SSD64GP-1M: MLC)で29,800円です。

これは争奪戦になりそうな予感...。
ちょっと気になるのは、コネクタ部分の画像が見つからないことです。形からは東芝タイプに見えるのですが...。

今度、仕事での開発用にパソコンを買うことになりそうです。日本にいたときと異なり、欲しいから買える、という状況ではありません。デスクトップ、ラップトップ(日本で言うところのノートブックは欧米では通常ラップトップといいます)いずれかを慎重に選ぶ必要があります。日本でやっていたような「開発はパワフルなデスクトップ、必要に応じてラップトップに資源を入れて持ち歩く」ということができないのです。

両方を買えないのであれば、ラップトップを選びます。デスクトップを持ち歩くことはできないためです。

そうなると、私は仕事柄、ラップトップでもヘビーに使います。しかも、日本にいたときの癖で、マシンを常時持ち歩くため、小型軽量も求めます。このような要件に見合うラップトップは、現在のいわゆる「ネットブック」ブームとは全く関係ないところにあると思うので、あまり同意できる人はいないのかもしれません。

いくつか必要とする要件を、現状で可能であることをベースとして挙げてみましょう。

  • 必要十分な総合パワー(CPUが強力だからいいということではなく、総合力です。ちなみに主な開発環境はEclipse+Cygwinです)。別に当代最高性能のCPUを求めるということはありません。普通に開発するにストレスを感じなければいいのです。これはCPUの問題だけではありませんね。
  • 本体での十分なモニタ解像度。いわゆるXGAでは不十分。ただし物理的な大きさはそれほど問わない。
  • 複数のオフィスアプリケーション+開発ツールが走るだけのメモリ。現状だと最低2GB。
  • ネットワーク関連。最低802.11g+Bluetooth。Bluetoothはマウスやら携帯やらで必須。
  • 高速で十分な二次記憶容量。100GB+。
  • なるべくUSキーボード。JIS準拠キーボードもUSドライバで使えばいいだけだが、使わないキーが多く無駄が多い。ヨーロッパ系のキーボードも悪くないが、慣れないので不便。
  • 本体のキーボードが打鍵可能なこと。私はA5サイズが平気な人ですが、Vaio UやLOOX Uはさすがに慣れがないので今のところ厳しいです。
  • 1kg程度の重量。
  • 十分なバッテリ持続時間。通常バッテリで最低3時間(カタログ値ではなく、開発で使う際の実使用時間)。オプションでいいので、大容量バッテリがあること。
  • 外部モニタはデジタル出力で1600x1200x2画面以上(とはいってもこれはさすがに現状ではありえないので、今はUSBのモニタアダプタを使っています)。

以前はペンオペレーションであることがとても便利だった(富士通のFMV-BIBLO MC/30を愛用してました、といってもわかる人はあまりいないかも...)のですが、今はそれほどではありません。あったら便利なのは確かですが、電磁誘導式だったらない方がいいです。抵抗膜式ならある分には歓迎です。

現在使っているのが、富士通のFMV LOOX P70T/Vなので、周辺機器(ポートリプリケータやACアダプタ等)の流用性から、今狙っているのがFujitsu SiemensのP1630なのですが、どうなのでしょうか。

こういうのは、要望が人それぞれなので仕様の「合意」は実質的に不可能だし意味もあまりないとは思いますが、技術的に現実的な視点での「こうだったいいのに」ということにはとても興味があります。良かったら意見をお聞かせください。


という触れ込み(?)の製品、それがEFI-Xです。 形式はUSBデバイスになっていて、これを挿すことによってWindows PCにMac OS Xをインストールできるそうです。 その逆...は既にBootCampで実現されていますね。

一種のブートマネージャで、複数のOSをインストールして切り替えながら使うことができますが、Mac OS Xがサポートされている点が斬新なところです。

WindowsベースのPCでMac OS Xが動作しないことの理由の一つに、EFI (Extensible Firmware Interface)のサポートが上げられます。 なお、現在EFIはUEFI (Unified EFI) Forumの管理下です。 MacはIntelベースになったときにEFIを採用しました。 もちろん、EFIといえどもROM (ファームウェア)にコードが書かれていますので、EFIをサポートすることが即Mac OSが動作することにつながるわけではありません。

ただ、WindowsベースのPCハードウェアの主流は未だに昔ながらのBIOSであり、EFIへの移行は遅々として進んでいません。 Mac以外に採用されているのは、Itaniumベースのシステムや、XScaleベースの組み込みシステムくらいです。 OS側としても、Windows系では、Windows Vistaのx64バージョンがUEFIをサポートしているのみです。

本製品の名前から、どうやらEFIの技術を使っているようですが、詳細は不明です。 なお、ヨーロッパで開発されているらしいです。

現状で「ラボベースで」動作確認を行ったと表明しているのは、以下のハードウェア(の組み合わせ)です。

  • Intelの最近の主なCPU (AtomおよびXeonを含む。AMDはサポート外)
  • NVIDIAおよびATiのいくつかのグラフィックカード
  • GIGABYTE, MSI, Intelのメインボード
  • いくつかのWLANアダプタ
  • 通常のサウンドカードおよびProToolsを初めとするオーディオボード
  • SATAのHDD/CD-ROM/DVD-ROM(PATAはサポート外)

なお、Hardware Compatibility List (HCL)に掲載されていないハードウェアの使用は、保証の無効化、サポートの中止になると警告しています。Appleは純正ハードウェア以外のMac動作や、商標の使用に対してかなり厳しい態度を取ってきましたから、慎重になっていると思われる文言もあちこちに見受けられます。

現在はデスクトップ用のみのサポートとなっており、 ノートブック用は開発中のこと。

販売代理店および販売対象国は以下のとおり。

  • mmservices
    スイス、オランダ、オーストリア、ドイツ、イタリア、フランス、スペイン、スカンジナビアが対象
  • EFiX USA LLC
    北アメリカ、中国、台湾、香港、日本が対象
  • AECLLUB
    ウクライナが対象
  • Kalki Todo Computo
    ペルーが対象

ちぇ、イギリスがないぞ。

現在のところ、公式サイトで得られる情報はあまり多くありません。 なお、FAQには次のような質問があります。

Q: いずれEFI-Xがインストールされたデバイスで全てのハードウェアが使えるようになるのでしょうか?

A: もしそうだったら我々の方が驚きです。冷蔵庫、電子レンジ、マウスパッドのサポートは実装されていません...まだ

なお、Intelベースの非MacマシンにOS XをインストールするプロジェクトはOSx86 Projectとして別に存在します。こちらは、Hackintoshと呼ばれることもあるそうです...。

古いメールを整理していたら、有名(?)なジョークが出てきましたのでペースト。航空券料金の複雑さを揶揄したものですね。

試しに、翻訳してみました。間違ってたらご指摘いただけると幸いです。


IF AIRLINES SOLD PAINT

もし航空会社がペンキを売ったら

Customer: Hi. How much is your paint?

やぁ、ペンキはいくらだい?

Agent: Well, sir, that all depends on quite a lot of things.

ええと、お客様、それはいろいろの事情に左右されます。

Customer: Can you give me a guess?  Is there an average price?

どのくらいなの? 平均価格とかないの?

Agent: Our lowest price is $12 a gallon, and we have 60 different prices up to $200 a gallon.

最低価格は1ガロン12ドルで、1ガロン200ドルまで60種類の価格がございます。

Customer: What's the difference in the paint?

ペンキはどう違うの?

Agent: Oh, there isn't any difference; it's all the same paint.

ああ、違いはございません。全て同じペンキでございます。

Customer: Well, then I'd like some of that $12 paint.

じゃぁ、12ドルのをもらおうかな。

Agent: When do you intend to use the paint?

ペンキはいつお使いでしょうか?

Customer: I want to paint tomorrow.  It's my day off.

明日かな。休みだから。

Agent: Sir, the paint for tomorrow is the $200 paint.

お客様。明日のペンキは200ドルでございます。

Customer: When would I have to paint to get the $12 paint?

12ドルのペンキはいつ塗ればいいんだい?

Agent: You would have to start very late at night in about 3 weeks.  But you will have to agree to start painting before Friday of that week and continue painting until at least Sunday.

およそ3週間以内の深夜に塗り始める必要がございます。 ただ、金曜日よりも前に塗り始めて、少なくとも日曜日までは塗り続けなければなりません。

Customer: You've got to be *&%^#@* kidding!

そんな馬鹿な。

Agent: I'll check and see if we have any paint available.

ペンキの在庫を確認してまいります。

Customer: You have shelves FULL of paint! I can see it!

ペンキならそこの棚にいっぱいあるじゃないか!

Agent: But it doesn't mean that we have paint available.  We sell only a certain number of gallons on any given weekend.  Oh, and by the way, the price per gallon just went to $16.  We don't have any more $12 paint.

しかしながら、それはペンキをご提供できることを意味するわけではないのです。 我々が週末用に販売するペンキの量には限りがございます。 ああ、ところでただいま1ガロンあたり16ドルになりました。 もう$12のペンキはございません。

Customer: The price went up as we were talking?

話している間に値段が上がったって?

Agent: Yes, sir.  We change the prices and rules hundreds of times a day, and since you haven't actually walked out of the store with your paint yet, we just decided to change.  I suggest you purchase your paint as soon as possible.  How many gallons do you want?

そうでございます、お客様。 我々は価格やルールを一日何百回も変更いたします。 お客様がペンキを購入なさってお店を出られていないので、そうなったのです。 できるだけ早くペンキをご購入なさることをお勧めします。 どれだけご入用ですか?

Customer: Well, maybe five gallons.  Make that six, so I'll have enough.

そうだな、5ガロンかな。6ガロンにしよう、それなら十分だ。

Agent: Oh no, sir, you can't do that.  If you buy paint and don't use it, there are penalties and possible confiscation of the paint you already have.

お客様、それはいけません。 お客様がペンキをご購入なさって使わない場合、違約金が発生して、既にお持ちのペンキは没収となる可能性がございます。

Customer: WHAT?

何だって?

Agent: We can sell enough paint to do your kitchen, bathroom, hall and north bedroom, but if you stop painting before you do the bedroom, you will lose your remaining gallons of paint.

我々はお客様の台所、浴室、廊下と北側の寝室に十分なペンキをお売りできます。 しかしお客様が寝室を塗り始める前におやめになった場合、残りのペンキは没収になります。

Customer: What does it matter whether I use all the paint?  I already paid you for it!

私がペンキを使い切るかどうかなんてどうだっていいじゃないか? もう金は払ったんだぞ!

Agent: We make plans based upon the idea that all our paint is used, every drop.  If you don't, it causes us all sorts of problems.

我々は全てのペンキ、最後の一滴まで使い切るという考えのもとに計画を立てております。 お客様がそうなさらない場合、我々にはあらゆる問題が発生してしまいます。

Customer: This is crazy!!  I suppose something terrible happens if I don't keep painting until after Saturday night!

そりゃおかしい!! 私が土曜の夜以降までペンキ塗りをし続けなきゃひどいことが起こるとでもいうのかい!

Agent: Oh yes!  Every gallon you bought automatically becomes the $200 paint.

ええ、そのとおりでございます!  お客様が購入なさったペンキはすべて1ガロン200ドルになります。

Customer: But what are all these "Paint on sale from $10 a quart" signs?

だったら、あの「1/4ガロン10ドルから」の看板はなんだい?

Agent: Well that's for our budget paint.  It only comes in gallons.  One $5 gallon will do half a room.  The second gallon to complete the room is $20.  None of the cans have labels, some are empty and there are no refunds, even on the empty cans.

ああ、それは我々の格安ペンキでございます。 ガロン単位でのご購入となります。 最初の5ドルのガロンは部屋の半分、次の20ドルのガロンで部屋を塗り終えることができます。 ペンキの缶にはラベルがありませんので、空のこともございますが、そのような場合でも返金は承っておりません。

Customer: To hell with this!  I'll buy what I need somewhere else!

ひどいもんだな! 別の店で買うよ。

Agent: I don't think so, sir.  You may be able to buy paint for your bathroom and bedrooms, and your kitchen and dining room from someone else, but you won't be able to paint your connecting hall and stairway from anyone but us.  And I should point out, sir, that if you paint in only one direction, it will be $300 a gallon.

お客様、それは無理でございましょう。お客様が浴室、寝室、ダイニングキッチン用のペンキを他で購入なさることはできるでしょう。 でも、廊下と階段は我々のペンキでしか塗ることができません。 それと、もしお客様が一方向に塗られるのでしたら、1ガロン300ドルになります。

Customer: I thought your most expensive paint was $200!

一番高いのは1ガロン200ドルじゃなかったのかい!

Agent: That's if you paint around the room to the point at which you started.  A hallway is different.

それはお客様が部屋のペンキ塗りを一周してもとの場所に戻ってきた場合でございます。 廊下は別でございます。

Customer: And if I buy $200 paint for the hall, but only paint in one direction, you'll confiscate the remaining paint.

じゃぁ、私が廊下用に200ドルのペンキを買って、一方向に塗ったら、残りは没収されるということかい。

Agent: No, we'll charge you an extra use fee plus the difference on your next gallon of paint.  But I believe you're getting it now, sir.

そうではございません。 割増料金と、もう1ガロン分のペンキ代の差額をいただくのでございます。 でも、お客様はすぐお使いになるのでしょう。

Customer: You're insane!

まったく馬鹿げてる!

Agent: Thanks for painting with AIr Canada..... United...etc.

毎度AIr Canada..... United... etc.ペンキをご利用いただきましてありがとうございます。


私がこのジョークを知ったのは2002年ですが、状況は今も大して変わりないですね...。

ロジアナでいろいろ計測するにあたり、初めてPC-6001(初代)をメイン基板が見えるところまでバラしたのですが、以下のICのみがソケットに挿してあるのですね。

  • 8049
  • 2364 x 2 (BIOS ROM)
  • 2332 (キャラクタROM)

ソフトウェアが入っているもの全てです。いざという時の差し替えを考えていたのでしょう。

BIOS ROMはこんな感じ。24ピンのマスクROM(1個8kB)が2個あります。

PC6001_2364.jpg

キャラクタROMと思われる2332。

PC6001_2332.jpg

それで気付いたのですが、BIOS ROMがソケット挿しになっているということは、ここを交換できるということではありませんか!

8kB/24ピンのEPROMはないと思うので、下駄付きで差し替えになるでしょうが、起動をBASICかSDOSかの手動切り替え、とかできるかもしれません。

MEMWRをちょっとアレすれば、RAMも載せられるかも?

まぁ、そこまでやるとカセットポンの簡便性が失われてしまいますが。


SD(HC)カードでは、ファイルシステムのフォーマットが物理的に制限されているわけではありません。 そのため、FAT16/2GBという規格のSD(SDHCではない)カードに、FAT16の規格を越える4GBサイズのものがありました。また、既存のSD(HC)カードに、規格以外のフォーマットをかけることも可能です。

SDHCが採用しているFAT32の論理上限は2TBなので、ソフト的な観点からは32GBを越えるカードも可能です。 しかし、実際には売られていません。なぜでしょう。

と思っていたら、英語版Wikipediaに情報がありました。


SDカードの仕様では、カードに128ビットのIDが入っています。 HCではないSDカード(仕様1.x)では、このうち12ビットがメモリクラスタの数(1~4,096)、3ビットがクラスタあたりのブロック数(4, 8, 16, 32, 64, 128, 256, 512)を表しています。 SDカード1.xのうち、古い仕様では、ブロックサイズが512バイト固定のため、最大容量は次のように求められます。

4,096(メモリクラスタ数) x 512(ブロック数/クラスタ) x 512(ブロックサイズ) = 1GB
  

より新しい1.xの仕様では、上記のIDフィールドにブロックサイズを表す4ビットの値を持って1,024および2,048バイトをサポートするようになり、1GBを越えるカードをサポートするようになりました。 しかし、これによりデバイスによっては1GBを越えるカードを読めないことも出てきました。 例えば、私の使っていたVodafoneの705SHはmicroSDカードをサポートしていますが、1GBまでのカードしか認識しません。 これなどは、おそらくこの古い仕様が原因ではないかと思います。

さて、SDHC(仕様2.0)では、メモリサイズを22ビットのフィールドで表します。 値は512kBの倍数です。 しかし、現状では22ビットのうち16ビットしか使われていません。 すなわち、フィールドの最大値は65,536となり、

512(kB) x 65,536 = 32GB
  

となります。 これが「32GB上限」のトリックです。

22ビットをフルに使うと、最大値は

512(kB) x 65,536 x 64(追加の6ビット分) = 2,048GB
  

となり、FAT32の論理最大の2TBまでサポートできることがわかります。

(11 Nov. 2008追記) 2TBはデフォルトのクラスタサイズ512バイトの場合です。FAT16のときのようにクラスタサイズを大きくすればさらに大容量化できます。

もちろん今これを行えば、4GBのSDカードのように互換性の問題も抱えることにはなるのですが、規格上はサポート可能にしておきながら、なぜ制限してしまったのでしょうか。

ちなみに、Windows XPが32GBを越えるFAT32のフォーマットを行わないのは、単にマーケティング上の理由です(NTFSに誘導したいため)。SDHCカードが32GB止まりであることとは、おそらく何の関係もありません。SDHCカードにNTFSなんか採用したら最後、激しくMicrosoft縛りがかかるばかりか、アクセスするためのソフトウェア・ファームウェアが複雑になりすぎて実用にならないでしょう。いくらSDカードアソシエーションのメンバにMicrosoftが入っているからといって...ねぇ。

なお、SD(HC)カードおよびホストアダプタを製造販売するには、SDアソシエーションのメンバになる必要があり、メンバに課される年会費は$1,500、加えて製造販売のためのロイヤリティは年$1,000です。まぁ、この手の会費としては格安ともいえます。そのせいか、SDアソシエーションのメンバ企業は非常に多く、「何でこの会社が?」というような企業もメンバに入っています。でも、意地でもソニーは入っていません

SDHCは登場からあっという間に最大容量の32GBに達し、 その32GBのSDHCカードが値下がりし始めています

SSDの代わりとしての利用も期待できるわけですから、早いところ何とかして欲しいものです。


(以下 11 Nov. 2008追記および修正)

FAT32の仕様自体は2TBまでサポートしているのは上記のとおりですが、以下の制限があります。

1ファイルのサイズは4GBまで

これは良く知られていますね。 理由は、ファイルの情報が格納されるディレクトリエントリにある (詳しくはこのページのDirectory Entry参照)ファイルサイズのフィールドが32ビット(4バイト、DWORD)分しかないためです。 FATのクラスタチェインだけを考えれば4GBを越えるファイルを表現することもできますが、ファイルサイズフィールドとの不整合が発生するため、アプリケーション誤動作の原因になりますし、高レベルAPIではエラーになる可能性があります。

容量が大きくなるにつれ、いわゆる「デフラグ」や空きスペースの計算量が極めて大きくなる

FATは、容量が大きくなるとフラグメンテーションが発生しやすいという問題はよく知られていますね。

ではなぜ計算量が大きくなるかというと、FATでは領域がクラスタ単位で管理されているFile Allocation Table(だからFAT)を基にして動作するためです。FAT32では、クラスタごとに32ビット(4バイト)の情報を持っています。

FATの各エントリは、次のクラスタが何番なのか、ファイルの最後なのか、利用されていないのか、不良なのかなどの情報を表しています(リンクリスト)。これが、FAT32では28ビット分まで使われるので、最大容量まで使い切ると228エントリ存在することになり、FAT領域の大きさは

4(バイト/エントリ) x 228(エントリ) = 1GB

という容量になってしまいます。空き容量を計算するために1GBの読み込みを行うのは、FATが主に使われている組み込み分野はおろか、現状のPCでも結構つらい作業でしょう。

これらの解決策として、exFATが提案されていますが、いろいろ技術的な事情(HDDには使えない、Windows XPでも使えない)や大人の事情(ライセンスが不透明、仕様が公開されていない)から、そう簡単には現在のFATの代替にはならないでしょう。


何となく気が向いたので、A Tour of Scalaを翻訳しました。 さらに気が向いたらツアーの内容も訳そうかな...。

ところで先日気にしていたスタックに関してですが、リファレンスを読む限り、tail-recursionはスタックを消費しないようにできているらしいです。


A Tour of Scala

Scalaはモダンでマルチパラダイムなプログラミング言語で、プログラムパターンを簡潔、エレガント、かつ型安全に表現することができます。 オブジェクト指向および関数型言語の機能をスムーズに統合しています。

Scalaはオブジェクト指向

Scalaは全ての値がオブジェクトである、という点において純粋オブジェクト指向言語です。 型とオブジェクトの挙動はclassとtraitで記述されます。 クラスは多重継承の代わりにサブクラスや柔軟なミックスインベースのコンポジションで拡張することができます。

Scalaは関数型

Scalaは全ての関数が値である、という点において関数型言語でもあります。 Scalaは匿名関数を定義するための軽量な構文をもち、高階関数をサポートし、入れ子の関数を書くことができ、カリー化をサポートします。 Scalaのケースクラスとビルトインのパターンマッチングは、多くの関数型言語で使われている代数型をモデル化します。

さらに、Scalaのパターンマッチングの考え方と、right-ignoring sequence patternsを使うことにより、XMLデータを自然に処理することができます。 ここでは、クエリを作るのにsequence comprehensionsが便利です。 これらの機能により、ScalaはWebサービスを作るのに最適な言語となっています。

Scalaは静的型付き

Scalaは安全で一貫性のある抽象化を行うための静的な型システムを持ちます。 特に、型システムは以下をサポートしています。

  • ジェネリッククラス
  • varianceアノテーション
  • 型の上限、下限
  • オブジェクトメンバとしての内部クラスおよび抽象型
  • コンパウンド型
  • 明示型付き自己参照
  • ビュー
  • ポリモーフィックなメソッド

局所型推論機構により、ユーザが冗長な型情報を記述する必要はありません。 これらの機能の組み合わせにより、プログラムの安全な抽象化再利用や型安全な拡張が可能となります。

Scalaは拡張性がある

ドメイン固有のアプリケーションの開発は、しばしばドメイン固有言語(DSL)拡張を必要とします。 Scalaは言語機能のユニークな組み合わせにより、ライブラリによる言語機能の追加を簡単にしています。

  • 任意のメソッドが後置および中置演算子として使用可能
  • 対象型による自動クロージャ生成

これらの利用により、構文拡張やマクロ機能などをしなくても新しい文を定義することができます。

ScalaはJavaおよび.NETと相互利用可能

ScalaはJava 2 Runtime Environmentと相互利用可能です。 特に、Javaとのインタラクションは可能な限りスムーズになっています。 ScalaはJavaと同様なコンパイルモデル(セパレートコンパイル、動的ローディング)を持ち、既存のライブラリにアクセスすることができます。 .NETフレームワーク(CLR)もサポートされています。

  • A Tour of Scala: 抽象型
  • A Tour of Scala: アノテーション
  • A Tour of Scala: クラス
  • A Tour of Scala: ケースクラス
  • A Tour of Scala: classOf定義済関数
  • A Tour of Scala: コンパウンド型
  • A Tour of Scala: Sequence comprehensions
  • A Tour of Scala: Extractorオブジェクト
  • A Tour of Scala: ジェネリッククラス
  • A Tour of Scala: 暗黙パラメータ
  • A Tour of Scala: 内部クラス
  • A Tour of Scala: ミックスインクラスの作成
  • A Tour of Scala: 入れ子関数
  • A Tour of Scala: 匿名関数構文
  • A Tour of Scala: カリー化
  • A Tour of Scala: 自動型依存クロージャ生成
  • A Tour of Scala: 演算子
  • A Tour of Scala: 高階関数
  • A Tour of Scala: パッケージ
  • A Tour of Scala: パターンマッチング
  • A Tour of Scala: ポリモーフィックメソッド
  • A Tour of Scala: 正規表現
  • A Tour of Scala: シールドクラス
  • A Tour of Scala: Traits
  • A Tour of Scala: 型上限制約
  • A Tour of Scala: 型下限制約
  • A Tour of Scala: 明示型付き自己参照
  • A Tour of Scala: サブクラス化
  • A Tour of Scala: 局所型推論
  • A Tour of Scala: 統合型
  • A Tour of Scala: Variances(共変及び反変)
  • A Tour of Scala: ビュー
  • A Tour of Scala: XML処理

PC-6001で垂直同期が取れるのか。

それを調べるため、DMA ON/OFFを繰り返したときにどうなるのか、試してみました。 プログラムは以下のようなものを使いました。 WAITの影響を少なくするため、RAMで動作させます。

	di
loop:
	ld	a, #0x02
	out	(#0x93), a
	call	wait
	ld	a, #0x03
	out	(#0x93), a
	call	wait
	jp	loop	

	;; T-state: 2840(incl. call)
wait:
	ld	hl, #100
wait_loop:
	dec	hl
	ld	a, h
	or	l
	jp	nz, wait_loop
	ret
  

実行の全体像は以下の図のようになります。 記録時間を長くするため、記録周期を粗くしている(1MHz)ので、CLKやM1、WAITは信号ドロップにより不正確です。 気にしないでください。 BUSREQ/BUSACKのみ見てください。

dma1.PNG

この図で、A-B区間は垂直帰線と推測されます。 赤くなっている部分は、H/Lが細かい周期で繰り返されている箇所です。 水平帰線によりH/Lを繰り返しているのでしょう。

dma2.PNG

これは、赤い部分に挟まれた短いHの期間をズームしたものです。 ここはDMA OFFでwaitを実行している部分でしょう。 A-Bの時間(727us)は、DMA OFF時のの論理実行時間(約720us)にきわめて近くなっており、予測は正しそうです。

dma3.PNG

さらに、赤い部分(H/Lが密で、水平帰線を繰り返している部分)のズームです。 本当なら水平線の本数は192本あり、その分のLを繰り返すはずが、ここでは32本分しかありません。 Bの部分でDMA OFFにしているためです。

少なくともここで言えるのは、「ポート0x93のコントロールによるVDGのDMAのON/OFFは垂直帰線に同期しているわけではない」ということです。 残念ながら。

さらに調べると、この計測における一つの水平帰線(BUSACK=L)の時間は40~41usなのですが、DMA ON直後のBUSACK=Lの時間(上図でAから始まるBUSACK=L部分)はそれより短い(21~25usくらい)という結果でした。逆に、DMA OFF直前のBUSACK=Lの時間(上図Bで終わる部分)は41usになっています。垂直帰線によるBUSACK=Hが終わった直後のBUSACK=L(最初の図のBの直後)もおよそ41usです。すなわち、DMA OFFからONにした直後のみDMAが占有する時間が少ないことになります。

これが何を意味するのかはまだよくわかりません。

もう少し考察が必要ですね。また、何か別の方法も考えねば...。

Scalaメモ

| | コメント(0) | トラックバック(0)

ちょっと最近気になる関数型言語、Scalaのメモ。

Overview

Scalaは、Javaとの親和性が高い静的型付き関数型言語で、2001年から開発されています。 開発元はこちらです。

関数型かつ純粋オブジェクト指向なので、Javaで苦手(不可能)とする以下のようなことをサポートしています。

  • プリミティブ型および関数のオブジェクトとしての扱い
  • staticの排除(代わりにシングルトンオブジェクトのネイティブサポート)
  • カリー化(currying)および高階関数(higher-order function)
  • 型推論機構
  • 遅延評価
  • trait (一種のmix-in)
    Javaのinterfaceに近いのですが、実装を持つことができます。
  • すべての識別子の中間演算子としての使用(a.func(b)はa func bと同じ、a + bはa.+(b)と同じ)
  • (配列とは異なる)リストのサポート
    配列とは、リストはimmutable(変更できない)、再帰的(内部にリストを含められる)、Lispのリストのようにさまざまなオペレーションがある、という点で違いがあります。
  • XML構文をサポート(プログラムの一部としてXMLが記述できる)
    たとえば、XMLを返す次のような関数が定義できます(インデントは見やすくするため)。 関数型言語なので、実行時の最後の評価値が返り値になり、明示的にreturnを使う必要はありません。
    def elm(attr: Any, content: Any) = {
      <data attr="{attr.toString}">
        {content}
      </data>
    }
    

これらの特徴により、プログラムをJavaにそっくりに書くこともできれば、関数型ばりばりのフォーマットで書くこともできます。Javaとのインタラクションを言語レベルでサポートしているので、Javaのプログラムをそのまま呼び出すことも可能です。 また、genericsなどJava 1.5+でサポートされた(無理のある)syntactic sugarが自然に書けるのもいいところです。


業務アプリへの適用可能性

関数型言語はある種の問題に対して非常にソリューションを書きやすいのですが、OCamlやHaskellなど、いままで業務の世界などであまり成功しているとはいえません。 その理由は、

  • 業務の世界は保守的なので新しい言語などの導入には慎重
  • 業務上、関数型のソリューションを必要とする場面が少ない

といったところでしょうか。

たとえば、RubyもRuby on Railsでそれなりの支持を得ていますが、メインストリームといえるほどの盛り上がりにはなっていないと思います。

Scalaの場合、Javaをネイティブサポートしていたり、普通に手続き型風にコードを書くことも可能だったり(構文も似ている)、結構気を使っている気がします。 ライセンスもBSDスタイルなので、それほど神経質になる必要がありません。

Javaのサポートについては、そもそもScalaプログラムをコンパイルすると、Javaのクラスになり、Scalaのライブラリを使って実行するようになっています。 加えて、Javaに「あったらいいな」と思える機能があるので、なかなか使えそうな気はします。

個人的には、プリミティブや関数をfirst class objectにしたり、高階関数が使えたりするのはとても便利です。JavaScriptでもできますし。 それと、静的型付け言語でコンパイル時に型チェックが行われるというのが、業務アプリの世界ではなじみやすいかもしれません。 RubyやJavaScriptなどの動的型付け言語は便利ですが、検証やテストが大変なので。


気になる点

ちょっと気になるのは、関数型言語の特徴を生かして書きたい場合、処理を再帰で書くことが多いのですが、メモリ効率や実行効率がどうなるかです。 たとえば、次のような例があります。

整数aとb(a <= b)の間の数の総和を求める。

def sumInts(a: Int, b: Int): Int = if (a > b) 0 else a + sumInts(a + 1, b)
  

この関数sumIntsは、aとbの差が大きければ再帰しまくるので、スタックを使っているとすればあっという間にあふれてしまいます。 tail recursionくらいは展開しているかもしれませんが...。

次は、クイックソートの例です。

def sort(xs: Array[Int]): Array[Int] =
  if (xs.length <= 1) xs
  else {
    val pivot = xs(xs.length / 2)
    Array.concat(
      sort(xs filter (pivot >)),
           xs filter (pivot ==),
      sort(xs filter (pivot <)))
  }
  

返り値の配列は引数とは異なるので、元の配列を保存する必要がない場合、余計にメモリを必要とします。 まぁ、これらが問題になるような場合には手続き的に書くことも可能なのですが。


開発環境

開発環境に関しては、Eclipseのプラグインが公開されており、Javaと同じような感覚で開発ができます。

Scalaの実行形式はJavaのバイトコードなので、デバッガを使うと、Scalaプログラム(ライブラリ含む)とJavaの間を行ったりきたりしながら実行されます。 Scalaで書かれた部分はScalaのコードとして表示されるため、きわめてシームレスなデバッグが可能です。


いずれにしても、これからどのようになっていくか、ちょっと楽しみです。

Back to the Future IIではデロリアンが空を飛びますが、あれから20年余りで実現に向かっているようです。

英紙Dailymailによると、Autovolantor(auto-volant-or: 飛行可能な車)と呼ばれる空飛ぶ車が開発されているそうです。ベース車は£200,000のフェラーリ599GTBで、改造後の価格は£500,000。

胴体にマウントされた8つのファンにより、空に浮かぶことができます。原理的にはVTOLに近そうです。

現時点では、開発はまだかなり初期段階です。さらに、開発者によると技術的には可能でも政治的な問題で実用化までは壁があるとのこと。まぁ、当然ですね。

また、一回の給油で「飛行」できる距離は75マイルと長くなく、あくまで渋滞を避ける程度の使い方になりそうです。

アイデアから考えると、「羽根」の必要性はあまり感じられないような。それよりデロリアンみたいにホイール部分からエアーを噴き出してしてくれればいいのに。

ロジアナが手に入り、CPUの詳細な動作状態がわかるようになったので、動画と音声の同時再生の可能性について検討してみたいと思います。 


計測結果とその妥当性

まず、計測から得られた情報です。 以下は、VDGによる1ライン分のBUSREQ/BUSACKのタイミングを取ったものです。


busack3.PNG
  BUSACK=LBUSACK=H
水平帰線40.16us 22.64us
垂直帰線  4482.32us


BUSACK=Lのときは、MC6847(VDG)からのDMAが動作していて、CPUは完全に停止しています。 多少測定誤差がありますが、Techknowの数値(1ライン=63.5us)とほぼ符合します(図では62.8usと出ています)。 一画面分(192ライン)、1秒60フレームとして逆算すると、

(1,000,000 / 60) - (63.5 x 192) = 4,474.67us
  

となり、垂直帰線の数値もほぼ符合しています。

1画面の描画の間で使える時間は、おおよそですが以下のとおりです。

1水平線: 40us ≒ 160 T-states
1垂直線: 4474.67us ≒ 17870 T-states
1画面分: 40us x 192 + 4474.67us ≒ 48,541 T-states
  

T-stateの計算にクロック(3.993600MHz)を使っています。 丸め誤差が発生していますが、ここではとりあえず置いておきます。


1画面描画にかけられる時間

以上から、1画面にかけられるのはおおよそ48,500 T-statesとなります。 128x96ドットのモードの場合は、VRAMの容量は1,536バイト。 以前ムービープレイヤーを最適化していたときに計算したT-statesの平均値が37,000ほどだったのですが、この数値はWAITを入れていません。 すべて1バイト命令であるという単純な仮定で計算しなおすと、

37,000 x (5 / 4) = 46,250 T-states
    

となり、けっこうぎりぎりです。 ただし、これには2msecのクロック割り込みの時間なども入っています。 圧縮も何も考えずに単に1,536バイトのldirを行うとすると、WAITを考慮して33,787 T-statesです。 セットアップやらいろいろ考えても何とかなりそうですね。

256x192ドットのモードの場合は、VRAMの容量は6,144バイト。 以前のムービープレイヤーでは142,000 T-states (WAIT考慮なし、クロック割り込み時間込み)でした。 WAITを考慮したldirのみの実行時間でも135,163 T-statesです。 話になりません。


もっとも、これは秒間60フレームの描画を前提にした計算ですから、以前のように秒間15フレームにすれば4倍の時間、およそ185,000 T-statesかけられるということです。 処理のタイミング合わせは複雑になりそうですが。 128x96ドットなら音声も含めて再生が期待できそうです。


水平帰線期間中の処理の可能性

水平帰線期間中に1ライン分描画できるでしょうか。

128x96ドットのモードを使うとすると、縦1ドットに対して2水平線分の時間を割くことができますから、320 T-statesとなります。 これなら128ドット分(16bytes)の転送と音声の発声が何とかなるかもしれません。

ちなみに、256x192ドットのモードだと、160 T-statesで256ドット分(32 bytes)の転送となり、画像だけで5 T-state/byteしかかけられません。 M1ステート時のWAITを考慮すると、転送系最速のpush/popを使っても12/11 T-statesかかるため、この時点でアウトです。

ただ、PC-6001の場合は垂直帰線時間で描画しても問題ないので、それほど深刻ではないかもしれません。


問題点

さて、ここで以下の問題があります。

  1. RAM空間ではM1ステートで1クロックのウェイトが入ります(調査の結果、ROM空間ではアクセスのたびに1クロックWAITが入ります)。 また、CB/DD/ED/FD prefixを持つ命令や、IN/OUT系ではさらにそれぞれ1クロックづつWAITが入ります。 これらを考慮して設計する必要があります。
  2. VDPが画面を描画中のときは、CPUがVRAMにアクセスしたら停止するわけではなく、完全停止です。 そのため、MC6847が描画中に表示データのセットアップをすることができません。
  3. 垂直・水平帰線期間中であることを検出する術がありません。 特に垂直帰線時に行う処理のタイミングが計れないので、致命的かもしれません。

以上は通常、他機種では問題の出ない部分でしょう。 例えば、MZ-700では上記の2, 3を活用しています。

3.を何とかすることはできるのでしょうかね? BUSACKは拡張ポートにも出ていないため、信号変化をトリガーに割り込みをかけるのも、本体に手を入れない限り難しそうです。


これまで、VDGのタイミングが全くわからなかったため、盲目状態で行っていたタイミング計算がだいぶ正確に把握できるようになってきました。ロジアナって便利ですね...。

ただ、タイミングあわせについてはもう少し調査が必要です...。


カメレオンUSBのロジアナを買ったので、さっそくWAIT信号について調査しました。

用意したプローブ(=ただのICピン)が足りず、アドレス線は10ビットしか取れていませんが、どこを実行しているかはわかります。

計測したのは、起動後に"How Many Pages?"と表示され、入力待ちになっている状態です。ROM内を実行していることになります。 

0xfbf-call.png

この画面で青い線で区切られたA-Bの区間は、0x0fbfを実行しています(ADは10ビットのみ表示されていることに注意)。 この部分のアセンブリ表現は次のようになります。

0FBF CDFF0F    CALL    $0FFF

すなわち、3バイト命令のCALLを実行していて、M1ステートの0xfbfで2回、 続く0xfc0, 0xfc1の読み込みでそれぞれ2回ずつWAITが入っていることがわかります。 そして次の命令が0x0fffから始まっていることが読み取れます。

もう少し詳しくアドレス線を読み解くと、まず0xfbf(0x3bf)からオペコードを読込み、次にリフレッシュアドレス0x45(0x245)を送出します。M2サイクルでは0xfc0(0x3c0)、M3サイクルで0xfc1(0x3c1)からそれぞれオペランドを読込みます。これはCALL命令なので、PCの2バイトをスタックにプッシュ(0x0eb, 0x0ea)しています。その後、次の命令である0xfff(0x3ff)に飛びます。

クロックを見ると、本来17クロックのCALLに20クロックかかっています。 どうやら2バイト目と3バイト目を読み込む際のWAITは1クロックずつで、 各マシンサイクルでの2回目のWAITは実際には入っていないようです。

次に実行する命令を見てみます。

0FFF 2130FA    LD      HL,$FA30

0xfff-ld.png

この命令では、本来10クロックのところが13クロックかかっていて、やはりM1だけでなく、2バイト目、3バイト目の読み込みにも1クロックずつWAITがかかっています。

以上のことより、ROMからの読み出しのときは、常に1クロックずつWAITが入ることがわかります。 PC-6001のROMに使われているuPD2364のアクセス性能は製品により異なりますが、300/350/450nsです。 450ns品を使っているとすればまぁ納得のいく仕様でしょう。

このアーカイブについて

このページには、November 2008に書かれたブログ記事が新しい順に公開されています。

前のアーカイブはOctober 2008です。

次のアーカイブはDecember 2008です。

最近のコンテンツ アーカイブ