Posts Tagged with "Design"

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.
posted by sakurai on November 8, 2022 #547

giiにより生成されたコードの修正法

元に戻って、標準のgiiにより生成されるコードの追加の修正法を示します。前稿までにCListViewの修正を示しましたが、ここではもう一つのCGridViewの修正を行います。

標準のgiiではテーブル表示にCListViewとCGridViewの2種類を選択するとができます。見かけが良いのはCGridViewで、図547.1のようにエクセルライクな表を作成してくれます。

図%%.1
図547.1 標準のCGridViewによる表示

views/docs/index.phpの修正法を示します。自動生成されたindex.phpを見ると、

<?php $this->widget('zii.widgets.grid.CGridView', array(
        
'id'=>'docs-grid',
        
'dataProvider'=>$model->search(),
        
'filter'=>$model,
        
'columns'=>array(
                
'id',
                
'title',
                
'pages',
                
'link',
                
'category_id',
                array(
                        
'class'=>'CButtonColumn',
                ),
        ),
)); 
?>

のように変数ではなくラベルになっています。従って\$model->(リレーション名)->(メンバ名)のように手修正することができないと思っていました。ところがyii2のGridViewのcolumnsにおいて、(リレーション名).(メンバ名)でリレーション先を表示できるとあったため、yiiで実行してみたところ、正常に表示されることが分かりました。この機能はマニュアルに書かれてないようです。

<?php $this->widget('zii.widgets.grid.CGridView', array(
        
'id'=>'docs-grid',
        
'dataProvider'=>$model->search(),
        
'filter'=>$model,
        
'columns'=>array(
                
'id',
                
'title',
                
'pages',
                
'link',
                
'category.name',
                array(
                        
'class'=>'CButtonColumn',
                ),
        ),
)); 
?>

これを実行した結果を図547.2に示します。

図%%.2
図547.2 修正したCGridViewによる表示

図547.1ではCategoryのタイトルで数字となっていたカラムが、Nameのタイトルでカテゴリ名に変化しています。ちなみにこのカラムタイトルは、"attribute:format:label"のようにラベルとして指定可能です。例えば元のままの"Category"としたければ、

                'category.name:text:Category',

のように記述します。

yiiにおいてはgiixを使えばリレーションに関する手修正は必要ないため、ここまでとします。


左矢前のブログ 次のブログ右矢

posted by sakurai on November 7, 2022 #546

giixの実行

新規に追加されたGiixModel GeneratorとGiixCrud Generatorのうち、まずモデルジェネレータでデータベーステーブルに対応するdocs及びcategoryの2つのモデルを作成します。モデル指定では'*'が可能であり、全てのモデルを一度に作成できます。

次に、CRUDジェネレータで今作成した2つのモデルを個々に指定し、それぞれに対してコントローラ及び関連ビューを作成します。

try it(/?r=docs)をクリックしdocsを表示します。

図%%.1
図546.1 リストビュー
図546.2のように、前稿では手修正した部分が、自動的にリレーション先のメンバで表示されています。

Create表示

次にcreate docsをクリックすると、docsのレコード入力画面になりますが、標準のgiiではcategory_idは数値を入力しなければなりませんでした。ところが、giixでは、次のようにリレーション先のメンバのドロップダウンリストの選択画面を生成してくれます。

図%%.2
図546.2 Createビュー

giixの秀逸なところは、これまでのように手修正することなしに、リレーションをたどってくれるところです。番号で入力することなく、別の配列のメンバを直接指定することができます。

また、別の表に分けないとcategory nameをひとつひとつテキスト入力する必要がありますが、分離してリレーションを張り、フォーリンキー制約を解釈できるgiixの機能により、ドロップダウンで選択するのみで良くなりました。giixを用いればCRUDの全てにおいて外部制約が自動的に解釈され、数字にはなりません。

リレーションに関してはgiixでは全く修正が不要です。


左矢前のブログ 次のブログ右矢

posted by sakurai on November 4, 2022 #545

giixの準備

