ぐだぐだ低レベルプログラミング(210)x86(16bit)、LOCKプリフィクス

Joseph Halfmoon

遥か半世紀を遡る8088/8086の時代からx86はマルチプロセッサに対応しとります。そのお印がLOCKプリフィックスです。LOCK自体はエミュレータ上でも使い放題ですが意味なし。その動作をシミジミ味わうには、マルチ・プロセッサに対応したインテル・マルチバスシステムなどが必要。そんなもの無いぞなもし。

※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら

※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。

    •  Windows 11 PC (i5-1235U)
    •  Ubuntu 24.04 LTS on WSL2
    •  QEMU 8.2.2
    •  FreeDOS 1.3

今回は、動作確認すべきコードも無いんですけど。。。

8088、8086のバスモード

その登場の最初から、x86はマルチプロセッサシステムを意識していたのであります。その証拠がMN/MX#というバスモード制御端子です。busLOCK_EC

この端子をLOWに落とせばMaximumモード、HIGHならMinimumモードということになります。

Minimumモードは、シングル・プロセッサの8086、8088システム用の動作モードです。このモード下では、CPUチップがALE(アドレス・ラッチ・イネーブル)やWR#(ライト)、HLDA(ホールド・アクノリッジ)、INTA#(インタラプト・アクノレッジ)等々のバス制御信号を自ら制御します。このモードの場合、バス上にDMAコントローラなどのCPU以外のバスマスタを共存することは想定されてますが、複数のCPU自体を共存させることは想定されてません。

一方、Maximumモードは、マルチ・プロセッサ用の動作モードです。CPUは直接、バス制御信号を出すことはなく、入出力するのはステータス信号などです。外部のバス・アービターで、複数のプロセッサから到来するバス要求を塩梅して、競合しないようにバスのアクセス権を調整し、メモリなりIOなりにつなげることになります。

バスLOCK信号

さて、マルチCPU用のMaximumモードでだけ出力される信号がLOCK#(#はLOWアクティブの意味です)です。この信号が出力されたら、バスをLOCKし、LOCK中の一連のバスサイクルの間、他の人にメモリを触らせないでね、という要求を示す信号です。この信号自体はあくまでCPUからたれ流されるだけの信号なので、実際にどうするかは外部のバスアービター次第です。通常は

一体にして不可分のRead modify write操作

が実現されるようにバスアービターが実装されている筈。

LOCKプリフィックス

オペコード 0xF0 のプリフィックスがLOCKプリフィックスです。プリフィックスなので、テキトーにいろいろな命令の前に置くことができます。その効果は引き続く1命令の間、LOCK#信号をアサートする、というものです。ただし、バスがMaximumモードかどうか、あるいはLOCKがついている命令がLOCK本来の目的(プロセッサ間同期)のための命令かどうかなどは知ったことではないようです。MinimumモードでLOCKをつけてもLOCK#信号そのものが存在しないので意味なしです。ただし、LOCK実行分のサイクル数は消費するし、内部のロジック的にはバスホールド要求に対する反応が鈍くなったりする副作用はついてくるみたいっす。

LOCK XCHG

通常、8088/8086のマルチプロセッサシステムでのLOCKの使用方法としては、「XCHG メモリ、レジスタ」という命令に付加するというのがフツーの使い方であるようです。

「XCHG メモリ、レジスタ」という命令は、該当のメモリの旧値を読み出し、レジスタの内容を該当のメモリの新値として上書きし、読み出したメモリの旧値をレジスタに残すというRead Modify Write操作を行います。「該当のメモリ」というのがまさにセマフォとなります。セマフォを読み出し、セマフォに「使っているよ」という新値を書き込み、読み出したセマフォの旧値が「使ってません」ならば、クリティカルな部分へのアクセス権ゲット!ということでアクセスします。しかし、旧値が「使っているよ」ならば誰かが既に使用中なので、自らは制御権は得られなかったということで「また今度」となります。

さて、この旧値の読み取りと新値の書き込みの間に他所の人も制御権をゲットするために読み取りしたり書き込みできたりすると、この制御方法は崩れます。つまり、旧値の読み取りと新値の書き込みの間だけ、他の人のアクセスを排除しバスに鍵かけておく、のがLOCKの役割です。無暗とLOCKするとバスの権利の調整が不調に終わるので効率落ちる筈。LOCKプリフィックス自体は後続の1命令にのみ有効なので、Read Modify Write操作を行う命令のみに意味があります。

より近代的な同期命令もいろいろあるけど

マルチプロセッサに精通された姉貴兄貴の皆さまはよーくご存じのとおり、他にもいろいろプロセッサ間同期の方法はあります。そして、それに適したモダーンな命令を持つ近代的なプロセッサも今では多いです。しかし、半世紀ほど前に最初のx86である8086、8088が登場したときは、XCHG命令にLOCKつける、というのがその時代の標準的なセマフォの実装だったみたい。

今回のところはそういうことで(どういうことだ?)

ぐだぐだ低レベルプログラミング(209)x86(16bit)、INTOとINT へ戻る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です