目次

ニュース

日記カテゴリ

書庫

2008年5月7日

そういえば、公開していなかったことに気が付きました。

こちらです。

 http://twitter.com/udonge

たまに更新しますので、お気軽にFollowしてくださいませ。

posted @ 9:40 | Feedback (3)

2008年3月27日

CPUID命令を使って、CPUの情報をプログラムで探ってみましょう。

もちろん、アセンブラ命令はCPUIDを使います。ちなみにここで扱うのはIntelCPUです。

CPUIDって命令がたくさん使える上に、動作の種類が大量にあるので、ファンクション0(ベンダー文字列の取得)と、ファンクション1(CPU情報の取得)をやってみます。

CPUIDは、EAXに命令を入れて、cpuidを実行することで、eax, ebx, ecx, edxレジスタにそれぞれ情報が返ってきます。

まず、ファンクション0。

mov eax, 0

cpuid

上記の命令を実行すると、ASCII文字列で、GenuireIntelという文字が返ってきます。(ソース参照)

 

次にファンクション1です。

mov eax, 1

cpuid

この命令を実行することで、EAXにプロセッサシグネチャ、EBXにファンクションフラグ、ECXにFeatureFlag2, EDXにFeatureFlag1が返ってきます。

プロセッサシグネチャの内部構成は次の通りです。

プロセッサシグネチャ

Bit 0~3: Stepping ID

Bit 4~7: Model Number

Bit 8~11: Family Code

Bit 12~13: Processor Type

Bit 14~15: Reserved

Bit 16~19: Extended Model

Bit 20~27: Extended Family

Bit 28~31: Reserved

このうち、Model NumderとFamily Codeの組み合わせでCPUを判断することができます。

(厳密にはProcessor TypeでOverdriveがあったり、Extended Modelでさらに分岐があったりしますが)

ファンクションフラグは、通信用語の基礎知識を見ると以下の通りのようです。

Bit 31~24: APIC ID

Bit 23~16: 論理CPU数

Bit 15~8: CLFLUSH

Bit 7~0: ブランドID

Feature Flag1および2については、CPUにSSEやHTTなどの機能が存在するかかどうかをCPUのフラグで判別できます。

ここでは長くなるので、割愛さしてもらいますが・・・。

詳しくは、こちらから。http://download.intel.com/design/processor/applnots/24161832.pdf

 

ということで、ここではプロセッサシグネチャについて、実際にプログラムで確認してみます。

コンパイラーはVisual C++ 9.0 Express Editionです。

001 #include "stdafx.h"
002 #include <iostream>
003 
004 int _tmain(int argc, _TCHAR* argv[])
005 {
006     typedef unsigned int DWORD;
007 
008     struct _cpumatrix {
009         unsigned char cpu_code;
010         std::string desc;
011     } cpumatrix[] = 
012     { 
013         // CPUのマトリックステーブル。左側にFamilyCode, ModelNumberと右側にCPUの文字列を対応づけます。
014         { 0x40, "Intel486 DX processor"},
015         { 0x41, "Intel486 DX processor"},
016         { 0x43, "IntelDX2 processor"},
017         { 0x44, "Intel486 SL processor"},
018         { 0x45, "IntelSX2 processors"},
019         { 0x47, "Write-Back Enhanced IntelDX2 processors"},
020         { 0x48, "IntelDX4 processor"},
021         { 0x51, "Pentium processors(60,66)"},
022         { 0x52, "Pentium Processors(75,90,100,120,133,150,166,200)"},
023         { 0x54, "Pentium processor with MMX technology(166,200)"},
024         { 0x61, "Pentium Pro processor"},
025         { 0x63, "Pentium II processor, model03"},
026         { 0x65, "Pentium II processor, model05, PentiumII Xeon processor, Intel Celeron processor"},
027         { 0x66, "Celeron processor, model06"},
028         { 0x67, "Pentium III processor, model07, and Pentium III Xeon processor, model07"},
029         { 0x68, "Pentium III processor, model 08,Pentium III Xeon processor, model 08,and Celeron processor, model 08"},
030         { 0x69, "Intel Pentium M processor, Intel Celeron M processor model 09"},
031         { 0x6A, "Pentium III Xeon processor, model0Ah"},
032         { 0x6B, "Pentium III processor, model 0Bh"},
033         { 0x6D, "Intel Pentium M processor,90 nm process."},
034         { 0x6E, "Intel Core Duo processor, 65 nm process."},
035         { 0x6F, "Intel Core2 Duo processor, 65 nm process."},
036         { 0xF0, "Pentium 4 processor."},
037         { 0xF1, "Pentium 4 Processor 0.18um process."},
038         { 0xF2, "Pentium 4 Processor 0.13um process."},
039         { 0xF3, "Pentium 4 Processor, Celeron D Processor"},
040         { 0xF4, "Pentium 4 Processor, Pentium D Processor 90nm process"},
041         { 0xF6, "Pentium 4 Processor, Pentium D Processor 65nm process"},
042         { 0x00, "unknown processor"}
043     };
044 
045 
046     // ベンダーIDのチェック
047     char vender_sig[13];
048     __asm {
049         mov eax, 0;                                /* EAXに0を入れる */
050         cpuid;                                    /* CPUID実行 */
051         mov dword ptr [vender_sig + 0], ebx;    /* 最初の4文字 */
052         mov dword ptr [vender_sig + 4], edx;    /* 次の4文字 */
053         mov dword ptr [vender_sig + 8], ecx;    /* 最後の4文字 */
054         mov byte ptr [vender_sig + 12], 0;        /* ラストに \0 */
055     }
056 
057     std::cout << "Vender String = " << vender_sig << std::endl;
058 
059 
060     // プロセッサシグネチャ, ファクションフラグ、Featureフラグのチェック
061     DWORD prosessor_sig, function_flag, feature_flag2, feature_flag1;
062     __asm {
063         mov eax, 1;                        /* EAXに1を入れる */
064         cpuid;                            /* CPUID実行 */
065         mov dword ptr [prosessor_sig], eax;    /* プロセッサシグネチャ */
066         mov dword ptr [function_flag], ebx;    /* ファンクションフラグ */
067         mov dword ptr [feature_flag2], ecx;    /* Featureフラグ */
068         mov dword ptr [feature_flag1], edx;    /* Featureフラグ */
069     }
070 
071     // ステッピングID, モデルナンバー, ファミリーコード, プロセッサタイプ
072     DWORD SteppingID, ModelNumder, FamilyCode, ProcessorType;
073     SteppingID =   prosessor_sig & 0x0000000F;
074     ModelNumder =   ( prosessor_sig & 0x000000F0 ) >> 4;
075     FamilyCode =    ( prosessor_sig  & 0x00000F00 ) >> 8;
076     ProcessorType = ( prosessor_sig & 0x000003000 ) >> 12;
077 
078     // マトリックステーブルから一致する文字列を探します。
079     std::string cpustring = "unknown processor";
080     for ( int i = 0 ; ( cpumatrix[i].cpu_code != 0x00 ) ; i++ ) {
081         if ( ( FamilyCode << 4 ) + ModelNumder == cpumatrix[i].cpu_code ) {
082             cpustring = cpumatrix[i].desc;
083         }
084     }
085 
086     std::cout << "ProcessorType = " << ProcessorType << std::endl;
087     std::cout << "SteppingID = " << SteppingID << std::endl;
088     std::cout << "ModelNumder = " << ModelNumder << std::endl;
089     std::cout << "FamilyCode = " << FamilyCode << std::endl;
090     std::cout << "Processor Desciption = [" << cpustring.c_str() << "]" << std::endl;
091 
092     return 0;
093 }

このコードを実行すると、

Vender String = GenuineIntel

ProcessorType = 0

SteppingID = 7

ModelNumder = 4

FamilyCode = 15

Processor Desciption = [Pentium 4 Processor, Pentium D Processor 90um process.]

のように、CPUの情報が出力されることを確認することができます。

posted @ 15:14 | Feedback (16)

2008年3月25日

アセンブラ言語は、コンピュータの命令を直接(と言っても機械語でもありませんが、ほぼ1対1で対応するってことで)記述する言語です。

ですが、この言語を使ってプログラミングを行うと、メモリの値を直接のデータアドレスで指定しないといけません。

もともとアセンブラには変数っていう概念はないのでアドレスを計算してあげなければいけないんですけど。

そこで、Visual C++のインラインアセンブラを使うと、C++コードの途中にアセンブラ言語を混ぜることができます。

こうすることで、必要最低限の作業量でMMXやSSEなど、通常のコンパイラが吐いてくれないアセンブラ命令を使うことができたり、CPUIDなどの特殊命令も実行することができます。

インラインアセンブラは次のような記述で使えます。

001 __asm {
002     // インラインアセンブラコードをここに記述
003 }
004 
こんな感じ。

まずは、C++で変数を定義して、そこにアセンブラでデータを突っ込んでみましょう。

データのロードにはmov命令を使います。たぶんアセンブラで最も使う命令と思われます。

001 #include <iostream>
002 void main()
003 {
004     int a;
005     __asm {
006         mov a, 256;
007     }
008     std::cout << "a = " << a << std::endl;    // a = 256 と出力される
009 }

 

MOV命令は

mov dest, src

dest レジスタ,メモリ

src レジスタ,メモリ,即値

となっています。ですので、

001 {
002     int a,b;
003     b = 256;
004     __asm {
005         mov a, b;
006     }
007 }
008 

というのは動きません。

次に、足し算命令を使ってみましょう。

足し算命令はaddを使います。

add dest, src

flag OF, SF, ZF, AF, CF, PF

dest レジスタ,メモリ

src レジスタ,メモリ,即値

これをインラインアセンブラで記述してみます。

001#include <iostream>
002void main()
003{
004    int a;
005    __asm {
006        mov a, 256;
007        add a, 128;
008    }
009    std::cout << "a = " << a << std::endl;    // a = 384 と出力される
010}

このときに、MOV命令と違って演算を行うとフラグが立ちます。これは、算術演算を行った時の結果に対して出てくるものです。

CF(キャリーフラグ)

算術命令を行った際に、最上位ビットが繰り上げもしくは繰り下げを行ったときにセットされます。

PF(パリティーフラグ)

演算結果のパリティビット。二進数で1の数が偶数のときに1になる。使ったことがないw

AF(補助フラグ)

あまり使わない…かも。調べて分かったら書く。

ZF(ゼロフラグ)

演算結果が0になった場合に1になる。とても使う。

SF(サインフラグ)

演算結果がマイナスになったときに1になる。signedコードなので基本的には最上位ビットと同じ。

OF(オーバーフローフラグ)

ビットが越えたときに1になる。たとえば、

mov AX, 65530;
add AX, 100;

とすると、AXレジスタは16ビットなのでオーバーフローとなり、ビットが立ちます。

符号付き演算で、符号が変化したときに1になります。

この値をチェックすることもあります。たとえば、INT 21Hなんかは異常時にCFが1になってくるので、関数の戻り値みたいに使う人もいたり。

 

といことで、次回はCPUID命令で。

posted @ 18:18 | Feedback (30)

2008年3月20日

わんくま同盟に参加して、一年になりました。

そもそも、わんくま同盟に申請出したときには、存在が何をしているのかすら知りませんでした。

某SNSで、「Web記事でも書けるようにならんかなー。」とぼやいていたところ、 とあるかたから、

「や ら な い か ?」

といわれまして、とりあえず、

「よくわからないけれど、やるお!」と答えたのがきっかけでした。

それにしても、ここ一年ですごい密度の高いメンバーに出会えてとても充実しました。

最近はチラ裏で遊んでばかりで、さぼってばかりで申し訳ないです。

もしかしたら、しょーもないインラインアセンブラなんかも乗せると役に立つのかもしれません。

めざせ、月1エントリ… orz

posted @ 20:51 | Feedback (4)

2008年2月4日

半年くらい前のエントリ:http://blogs.wankuma.com/nagase/archive/2007/08/31/92916.aspx#120872

ですが、

>この回路図を基に0-10V入力に対して4-20mA出力になるような回路にするにはどうしたら宜しいでしょうか?

ということで、返信をテキストで記述しようとしたが、それを書くには余白が狭すぎるので新しく起こしました。

 

前段の加算回路で、2.5Vのオフセットをつけて、0Vから10Vを2.5Vから12.5Vに変換してます。

これを、1V=1.6mAの演算式で、R11をセットします。これで、(計算上は)出力に、4mA - 20mAを流せます。

ただし、上の回路はそもそもuAオーダーの出力を出すためものなので、オペアンプが飽和します。通常利用の場合は、電圧検出抵抗で検出した電流を電圧に変換して、増幅器の反対側に入れるのをオススメしておきます。

posted @ 18:29 | Feedback (3)
C#の練習用にDelegateを利用したFizzBuzz問題をやってみた。
なんかメソッドがことごとくstaticになってるんで、見た目はあまりよくはないですが…。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DelegateFizzBuzz
{
    class Program
    {
        public static int[] FizzBuzzMap = 
           {3,  0,  0,  1,  0,  2,  1,  0,  0,  1,  2,  0,  1,  0,  0 };

        protected delegate void doFuzzBuzz(int n);

        public static void Other(int n)
        {
            Console.WriteLine(n);
        }

        public static void Fuzz(int n)
        {
            Console.WriteLine("Fuzz");
        }

        public static void Buzz(int n)
        {
            Console.WriteLine("Buzz");
        }

        public static void FuzzBuzz(int n)
        {
            Console.WriteLine("FuzzBuzz");
        }
        

        static void Main(string[] args)
        {
            doFuzzBuzz[] FizzBuzzFunc = 
            {
                new doFuzzBuzz( Other ),
                new doFuzzBuzz( Fuzz ),
                new doFuzzBuzz( Buzz ),
                new doFuzzBuzz( FuzzBuzz )
            };

            for (int i = 0; i < 100; i++)
            {
                FizzBuzzFunc[FizzBuzzMap[i % 15]](i);
            }
        }
    }
}
posted @ 13:57 | Feedback (0)

2008年1月27日

1月の東京勉強会に参加されたみなさま、おつかれさまでした。

いろいろと思うことととかあるんですが、そのあたりはチラ裏でどどんと1日10エントリするとして。

特に2次会では、ひさびさにえムナウさんとえぴさんとの席で濃いい話も出来たのでなかなか楽しい会話でした。あ、あと、いろんな面で大変スミマセンでした。次回にでも^-^

最近は、何年ぶりかにASP.NETを触りつつC#もやっていたんですが、やっぱりプログラミング言語って面白いですよね。

なんというか、久しぶりにプログラミングに燃えてきました。

posted @ 0:13 | Feedback (2)

2008年1月22日

私のはてなダイヤリーからの転載です^-^;

えーと、株価っていうかここでは日経平均株価とかTOPIX、ニューヨークダウなどの株価指数です。

株価が下がっても、株式を持っていない自分には関係ねーよ!なんつっている人も結構多いですが、んなこたーありません。

株価が下がるっていうことは、世の中に出回るお金の流通量が減ります。すると、物が売れなくなります。

物が売れないと、会社が売り上げが減るか、もしくはなくなります。

特に、大企業から仕事を請け負っているような、業務請負なんかの場合には、大企業は他社に仕事回すような余裕はないものですから真っ先に仕事がなくなります。

するってーと、当然会社は小さいほうからつぶれていきますね。

ちなみに、現在ガンガン株価が下がっている理由としては、もちろん発端としては米国サブプライムローンによる金融の損失っていうものもあるのですが、いわゆる金が株式から先物に流れているせいもあります。

ここの先物っていうのは原油とか小麦とかのこと。

株価が下がって原油・小麦とかの価格があがる → 会社はつぶれるわ、物価は大暴騰するわ、失業率があがりまくるわ

ということですね。ただですねー。今回の下げがこれだけ止まらないっていうのは、福田超先生が明確な改革路線を見出さないからいかんのです。

小泉内閣時代にも問題は多々ありましたが、改革路線だけは絶対に貫くっていうメッセージがあったものだから、ここまでひどくはならんかったのですが・・・。

posted @ 12:42 | Feedback (2)

2008年1月9日

ということで、わたくしの20代は終了しました。

思えば20代と10代はかなりヒサンな人生を送ったような気がします。

 こちらの世界でも、よろしくおねがいいたします。

posted @ 9:45 | Feedback (13)

2008年1月7日

本日から仕事始めの人も多いかと思います。1/7は近年まれに見る憂鬱な月曜日ですね。 今年はちょっとASP.NETにでも手を出したり、勉強会への参加も増やしたいと思っています。本年もよろしくお願いいたします。 今年の正月は、近年まれに見る早寝早起きを繰り返していたので仕事が始まってからのほうが起床時間が遅いです(笑
posted @ 11:59 | Feedback (3)

Blog 利用状況

コミュニティ

プロファイル