標準では前稿のようにマニュアル修正が必要でした。これを自動で行うgiixという拡張があります。 yii extensionsからダウンロードし、以下のようにprotected/config/main.phpを設定します。

importにgiixを設定します。

        'import'=>array(
            :
                
'ext.giix.components.*'// giix components
            
:
        ),

次にmodulesのgiiのうち、generatorPathsをgiixを使用するように設定します。

        'modules'=>array(
                :
                
'gii'=>array(
                        
'class'=>'system.gii.GiiModule',
                        
'ipFilters'=>array('127.0.0.1'),
                        
'generatorPaths' => array(
                                
'ext.giix.generators'// giix generators
                        
),
                ),

ブラウザでアプリケーションにアクセスし、/?r=giiとしてgiixを起動します(r=giixではない)。

図%%.1
図545.1 giixの表紙

新規にGiixModel GeneratorとGiixCrud Generatorが追加されています。


左矢前のブログ 次のブログ右矢

posted by sakurai on November 3, 2022 #544

giiの実行

ブラウザでアプリケーションにアクセスし、/?r=giiとしてgiiを起動します。パスワードを適宜入力します。IPアドレスが許可されていれば、図544.1の画面が現れます。様々なジェネレータが用意されています。

図%%.1
図544.1 giiの表紙

まず、モデルジェネレータでデータベーステーブルに対応するdocs及びcategoryの2つのモデルを作成します。

次に、CRUDジェネレータで今作成した2つのモデルを指定し、それぞれに対してコントローラ及び関連ビューを作成します。

try it(/?r=category)をクリックしcategoryを表示します。

図%%.2
図544.2 categoryリスト表示

リレーションの構造

docsテーブルの中のカテゴリ種別は別のテーブルcateogryのidを示しています。これをforeign keyとして以下のようにリレーションが張られています。protected/models/Docs.php(一部)は以下のようになっています。

   public function relations()
   {
     return array(
       'category' => array(self::BELONGS_TO'Category''category_id'),
     );
   }

Docモデル中のリレーションcategoryは、"Docs belong to a Category"と読みます。n対1の関係を示します。

protected/models/Category.php(一部)は以下のようになっています。

   public function relations()
   {
     return array(<br />
       'docs' => array(self::HAS_MANY'Docs''category_id'),
     );
   }

Categoryモデル中のリレーションdocsは、"A Category has many docs"と読みます。1対nの関係を示します。

表示の修正

データベース内容一覧を表示するためのviews/docs/_view.phpを見ると、自動生成後は

   <b><?php echo CHtml::encode($data->getAttributeLabel('category_id')); ?>:</b>
   <?php echo CHtml::encode($data->category_id); ?>

となっており、図544.3のようにcategory_idとして数字が表示されます。

図%%.3
図544.3 修正前
これでは分類がすぐには判りません。この数字で別の表categoryを参照する必要があります。以下のように修正すると、参照テーブルのメンバ名(name)で表示されます。

   <b><?php echo CHtml::encode($data->getAttributeLabel('category_id')); ?>:</b>
   <?php echo CHtml::encode($data->category->name); ?>

これを表示すると図544.4のようにカテゴリ名で表示されます。

図%%.4
図544.4 修正後

これがYiiの素晴らしい機能で、$data->(リレーション名)->(参照メンバ)のように、リレーションをあたかも構造体のように辿ることができます。自動的にリレーション先の表のメンバを参照可能です。


左矢前のブログ 次のブログ右矢

posted by sakurai on November 2, 2022 #543

データベースの作成

ER図作成ツールであるmysqlworkbenchをダウンロードし、インストールします。次にER図を作成します。これは前稿で設計した仕様を入力します。

図%%.1
図543.1 ER図
データ入力も行うことができ、簡単にデータを入力することができます。これをforward engineering機能により、データベースに移すことができます。ここではデータベース名をtestとしました。

yiiによるスキャフォールディングの準備

まずyiiを用いて実行します。yiiのインストールは済んでいるものとします。次のとおりyiicにより、アプリケーションひな形ディレクトリを作成します。太字が入力する部分です。

\$ /var/www/html/yii/framework/yiic webapp doctest
Create a Web application under '/var/www/html/yii/demos/doctest'? (yes|no) [no]:yes
mkdir /var/www/html/yii/demos/doctest
mkdir /var/www/html/yii/demos/doctest/protected
:
mkdir /var/www/html/yii/demos/doctest/images

Your application has been created successfully under /var/www/html/yii/demos/doctest.

models, views, controllersを一時書き込み可能とします。Giiの自動生成による書き込みはウェブブラウザによるため、第3者が書き込めなければなりません。セキュリティ上問題があるため、完了後には書き込み不可にしておきます。

\$ chmod og+w protected/models protected/views protected/controllers

giiの設定をします。コメントを外し、パスワード設定、IPアドレス許可等の変更を行います。

\$ emacs protected/config/main.php

これによりprotected/config/main.phpを以下のように修正します。

       'modules'=>array(
                
// uncomment the following to enable the Gii tool
                
'gii'=>array(
                        
'class'=>'system.gii.GiiModule',
                        
'password'=>false,
                        
'ipFilters'=>array('127.0.0.1','::1'),
                ),
        ),

mysqlサーバの設定をします。コメントを外し、ユーザ名、mysqlパスワード設定等の変更を行います。

\$ emacs protected/config/database.php

これによりprotected/config/database.phpを以下のように修正します。

// This is the database connection configuration.
return array(
        
// uncomment the following lines to use a MySQL database
        
'connectionString' => 'mysql:host=localhost;dbname=test1',
        
'emulatePrepare' => true,
        
'username' => 'root',
        
'password' => 'XXXXXXXX',
        
'charset' => 'utf8',
);


左矢前のブログ 次のブログ右矢

posted by sakurai on November 1, 2022 #542

はじめに

ハードウェアの設計と並行してソフトウェアを設計します。まずは、PHPフレームワークであるyii/yii2と、laravelを取り上げます。これら3者を用いて同じテーマでアプリケーションを設計します。

対象となるアプリケーションは、弊社社内で使用している「資料一覧表」の作成とします。一覧表の作成は非常に汎用的であり、資料に限らず10以上のモノを管理しようとすると、一覧表は不可欠です。

データベース設計

docsとcategoryの2つの表で管理します。docsとその例を表542.1で示します。

表542.1 資料(docs)表
id 題名(title) ページ数(pages) 保存場所(link) 分類(category_id)
1 ISO 26262 第1版 Part 1 29 1
2 ISO 26262 第1版 Part 2 35 1
3 平成26年度電子部品信頼性調査研究委員会報告 (FIDESの解説) 125 2
4 平成27年度電子部品信頼性調査研究委員会報告-改 (IEC/TR 62380, FIDES)  192 2
5 Bluespec SystemVerilogリファレンスガイド 453 3
6 BSVユーザガイド 142 3
: : : : :

次に分類(category)表とその例を表542.2で示します。

表542.2 分類(category)表
id 分類(category)
1 車載機能安全規格
2 故障率データベース
3 技術文書
: :

categoryをdocsの表に埋め込めば一枚の表にすることは可能ですが、このように表を分離し、categoryをユニークにすることにより、n対1の関係となるので、修正が容易となるメリットがあります。

(参考情報)https://johobase.com/dividing-multiple-tables-merit/

ここに示されるように、資料表のレコードが100万件有り、分類に修正が入ると100万レコードの修正になるのに対し、表が分離されていると1つのレコードの修正で済みます。

このcategory_idカラムのように他の表のインデクスとなっているカラムをフォーリンキーと呼び、これでリレーションが張られていることになります。この「関係性」の機能を持つデータベースをリレーショナルデータベースと呼びます。


左矢前のブログ 次のブログ右矢

posted by sakurai on October 28, 2022 #541

<PC>の必要性

従来例を再掲します。作成しようとするパイプラインロジックは大略、前の図540.1のとおりです。ただし図540.1では<PC>が明示されていません。

図%-%.1
図540.1 あるRISC-Vプロセッサのパイプライン図(再掲)

次の命令ストリームの起点であるPCは、基本的に

  1. 分岐が無ければ(有っても投機的に数命令は実行)、現PC+4
  2. PC相対分岐が有ればPC+オフセット
  3. 絶対分岐の場合はその値

を次のPCにセットします。この他にも割り込み、例外処理等で新PCを演算し、次のPCにセットします。これを<PC>を意識した図に書き直すと、図541.1のように判りやすい図となります。図540.1のように、PC演算器やレジスタが窮屈に<IF>の中に折れ曲がることは無く、ストレートフォワードに描かれています。<PC>の入力が<PC>であることも図541.1を見れば明らかです。

図%%.1
図541.1 <PC>の考え方に基づき書き直したパイプライン図

図541.1では分岐の場合は<EX>の結果レジスタがPCであることから元の<EX>と分岐先<PC>が重なり、その次のステージが分岐先<IF>となることが良くわかります。クロックベースが原則のパイプラインを記号で書けば、

   <PC><IF><ID><EX><WB>
          <PC><IF><ID><EX><WB>

となります。分岐先のPC計算を分岐元のEXで代行している様子が良く分かります。

一方、図540.1では<EX>の後にPCレジスタが入り、その次に<IF>ステージとなるので、記号で書くと、

   <IF><ID><EX><WB>
          <IF><ID><EX><WB>

となり、<IF>が湧き出す意味が不明です。<IF>の入力レジスタがPCで、分岐命令の<EX>でそれを生成しているのだからという説明になると思いますが、であればPCを明示したほうが分かりやすいのは言うまでもありません。

逆にPCの生成も含めたパイプラインを理解してしまえば頭の中でできるため、取り立てて<PC>の必要性は感じなくなるので、不思議とも思わないようになりますが、教育的とは言えません。そもそも最も重要なPCの更新ステージはどこなのかが図示されていません。これでは分岐命令の高速化、例えばBTB等による<PC>の物量増加も、どのステージの話なのか理解しづらくなります。

<PC>の制御法

<PC>の必要性が理解できたところで、過去記事でパイプライン制御論理を示しました。<PC>の上流が<PC>だからといって上流に出力するwait信号を自分自身に入れると永久にストールするので、自分自身に入れてはいけません。

また、図示されていませんが、PCレジスタ自体も同じパイプライン制御論理によりパイプラインを流します。その理由は、例外の際には分岐が発生しますが、戻りアドレスをスタックに格納します。その戻りアドレスを上記PCパイプラインから適宜取得するためです。


左矢前のブログ 次のブログ右矢

posted by sakurai on October 27, 2022 #540

PCステージ

PCステージ(<PC>)を設計します。と言うとなじみがありませんね。一般には存在しないステージなので。以降ではステージ記号を次のように定義します。例:PCステージ:=<PC>

一般にはパイプライン図は<IF>から始まっています。例えば図540.1のように。PCレジスタは<IF>の入力レジスタとして描かれています。良く見ると、本来の<PC>の演算器や結果レジスタは折り曲げられて、窮屈な恰好をしています。

図%%.1
図540.1 あるRISC-Vプロセッサのパイプライン図(引用元)

図540.2の黄色のステージ記号及び点線は弊社で追加しました。FDレジスタとは<IF>と<ID>の間のステージなので、<IF>の結果レジスタです。つまりFDレジスタの左側は全て<IF>です。この図でもPCレジスタは窮屈に折り曲げられています。

図%%.1
図540.2 あるRISC-Vプロセッサのパイプライン図(引用元)

この図のように<IF>の中にPCレジスタが書かれています。これが変であることに気づかれたでしょうか。パイプラインプロセッサは、パイプラインレジスタにより、組み合わせ回路の結果を次々に受けていくバケツリレー式であり、本来ステージの内部は組み合わせ回路で構成され、レジスタは無いはずです。

それでは<IF>の入力である命令アドレスはどこのステージで生成されるのでしょうか?それが<PC>です。つまり一般の図ではPCは<IF>の入力レジスタのように描かれていますが、実は他のステージと同様、<PC>の結果レジスタです。こう考えるとパイプラインの各ステージが統一的に理解できます。

例えば分岐命令では分岐先アドレス計算をする必要があり、それは必ず<ID>の後になります。図540.2にもPC calculationとありますが、それがパイプライン中の2個目の<PC>です。そして分岐条件が確定した後に<IF>が実行されるので、<PC>は明示したほうが判りやすいです。

一般的に<PC>が無視される理由としては、有名な教科書がIF, ID, EX, MEM, WBの5段で書かれている、からなのかもしれませんが、本来は

<PC><IF><ID><EX><MA><WB>

の6段パイプです。このことは過去記事でも指摘しています。

次の質問です。<PC>の前のステージは何でしょうか?答えは<PC>です。分岐しない限り<PC>は次の<PC>を生成し、1サイクル毎に次々にストリームを生み出します。

一方、例えば分岐命令等のようにパイプラインの途中に<PC>が出現することがあり、複数現れる場合でも命令ストリームの開始PCの計算ですから、いきなり別の命令ストリームの<IF>が現れるよりは判りやすいと思います。無から有は湧いてきません。

割り込みや例外を考える時には一層重要です。割り込みレベルやマスクや例外の種類等の情報を総合して、まずPCがどうなるかを決定します。PCさえ確定すれば、後は<IF>以降のパイプラインを普通に流せば良いだけです。つまり常に<PC>が命令ストリームの起点となります。

本稿で述べたことはエンジニアとしては意識しなくても、設計できるし、見方を変えて設計が変わるわけではないので、哲学に属する話かもしれません。

しかし、設計思想として大事な話なので強調しています。この思想のメリットもあり、例えば<PC>においてPCアドレスを命令アドレスとして命令メモリに流し、<PC>と<IF>の間のクロックで命令アドレスをラッチし、<IF>として命令メモリからデータを流し、プロセッサは<IF>と<ID>の間のクロックで命令データをラッチする、というフローが一般的ですが、<PC>を<IF>の中に混ぜると<IF>が複雑になります。一方この考え方であれば、ラッチベースの動作がすっきりします。


左矢前のブログ 次のブログ右矢

posted by sakurai on October 25, 2022 #536

デコーダのソースの一部を示します。

genRules(
   switch(in_instr,
      when(pat(n(7'b0000000), v, v, n(3'b000), v, n(7'b0110011)), fadd),
      when(pat(n(7'b0100000), v, v, n(3'b000), v, n(7'b0110011)), fsub),
      when(pat(               v, v, n(3'b000), v, n(7'b0010011)), faddi),
      when(pat(n(7'b0000000), v, v, n(3'b111), v, n(7'b0110011)), fand),
      when(pat(n(7'b0000000), v, v, n(3'b110), v, n(7'b0110011)), ffor),
      when(pat(n(7'b0000000), v, v, n(3'b100), v, n(7'b0110011)), fxor),
      when(pat(               v, v, n(3'b111), v, n(7'b0010011)), fandi),
      when(pat(               v, v, n(3'b110), v, n(7'b0010011)), fori),
      when(pat(               v, v, n(3'b100), v, n(7'b0010011)), fxori),
      when(pat(               v, v, n(3'b010), v, n(7'b0000011)), flw),
      when(pat(            v, v, v, n(3'b010), v, n(7'b0100011)), fsw),
      when(pat(n(7'b0000000), v, v, n(3'b001), v, n(7'b0110011)), fsll),
      when(pat(n(7'b0000000), v, v, n(3'b101), v, n(7'b0110011)), fsrl),
      when(pat(n(7'b0100000), v, v, n(3'b101), v, n(7'b0110011)), fsra),
      when(pat(n(7'b0000000), v, v, n(3'b001), v, n(7'b0010011)), fslli),
      when(pat(n(7'b0000000), v, v, n(3'b101), v, n(7'b0010011)), fsrli),
      when(pat(n(7'b0100000), v, v, n(3'b101), v, n(7'b0010011)), fsrai),
      when(pat(n(7'b0000000), v, v, n(3'b010), v, n(7'b0110011)), fslt),
      when(pat(n(7'b0000000), v, v, n(3'b011), v, n(7'b0110011)), fsltu),
      when(pat(               v, v, n(3'b010), v, n(7'b0010011)), fslti),
      when(pat(               v, v, n(3'b011), v, n(7'b0010011)), fsltiu),
      when(pat(v, v, v, v, n(3'b000), v, v, n(7'b1100011)), fbeq),
      when(pat(v, v, v, v, n(3'b001), v, v, n(7'b1100011)), fbne),
      when(pat(v, v, v, v, n(3'b100), v, v, n(7'b1100011)), fblt),
      when(pat(v, v, v, v, n(3'b101), v, v, n(7'b1100011)), fbge),
      when(pat(v, v, v, v, n(3'b110), v, v, n(7'b1100011)), fbltu),
      when(pat(v, v, v, v, n(3'b111), v, v, n(7'b1100011)), fbgeu),
      when(pat(v, v, v, v, v, n(7'b1101111)), fjal),
      when(pat(               v, v, n(3'b000), v, n(7'b1100111)), fjalr),
      when(pat(               v, v, n(7'b0110111)), flui),
      when(pat(               v, v, n(7'b0010111)), fauipc),
      when(pat(               v, v, n(3'b001), v, n(7'b1110011)), fcsrrw),
      when(pat(               v, v, n(3'b101), v, n(7'b1110011)), fcsrrwi),
      when(pat(               v, v, n(3'b010), v, n(7'b1110011)), fcsrrs),
      when(pat(               v, v, n(3'b110), v, n(7'b1110011)), fcsrrsi),
      when(pat(               v, v, n(3'b011), v, n(7'b1110011)), fcsrrc),
      when(pat(               v, v, n(3'b111), v, n(7'b1110011)), fcsrrci),
      when(pat(n(25'b0), n(7'b1110011)), fecall)
   ) // switch
);

これは1ステップ目のデコーダステップであり、ここでビットパターン、例えばaddi命令とのマッチが取れれば、2ステップ目として個別の関数、例えばfaddiが呼び出されます。一例であるfaddiを示せば、

function Action faddi(Bit#(12) imm, Bit#(5) rs1, Bit#(5) rd) = 
   action
      Int#(32) immSext = signExtend(unpack(imm));
      if (immSext == 0)
         $display("time %4t -   mv\t%s,%s", $time, regname(rd), regname(rs1));
      else if (rs1 == 0)
         $display("time %4t -   li\t%s,%0d", $time, regname(rd), immSext);
      else
         $display("time %4t -   addi\t%s,%s,%0d", $time, regname(rd), regname(rs1), immSext);
   endaction;

RISC-Vにおいてaddi命令はイミディエイトがゼロの場合はmv命令として使用され、逆にソースレジスタにゼロレジスタを指定すれば、イミディエイトロード(li)命令として働きます。これらはプロセッサの設計的には不要な処理ですが、逆アセンブラのシンタックスシュガーとして実装しました。

2ステップ目の処理として、各種関数を命令数だけ並べる必要があります。


左矢前のブログ 次のブログ右矢

posted by sakurai on October 24, 2022 #535

BSV実行結果(ハードウェアからの出力)と逆アセンブルリストをサイドバイサイドに並べた図を535.1に示します。分岐関係を除いて一致していることが分かります。BSV実行出力にアドレスやデータを表示することは簡単ですが、逆アセンブラを作成しているわけではないので、それらの表示機能は実装していません。

図%%.1
図535.1 実行結果と逆アセンブルリスト

この後も「はじめてのCPU自作」にあるようにECALLやCSR操作命令等を実装し、ひととおりriscv-testが通るデコーダまで作成が完了しました。ところで論理合成ツールには論理圧縮機能が含まれるため、出力されたデコーダ論理を合成前に圧縮する必要はありません。


左矢前のブログ 次のブログ右矢


ページ: