コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2014年5月30日 >>> 2014年5月17日
link もっと後

2014年5月30日

自作エミュレータ - ワード幅とハーフワード読み出し

目次: Linux

RISC CPUにはワード幅での読み書きしかできないアーキテクチャがありますが、より狭いハーフワードやバイトへのアクセスってどうしているのでしょう?

単純に考えると、ひとまず近しいアドレスからワード幅で読み出して、しかるべきシフト演算を行うことで、目的のハーフワードやバイトデータを得ていそうです。

例えば、ワード幅64bits、読みたいデータ幅16bits、アクセス先のアドレスが0x12として考えてみます。

まず、データバスにはアドレス0x12ではアクセスできませんので、ひとまず0x12を超えない最大の8の倍数(64bits = 8bytes)であるアドレス0x10から64bitsを読み出します。

このときバスから読み出したデータが0x1234_5678_0246_8aceだとして、バスから読み出したデータを読みたいデータ幅(= 16bits)ごとに分割し、符号ビットから近い順から並べると、


0x1234:
0x5678:
0x0246:
0x8ace:

となります。

リトルエンディアンシステムの場合、データの上位から、アドレス+6、アドレス+4、アドレス+2、アドレスそのもの、に対応しますので、


0x1234: アドレス+6 = 0x16
0x5678: アドレス+4 = 0x14
0x0246: アドレス+2 = 0x12
0x8ace: アドレスそのもの = 0x10

と対応します。

従って目的のアドレス0x12にあるデータは0x0246であることがわかり、バスから読み出したデータをシフトすべき量は16bitsであることがわかります。

同様にアドレス0x14ならばデータは0x5678となり、シフトすべき量は32bitsです。

コードでどうぞ

このような処理をいちいち考えていると面倒で死にそうなので、コードで書いてみることにしました。

バスから読んだデータから対応するアドレスのデータを得る関数(リトルエンディアン)

public static long ADDR_MASK_64 = ~0x7L;
public static long ADDR_MASK_32 = ~0x3L;
public static long ADDR_MASK_16 = ~0x1L;
public static long ADDR_MASK_8 = ~0x0L;

/**
 * @param dataLenデータ幅
 * @returnアドレスマスク
 */
public long getAddressMask(int dataLen) {
    switch (dataLen) {
    case 64:
        return ADDR_MASK_64;
    case 32:
        return ADDR_MASK_32;
    case 16:
        return ADDR_MASK_16;
    case 8:
        return ADDR_MASK_8;
    default:
        throw new IllegalArgumentException("Data length" +
                String.format("(0x%08x) is not supported.", dataLen));
    }
}

/*
 * @param addr     データのアドレス
 * @param data     バスから読んだデータ
 * @param busLen   データバス幅
 * @param dataLen  データ幅
 * @return addrにあるデータ
 */
public long readMasked(long addr, long data, int busLen, int dataLen) {
    long busMask = getAddressMask(busLen);
    long dataMask = getAddressMask(dataLen);
    int sh = (int)(addr & ~busMask & dataMask) * 8;

    return data >> sh;
}

ふっざけんなー!意味がわからんわー!!と叫んでいる半年後の自分が見えたので、併せて解説も書いておきます。

バスから読み出したデータをシフトする量を求める部分がaddr & ~busMask & dataMask * 8の部分です。

まずaddr & ~busMaskですが、バス幅で割った余りのアドレスを求めています。
例えば、幅が64bitsでアドレスが0x12ならば、8で割った余りのアドレス0x02を求めています。

次にaddr & ~busMask & dataMaskですが、データ幅境界にアドレスを揃えています。この意味と必要性の議論は後述します。
例えばデータ幅が16bitsならば、アドレスを2の倍数にします。アドレス0x01なら0x00、アドレス0x02なら0x02、アドレス0x03なら0x02です。


アドレスからビットシフト量へ

残りの処理はアドレスに8を掛けて右ビットシフトしています。関数の返値は上位に余計なデータが残っていますので、返り値を受け取った人は、余計な上位のデータを捨てる必要があります。


バス幅からデータ幅へ

呼び出す側のコードは、こんな感じです。

呼び出し側の例

//データバス幅
public static int BITS_DATA_BUS = 64;

public byte read8(long addr) {
    return (byte)readMasked(addr, readWord(addr), BITS_DATA_BUS, 8);
}

public short read16(long addr) {
    return (short)readMasked(addr, readWord(addr), BITS_DATA_BUS, 16);
}

public int read32(long addr) {
    return (int)readMasked(addr, readWord(addr), BITS_DATA_BUS, 32);
}

他のアドレスが渡される場合も同様です。


アドレス0x12から読む場合


アドレス0x16から読む場合

他のバス幅、他のビット幅でも同じ考え方で処理可能です。


他のデータ幅の例

データ幅の境界にアドレスを揃える意味

データ幅境界以外からデータを読んで良い、つまり0x13から読んだときに0x0246ではなくて、0x7802を返せるシステムならば、& dataMaskは不要です。


アドレス0x13から読む場合

この方が便利ですが良いことばかりでもなく、バス幅をまたぐ際の読み出し、例えば0x17から16bits読む際の処理が必要になります。


アドレス0x17から読むときの問題点

しかし前述のコードではバス幅の境界をまたぐ読み出し方に対応できませんから、データ幅境界以外からデータを読めないようにして、異常動作しないように防いでいます。

編集者:すずき(2024/03/05 02:43)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2014年5月25日

企業も生きている

企業の生涯を追うと、若い時は素早くて何でもチャレンジするけれど、時が経つと緩慢で億劫になって何もしなくなり、やがて体が動かなくなって息絶えるんです。

なんか、企業と生き物って似ているなーと思ったら、色々浮かんできました。

不採算部門のレイオフ
内臓切るような外科手術、あるいはスタンガンですかね。体力が激減するし、調子に乗って何度もやればショック死です。
税金での救済
死体のゾンビ改造術のようなもん?ゾンビは周りにいる健康な人を襲うため、市場に悪影響が出る、ってな感じです。

メモ: 技術系の話はFacebookから転記しておくことにした。

編集者:すずき(2015/11/29 19:47)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2014年5月24日

はじまりとおわり

国道には○○号線、と番号が振られていて、重なっている区間もあります。中には始点や終点が別の国道と重なっている場合もあります。

じゃあ、国道の始まりと終わりは誰が決めるのか?と疑問に思い調べてみると、道路法に基づいた「一般国道の路線を指定する政令」(昭和四十年三月二十九日政令第五十八号)という政令で決められているそうです。

道路法といい、政令といい、何の捻りもないストレートな名前です。わかりやすいのでありがたくもあり、あまりにあっさり見つかったのでやや物足りなくもあり。うーん…。

試しに一つ調べてみる

我が家からもっとも近い国道はR171です。試しにR171について調べてみましょう。

先の政令58号によれば、国道171号線の起点は京都市、終点は神戸市です。重要な経過地は、向日市、長岡京市、京都府乙訓郡大山崎町、高槻市、茨木市、箕面市、池田市、伊丹市、尼崎市、西宮市(河原町)、芦屋市(清水町)です。

あれ?これだけ?どうも政令58号では具体的な位置(交差点名、何号線に吸収される、など)は言及していないようです。

詳細な位置

道路整備促進期成同盟会全国協議会が発行していた「道路時刻表」によると、道路を走行した際の所要時間の概算値を見ることができます。

走行時間の付属情報として、始点、主な交差点(と交差する道)、終点も書いてあるため、どこで何の道が重なっているかがわかります。本来の用途と異なる使い方ですが、この際わかれば何でも良いのです。

が、しかし道路時刻表は2008年で絶版とのこと。うーん、最新の情報はどこにあるんですかねえ…。

編集者:すずき(2014/05/24 19:02)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2014年5月30日 >>> 2014年5月17日
link もっと後

管理用メニュー

link 記事を新規作成

<2014>
<<<05>>>
----123
45678910
11121314151617
18192021222324
25262728293031

最近のコメント5件

  • link 25年12月18日
    すずきさん (12/23 23:51)
    「良く見たらksys_read()でfil...」
  • link 25年12月18日
    すずきさん (12/23 23:15)
    「ですね、まあpread+readだと話が...」
  • link 25年12月18日
    hdkさん (12/21 08:34)
    「昔試しにデバイスドライバーを作ったことが...」
  • link 25年11月28日
    hdkさん (12/04 08:10)
    「あれ、停止直前くらいの時のトルクコンバー...」
  • link 25年11月28日
    すずきさん (12/03 11:24)
    「トルクコンバーターがいてエンブレは掛かり...」

最近の記事20件

  • link 25年12月26日
    すずき (12/30 14:01)
    「[Linuxのjournal操作メモ] 目次: Linux最近のLinuxディストリビューションはsystemdを採用している...」
  • link 23年4月10日
    すずき (12/29 23:24)
    「[Linux - まとめリンク] 目次: Linuxカーネル、ドライバ関連。Linux kernel 2.4 for ARMが...」
  • link 25年12月22日
    すずき (12/28 23:39)
    「[ゲームを買ったら遊びましょう3] 目次: ゲーム前回の振り返り(2024年10月20日の日記参照)から1年経ちました。所持し...」
  • link 21年12月28日
    すずき (12/25 00:40)
    「[ゲーム - まとめリンク] 目次: ゲームNintendo DSを買ったパネルでポンDS最近の朝はパネポンDS聖剣伝説DSチ...」
  • link 08年3月25日
    すずき (12/24 22:16)
    「[シムシティDS2クリア] 目次: ゲームシムシティDS2のチャレンジモード「現代 温暖化」編をクリアして、スタッフロールを拝...」
  • link 25年12月10日
    すずき (12/24 01:02)
    「[LinuxからBIOS/UEFIの設定を取得する] 目次: Linux設定によって何か動作を変えたい、PC再起動するのが嫌な...」
  • link 25年12月16日
    すずき (12/24 00:47)
    「[initramfsの更新方法] 目次: Linuxいつも忘れてググっている気がするのでメモしておきます。Linuxカーネルを...」
  • link 16年3月2日
    すずき (12/24 00:37)
    「[Device Treeの謎] 目次: LinuxDevice Treeを使ってARM Linuxを起動したとき、どうやってコ...」
  • link 25年12月19日
    すずき (12/21 00:11)
    「[preadとlseek + readは何が違う?] 目次: Linux前回(2025年12月18日の日記参照)はpreadと...」
  • link 25年12月8日
    すずき (12/20 21:48)
    「[LXPanelのボタン入れ替えが使えないときの直し方] 目次: LinuxLXDEにはLXPanelといってタスクバーやスタ...」
  • link 25年12月18日
    すずき (12/20 19:11)
    「[preadとlseek + readは違います] 目次: Linux知っている人には「なんだそんなことか」で終わりな話なんで...」
  • link 25年12月11日
    すずき (12/19 23:59)
    「[Ubuntuのカーネルパニック画面] 目次: LinuxUbuntu 24.04 LTSで起動中にカーネルパニックを起こすと...」
  • link 22年4月13日
    すずき (12/19 10:49)
    「[C言語とlibc - まとめリンク] 目次: C言語とlibcC言語について。C++言語もたまに。プログラムの落とし穴、演算...」
  • link 16年1月25日
    すずき (12/19 10:48)
    「[紆余曲折だったC++11のoverrideとfinal] 目次: C言語とlibc最近cpprefjp(リンクはこちら)のコ...」
  • link 16年1月8日
    すずき (12/19 10:48)
    「[C, C++の可変引数マクロでのつまづきとGNU拡張構文] 目次: C言語とlibcC99, C++11の可変引数マクロでは...」
  • link 13年8月11日
    すずき (12/19 10:47)
    「[C++とPythonのクラスと動的型付け] 目次: C言語とlibc初めて触れたオブジェクト指向言語がC++で、その次がJa...」
  • link 23年9月11日
    すずき (12/19 10:42)
    「[Windows - まとめリンク] 目次: WindowsWindows XPのブリッジ機能colinuxとWindowsの...」
  • link 08年9月10日
    すずき (12/19 10:42)
    「[Windows PCの容量が足りません] 目次: Windows最近Windowsの入っているパーティション(Cドライブ)の...」
  • link 08年9月11日
    すずき (12/19 10:41)
    「[Windows XPを再インストール] 目次: WindowsCドライブを35GBに切り直してWindows XPを再インス...」
  • link 22年8月16日
    すずき (12/19 10:39)
    「[このWindows PCはN年経過しています] 目次: Windowsゲーム用PCにWindows 10をインストールしまし...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 2025年
open/close 2026年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www2.katsuster.net
RDFファイル RSS 1.0

最終更新: 12/30 14:01