2026
2025
2024
2023
2022
2021
2020
2019
2018
2017
2016
2015
2014
2013
全26件 (26件中 1-26件目)
1
相変わらずのデバッグ作業だが、CPUは基本的に終了して、周辺の方を行っている。何らかのソースコード管理が必要になってきたので、RCSを入れることにした。最近はCVSの方がはやりなんだろうけど、使い方がよく判らない(笑)し、サーバを立てるのも億劫なので、ここはRCSでいいことにする。だいたい、複数人数で開発しているわけではないし... Windowsで動くRCSは、「Windows で RCS」を見つけたが、どうせならということで、cygwinにした。標準のインストールではrcsは入らないので、追加する必要あり。 普段、エディタはvim(香り屋版)を使っているが、rcs用のマクロを見つけたので、これも入れてみた。vimの上から、rcsが快適に使える。だいぶ作業がしやすくなった。----本日の御託家内は、ちょっと絵心があって、まあ、イタズラ書きみたいなものだが、時々メモ用紙にヘンな絵を書いている。 昨晩、呑んだくれて遅く帰ったら、とぼけた顔の三毛猫が鴨に取り囲まれている絵がテーブルの上にあった。タイトルは「カモダラケのミケ」。「サモトラケのニケ」のパロディらしい。(おバカである)
2007.08.31
コメント(0)

逆アセンブラを新調しました。今までのものと異なり、特別なレジスタに関してはレジスタ名を、さらに一部のレジスタではビット名も表示できるようにしました。これでだいぶデバッグが楽になります。Veritakのちょっとした「クセ」に嵌ってしまいました。---本日の御託月食は見られませんでした...
2007.08.29
コメント(0)
デバッグもちょっと飽きたので、PIC16F648Aへの対応を少し考えました。timer1という16ビットのタイマがあるのですが、これがアタマが痛いですね。同期モードと非同期モードがあるのですが、非同期モードでので、タイマの読み書きが問題です。書き込みのほうは原則的に、タイマを停止した状態で書き込みをしなさい、とのことなので、何とかなりそうですが、問題は読み出しですね。読み出しは特別なことをしなくても正しく読み出せることになっているので、ひと工夫しないといけないです。うぅぅ。---本日の御託 今週は、首藤さんは夏休みか・・・ちぇっ
2007.08.27
コメント(0)
え~、しばらく更新をしていなかったが、何にもしていなかったわけではありません。実は、PIC16F84A相当のモノは既に出来上がっていて、デバッグをしています。まあ、よく判っていないPICのアセンブラをテキトーに使いながら、テストプログラムを書いている(笑)のだが、期待どおりに動作してない場合、Verilogのコードに誤りがあるのか、そもそもアセンブラのプログラムがおかしいのか解析するのに時間がかかってしまう。バグそのものは単純なものがほとんどなのだが、単純なものほどツボに嵌ると、わけが判らなくて困る。そんなこんなでなかなか先に進まない状態。 前回timer0ユニットのいい加減なコードを載せたが、これも問題ありだ。timer0そのものは、PICのマスタークロックのクロックドメインに属しているが、プリスケーラはそうではない。プリスケーラ→timer0については、ダブルラッチによるシンクロナイザがPICのデータブックにあるブロックダイアグラムにも示されていて、いわゆるCDC(Clock Domain Crossing)問題は一応ケアされている。 問題は、逆方向。プリスケーラは、timer0に対する書き込みで、リセットされることになっている。前回載せた実装では、単純にハザードフリーのリセット信号を非同期リセットとして与えているが、うるさく言うとこれではCDCに関しては失格だ。どうすっかな・・・----本日の御託 暑い...
2007.08.26
コメント(0)
今日はtimer0モジュールです。データブックにあるものほぼそのままでまったく面白くありません。プリスケーラ、タイマ本体とも、1ビット余計に用意して、ハザード無しの出力を用意しています。プリスケーラはWDTと兼用になってます。----本日の御託内閣の支持率がすんごい数字になっている(笑)。昔の派閥推薦による組閣がいいとは決して思わないが、安倍内閣の閣僚を見ていると、なんていうか、自覚が足らんというか、脇が甘いというか...//// TIMER0 file register// (c) 2007 BakaOyaji// based on Figure 11-6: Block Diagram of the Timer0/WDT Prescaler// $Id$//module timer0_reg ( input clk_i, input reset_i, input [ 7:0] data_i, // write port input we_i, output [7:0] data_o, input reset_pre_i, // reset prescaler input t0cki_i, input t0se_i, input t0cs_i, input [2:0] ps_i, input psa_i, output set_t0if_o, // WDT related input wdt_i, output wdt_timeout_o ); wire t0clk0 ; assign t0clk0 = (t0cs_i == 1'b0) ? clk_i : (t0se_i ^ t0cki_i) ; wire ps_clk ; assign ps_clk = (psa_i == 1'b0) ? t0clk0 : wdt_i ; reg [8:0] prescale = 9'h00 ; wire prescale_out ; always@( posedge ps_clk or posedge reset_pre_i) begin if( reset_pre_i == 1'b1 ) begin prescale <= 'd0 ; end else begin prescale <= prescale +1 ; end // else end // always assign prescale_out = prescale[ ps_i +1] ; assign wdt_timeout_o = psa_i ? wdt_i : prescale_out ; assign t0clk1 = psa_i ? prescale_out : t0clk0 ; reg [2:0] dsync; wire timer0_en ; always@( posedge clk_i) begin dsync[2:0] <= { dsync[1:0], t0clk1 } ; end // always assign timer0_en = ((dsync[2] ==1'b0) &&(dsync[1] ==1'b1)) ? 1'b1 :1'b0 ; reg [8:0] timer0 ; always@( posedge clk_i ) begin if( reset_i == 1'b0 ) begin`ifdef FULL_RESET timer0 <= 9'h0 ;`endif // FULL_RESET end // if else if ( we_i == 1'b1 ) begin timer0 <= { 1'b0, data_i} ; end // else if else if ( timer0_en == 1'b1 ) begin timer0 <= timer0 + 9'h1 ; end // else if end // always assign data_o = timer0[7:0] ; assign set_t0if_o = timer0[8] ; // set_t0if_o is hazzerd freeendmodule // timer0_reg // EOF timer0_reg.v
2007.08.19
コメント(0)
WDT(ウォッチドッグタイマ)とクロックジェネレータです。WDTはもともと(私にとっては)どーでもいい部分(だって使うつもりないもん)だし、SLEEP命令も使うつもりはないので(したがって、クロックも止める必要なし)、完全にビヘイビアモデルで実装。WDTのリトリガブルワンショットは、Verillog-HDLの規格書(IEEE-1364.2001)に類似の例があります。(う~ん、意外にはかどらないな...)----本日の御託「7人のメタボ侍、内臓脂肪を斬る」笑えない、というか,ほとんど切ないニュース。労災になるのだろうか?//// Watch Dog Timet// (c) 2007 BakaOyaji// $Id$//// Behavior implementation`timescale 1ns/1nsmodule watchdogtimer( input clk_i, input reset_i , output reg wdt_o ); initial begin wdt_o = 0 ; end // initial always begin : monostable @( negedge reset_i ) # 3000 wdt_o = 1'b1 ; end // monostable always @( posedge reset_i) begin disable monostable ; wdt_o = 1'b0 ; endendmodule // watchdogtimer( // EOF watchdogtimer.v//// Clock Generater// (c) 2007 BakaOyaji// $Id$//// Behavior implementation// (c) 2007 BakaOyaji`timescale 1ns/1ns// 1MHz`define CYCLE 1000module clockgen ( input go_sleep_i, input wakeup_a_i , output reg clk_o , output reg wakeup_o); initial begin clk_o = 0 ; wakeup_o = 1'b0 ; forever begin begin : run forever begin clk_o = 1'b1 ; #(`CYCLE/2) if ( go_sleep_i ==1'b1 ) begin disable run ; end // if clk_o = 1'b0 ; #(`CYCLE/2) ; end // forever end // run @( posedge wakeup_a_i ) clk_o = 1'b0 ; wakeup_o = 1'b1 ; #(`CYCLE/2) clk_o = 1'b1 ; #(`CYCLE/2) clk_o = 1'b0 ; wakeup_o = 1'b0 ; #(`CYCLE/2) ; end // forever end // initialendmodule // clockgen// EOF clockgen.v
2007.08.18
コメント(0)

Skip系の命令の実行と割り込みが同時に起きた場合のテストです。まずは、skipが起きない場合。逆アセンブラのトレースの BTFSC 03,2 はBTFSC STATUS,Z に相当します。Zフラグはセットされていますので、skipは起きません。次は、skipが起きる場合です。逆アセンブラのトレースの BTFSS 03,2 はBTFSS STATUS,Z に相当します。Zフラグはセットされていますので、skipします。stack_topに積まれているリターンアドレスが上記の例と異なっていることに注意してください。あと未サポートの命令は、SLEEP,CLRWDT,RETFIE(GIEのセット機能)なのですが、ちょっとメンドクサそうです...---本日の御託 滝廉太郎の「荒城の月」いう唱歌があるが、意外に外国人にもウケていて、ベルギーでは賛美歌になっているそうである。また、ジャーマン・ロック(どっちかっていうと曲調はブリティッシュメタルだが)の雄、「スコーピオンズ」も歌っている。なんで「荒城の月」かっていうと、週末に家内と高校野球を見るともなく見ていて、高校の校歌の話になった。家内の高校の校歌は、出だしが「荒城の月」にそっくりだそうだ。しかも、作曲者は滝廉太郎の師匠筋にあたる人だそうである。「荒城の月」は2部形式の曲だから、Aメロの出だしは全体の半分以上を占めることになる。で、家内いわく、彼女の母校では「パクってんじゃねぇよ!」ということになるらしい(笑)。 そういえば、スコーピオンズのレコードのジャケットというのは、なんというか、ちょっとアレなものが多くて、「Virgin Killer」とかは当時中学生だった(30年以上前だが)ワタクシはかなりびびった覚えがある。今じゃ、完全に「幼児ポルノ」扱いになると思うが、CDのジャケットはどうなっているのだろう?
2007.08.15
コメント(0)

PICを作ろう ,インタラプトハンドラ ~昼休みにまったり進めるプロジェクト今日は、インタラプトハンドラです。インタラプト時の制御は、2007/07/21、2007/07/22、2007/07/25、で少し詳しく検討してますので、これに沿って実装します。このときの検討では、割り込みの信号は、2クロックサイクル入る事を前提にしています。このことを「保障」するのは、GIEビットを含めた、special function側で行うことにし、CPU側のインタラプトハンドラは、この前提のもとに実装します。(ソースコードは最後) 一応、FSMです。本当はムーアマシンにしたかったのですが、タイミングの制約から、ミーリィマシンになっています。出力の、iack_oは、インタラプトアクノレジサイクルを表します。テストをするために、CPUの内部に下記のような記述を追加してみました。 reg irq; wire [1:0]iack; initial begin irq = 1'b0 ; #200 // change this value to change interrupt timing @(posedge clk_i) // synch to clock irq = 1'b1 ; repeat (2) @(posedge clk_i) ; irq = 1'b0 ; end#200の部分を変えれば、任意のタイミングで割り込みを発生させられます。実行結果は、こんな感じ。とりあえず、うまくいっているようですね。分岐やSKIP系の命令の場合もテストする必要がありますが、次回予定。----本日の御託 庭の芝の状態がよろしくない。ちょっと、枯れた感じになっている。どうすっかな・・・//// Interrupt handler// FIGURE 14-15: INT PIN INTERRUPT TIMING// PIC16F627A/628A/648A//// $Id$//module interrupt_handler( input clk_i, input reset_i, input irq_i , // interrupt request output [1:0] iack_o // int ack cycle) ; reg int_cycle ; assign iack_o[0] = (~int_cycle) & irq_i ; assign iack_o[1] = int_cycle & irq_i ; // FSM always@( posedge clk_i) begin if( reset_i == 1'b1 ) begin int_cycle <=1'b0 ; end //if else if ( iack_o[0] == 1'b1 ) begin int_cycle <= 1'b1 ; end //else if else begin int_cycle <=1'b0 ; end //else end // alwaysendmodule // interrupt handler// EOF interrupt handler.v
2007.08.12
コメント(0)

ファイルレジスタとそのコントローラを実装したので、簡単なテストをやってみました。PICのプログラムを書かないと始まらないので、簡単なコードを書きました(最後に乗っけます)。 最初に、STATUSフラグをクリアして、Zフラグのみセットされるかチェック。ここはうまく行っているようです。引き続き、addwf PCLでいわゆる「計算型GOTO」を使用してテーブル引きで、Wレジスタの値を4倍してます。おっと、しくじってますね。ADDWF 02,1、flush信号が立って次のサイクルで強制的にNOPになってなければなりません。インストラクションレジスタのフラッシュ制御に、PCLの書き込みの条件を忘れてました。修正後はこんな感じ。OKのようです。ところで、PIC16系のプログラムにおける分岐系の命令の出現率は実際のプログラムではどれくらいなんでしょうか?PICは原則1命令/1クロックですが、分岐系の命令の場合は、フラッシュサイクルのため2クロック必要な場合があります。仮に5命令に一回分岐が起きているとすると、全体では20%がフラッシュサイクルに費やされることになります。全部出来上がってから適当なプログラムでちょっと測ってみたいと思います。----本日の御託 いままでは、おおむね、「シンタックスエラーがとれれば、一発で正しく動く」という「天才プログラマ」モードだったのです(笑)がだんだんデバッグモード主体になりつつあります。2007/08/10のステータスレジスタも(目視チェックで)バグを見つけました。そのまま晒しておきますので、ヒマな方は「ツッコミ」よろしく(笑) include <P16f84.INC>STARThere org 00; checking behaviors of some special function regs; STATUS Z flug must be set clrf STATUS clrf PCLATH pagesel test_PCL goto test_PCL;;;;;table_lookup addwf PCL retlw (4*0) retlw (4*1) retlw (4*2) retlw (4*3) retlw (4*4) retlw (4*5) retlw (4*6) retlw (4*7) retlw (4*8)test_PCL movlw 1 pagesel table_lookup call table_lookup movlw 3 pagesel table_lookup call table_lookup; addlw 0 addlw 0 addlw 0 addlw 0 addlw 0 end
2007.08.12
コメント(0)
ファイルレジスタだが、思いっきり面倒くさい。とりあえず、PIC16F84Aの汎用レジスタと最低限必要な、スペシャルファンクションレジスタのPCLATH、PCL、STATUS,FSRだけ実装する。といっても、PCL,FSRは実体はCPUの中にあるため、インターフェースのみの実装です。基本的にはデコーダーとデータセレクタのかたまりです、はい。PIC16シリーズでは、ファンクションレジスタのアドレス空間は最大で512バイト(Page0から4)ですが、品種によってはページ数が異なります。また、レジスタによっては異なるページでも同じページ内アドレスでアクセスできるようになっています。たとえば、PIC16F84では、PCLレジスタはページ0でのみアクセスできますが、STATUSレジスタはページ0,1でアクセスできます。品種によるこのような違いをできるだけ少なくするため、アドレスを以下のように定義しています。`define ADDR_PCL (9'bx_0000_0010)`define ADDR_STATUS (9'bx_x000_0011)そのうえで、アドレスデコードを行うfunction hit()を用意しました。if文ではなく、casex文を使用していることに注意してください。casexを用いることで、比較対照のデータのうちxをDon't careと解釈させています。一方、普通のRAMに相当するレジスタは、一定のアドレスのレンジを持ちます。こちらはうまい方法が思いつかないので、必要なビットスライスだけをとりだし、範囲の比較をしているだけです(function hit_gpr_addr)。データセレクタは、回路的にはAND-OR treeになるのですが、あとからレジスタの構成を変える(つまり別のPIC16の品種に対応する)のがいくらかでも簡単になるように、wor(Wired OR)を使用しています。論理合成ツールが対応しているかどうかよく判りませんが、ダメならあとで、普通のネットとORを使うように書き直します。実体がCPUの中にあるレジスタに関しては、Special functionレジスタの書き込みイネーブルや読み出しパスを一種のバックドアとして実装しました。----本日の御託民主党内でも必ずしも足並みがそろっていないようだが、テロ特別措置法の延長が最大の争点になる感じになってきた。無責任な予測では、ずばり「参院での可決を取引材料に、衆院解散」(笑)。//// file registers of YAP16T84// (c) 2007 BakaOyaji// $Id$//`include "yap16_instructions.h"`include "yap16_def.h"`include "yap16t84_def.h"module yap16t84_file( input clk_i, input reset_i, input [(`YAP16_FA_WIDTH)-1:0] fr_addr_i , input [7:0] data_i, // write port input we_i, // write enable output [7:0] data_o, // read port input re_i, // read enable // backdoors // PCL register input [7:0] pcl_i, // data from PCL reg output pcl_we_o, // back doors from/to CPU input [7:0] status_i, // data from status reg output status_we_o, // write enable // PCLATH reg output [(`YAP16_PC_WIDTH -1 -8):0] pclath_o , // FSR reg output [7:0] fsr_o ) ; wor [7:0] data_o ; // address decoders assign hit_tmr0 = hit( fr_addr_i , `ADDR_TMR0); assign hit_pcl = hit( fr_addr_i , `ADDR_PCL) ; assign hit_status = hit( fr_addr_i , `ADDR_STATUS) ; assign hit_fsr = hit( fr_addr_i , `ADDR_FSR ); assign hit_porta= hit( fr_addr_i , `ADDR_PORTA) ; assign hit_portb = hit( fr_addr_i , `ADDR_PORTB) ; assign hit_eedata = hit( fr_addr_i , `ADDR_EEDATA) ; assign hit_eeadr = hit( fr_addr_i , `ADDR_EEADR) ; assign hit_pclath = hit( fr_addr_i , `ADDR_PCLATH) ; assign hit_gpr = hit_gpr_addr( fr_addr_i[5:0]) ; // feed read data // assign data_o = hit_tmr0 ? 8'hxx : 8'h00 ; assign data_o = hit_pcl ? pcl_i : 8'h00 ; assign data_o = hit_status ? status_i : 8'h00 ; assign data_o = hit_fsr ? fsr_o : 8'h00 ; //assign data_o = hit_porta ? 8'hxx : 8'h00 ; //assign data_o = hit_portb ? 8'hxx : 8'h00 ; //assign data_o = hit_eedata ? 8'hxx : 8'h00 ; //assign data_o = hit_eeadr ? 8'hxx : 8'h00 ; assign data_o = hit_pclath ? { 8'h00, pclath} : 8'h00 ; assign data_o = hit_gpr ? gpr[ fr_addr_i[6:0]] : 8'h00 ; // generate XXXX_we_o assign pcl_we_o = (hit_pcl && (we_i == 1'b1)); assign status_we_o = (hit_status && (we_i == 1'b1)); // simple regs // FSR reg [7:0] fsr ; assign fsr_o = fsr ; always@( posedge clk_i) begin if( reset_i == 1'b1 ) begin`ifdef FULLRESET fsr <= 8'h00 ;`endif // FULLRESET end // if else if( hit_fsr && (we_i == 1'b1) ) begin fsr <= data_i ; end // else if end // always // PCLATH reg [(`YAP16_PC_WIDTH -1 -8):0] pclath ; assign pclath_o = pclath ; always@( posedge clk_i) begin if( reset_i == 1'b1 ) begin`ifdef FULLRESET pclath <= 8'h00 ;`endif // FULLRESET end // if else if( hit_pclath &&( we_i == 1'b1) ) begin pclath <= data_i ; end // else if end // always // General Purpose regs reg [7:0] gpr [`ADDR_GPR_LOW : `ADDR_GPR_HIGH] ; always@( posedge clk_i) begin if( hit_gpr &&( we_i == 1'b1) ) begin gpr[ fr_addr_i[6:0]] <= data_i ; end // if end // always // --------------- function hit( input [(`YAP16_FA_WIDTH-1):0] a , input [(`YAP16_FA_WIDTH-1):0] b ) ; begin casex( a ) b: hit = 1'b1 ; // true default : hit = 1'b0 ; //false endcase end endfunction // hit function hit_gpr_addr( input [6:0] addr ); // address is cut off to 6bit) ; begin hit_gpr_addr = ( ( `ADDR_GPR_LOW <= addr) && ( addr <= `ADDR_GPR_HIGH) ) ; end endfunction // hit_gpr_addr endmodule // yap16t84_file
2007.08.11
コメント(0)
今日は、ファイルレジスタコントローラです。「ファイルレジスタコントローラ」は私がテキトーにつけた名称ですが、普通のコンピュータシステムでいうところの、メモリとI/Oである、「ファイルレジスタ」への読み書きを制御する部分です。機能は3つ。1)アドレス生成2)ライトイネーブル生成3)リードイネーブル生成「アドレスの生成」は、ファイルレジスタをオペランドにする命令で、インストラクションのfスライス(下位7ビット)が0以外の場合は、fスライスがダイレクトアドレスに、0の場合はfsrレジスタによるインダイレクトアドレスを生成します。上位のビットを、ステータスレジスタのrp,irpスライスで補完します。実際にはデコーダを簡略化するため、「ファイルレジスタをオペランドにする命令」かどうかの判断は省略しています。「ライトイネーブル」は命令をデコードして、演算結果の格納先がファイルレジスタになる場合を抽出しています。「リードイネーブル」も同様です。当初、リードイネーブルは不要かとも思ったのですが、よく考えたら,I/Oは読み出しに「副作用」が伴う(たとえば、UARTとか)場合があるので、やっぱり必要ですね。そろそろ、また適当プログラムを動かして、動作確認をしたいのですが、CPUと対向するレジスタファイルを用意しないといけません。(めんどくせー)---本日の御託 トラ技(2007/9)を買いました。実は、先月号からちょっと読みたい連載(dsPICじゃないよ、笑)があって買ったのだが、今回はあんまり面白くなかった・・・orz//// File Resister controler////// file register controller// (c)2007 BakaOyaji// $Id$//`include "yap16_instructions.h"`include "yap16_def.h"module file_reg_controller ( input [( `YAP16_INST_WIDTH -1):0] instruction_i , input [7:0] fsr_i , // from FSR reg input irp_i , // from irp of STATUS reg input [1:0] rp_i , // from rp of STATUS reg output [(`YAP16_FA_WIDTH -1):0] fr_addr_o, // address of file registers output we_o, // write enable to file registers output re_o // read enable to file registers);reg we, re ;wire [6:0] f ; // FILE# fireld in the instruction assign { we_o, re_o } = {we, re}; // address generation assign f = instruction_i[6:0] ; assign fr_addr_o = ( f == 7'h00 ) ? {irp_i, fsr_i} // Indirect addressing, status[7] is IRP : {rp_i ,f}; // Direct addressing, status[6:5] is RP1,0 // re always@ * begin // ( instruction_i ) begin re <= 1'b0 ; casex( instruction_i) `YAP16_INST_ADDWF , `YAP16_INST_ANDWF , `YAP16_INST_COMF , `YAP16_INST_DECF , `YAP16_INST_DECFSZ , `YAP16_INST_INCF , `YAP16_INST_INCFSZ , `YAP16_INST_IORWF , `YAP16_INST_MOVF , `YAP16_INST_RLF , `YAP16_INST_RRF , `YAP16_INST_SUBWF , `YAP16_INST_SWAPF , `YAP16_INST_XORWF , `YAP16_INST_BCF , `YAP16_INST_BSF , `YAP16_INST_BTFSC , `YAP16_INST_BTFSS : begin re <= 1'b1 ; end default : begin re <= 1'b0 ; end endcase // casex end // always // we always@ * begin // ( instruction_i ) begin we <= 1'b0 ; casex( instruction_i) `YAP16_INST_ADDWF , `YAP16_INST_ANDWF , `YAP16_INST_CLRF , `YAP16_INST_DECF , `YAP16_INST_DECFSZ , `YAP16_INST_INCF , `YAP16_INST_INCFSZ , `YAP16_INST_IORWF , `YAP16_INST_MOVF , `YAP16_INST_MOVWF , `YAP16_INST_RLF , `YAP16_INST_RRF , `YAP16_INST_SUBWF , `YAP16_INST_SWAPF , `YAP16_INST_XORWF : we <= instruction_i[7] ; `YAP16_INST_BCF , `YAP16_INST_BSF : we <= 1'b1 ; default : we <= 1'b0 ; endcase // casex end // alwaysendmodule // file_reg_controller// EOF file_reg_controller.v
2007.08.11
コメント(0)
ステータスレジスタの実装です。STATUSレジスタと呼ばれていますが、いわゆる「ステータスフラグ」としては、C(キャリー)、DC(デシマルキャリー),Z(ゼロ)ビットだけであとは別の目的に使われています。今回の実装では、ちょっと手を抜き、TO(ウォッチドッグタイマのタイムアウト)とPD(パワーダウン)はまだ、何もしていません。各フラグは、special functionレジスタとしてもアクセスできます。悩ましいのは、フラグの更新と、スペシャルファンクションレジスタとしての書き込みが同時起きたときに、どちらを優先するかですが、PICmicro Mid-Range MCU Family Reference Manualによると、フラグの更新が優先するのですね。また、命令ごとに更新されるフラグが異なることも注意が必要です。そこで、各フラグの更新信号を命令からデコードしてます。つぎに、各フラグごとに更新を行うようにしています。あ、あと、ちょっとポート名などに見直しもしました。次は、File Registerのコントローラの予定です。---本日の御託家内が近所のスーパーで、靴(というか、ミュールだな)の中敷を買ってきたが、よく見たら2つとも「左足」用だった。(大笑い)//// STATUS register// Section 4.2.2.1 Status Register//`include "yap16_instructions.h"`include "yap16_def.h"module status_reg( input clk_i, // system clock input reset_i, // usual POR input [(`YAP16_INST_WIDTH -1):0] instruction_i , input status_we_i, // write enable for status reg input [7:0] data_i, // data from write_bus output irp_o, // IRP output [1:0] rp_o, // bit6 rp1 bit5 rp0 output to_n_o, // bit4 TO_ output pd_n_o, // bit3 PD_ output z_o, // bit2 Z output dc_o, // bit1 DC output c_o, // bit0 C input z_next_i, // bit2 Z input dc_next_i, // bit1 DC input c_next_i // bit0 C) ;reg irp, to_n, pd_n, z, dc, c;reg [1:0] rp; reg z_we, dc_we, c_we ; // flag write (update) enable assign {irp_o, rp_o, to_n_o, pd_n_o, z_o, dc_o, c_o } = {irp, rp, to_n, pd_n, z, dc, c } ; always@ * begin //always@( instruction_i ) { z_we, dc_we, c_we } <= 3'b000 ; // reset all casex( instruction_i) `YAP16_INST_ADDWF , `YAP16_INST_SUBWF , `YAP16_INST_ADDLW , `YAP16_INST_SUBLW : { z_we, dc_we, c_we } <= 3'b111 ; `YAP16_INST_ANDWF , `YAP16_INST_CLRF , `YAP16_INST_CLRW , `YAP16_INST_COMF , `YAP16_INST_DECF , `YAP16_INST_INCF , `YAP16_INST_IORWF , `YAP16_INST_XORWF , `YAP16_INST_ANDLW , `YAP16_INST_IORLW , `YAP16_INST_XORLW : z_we <= 1'b1 ; `YAP16_INST_RLF , `YAP16_INST_RRF : c_we <= 1'b1 ; // No default part endcase // casex end // always // C bit bit 0 always@( posedge clk_i) begin if( reset_i == 1'b1 ) begin`ifdef FULL_RESET c <= 1'b0 ;`endif // FULL_RESET end // if else if ( c_we == 1'b1 ) begin c <= c_next_i ; end else if( status_we_i == 1'b1 ) begin c <= data_i[0] ; end end // always // DC bit bit 1 always@( posedge clk_i) begin if( reset_i == 1'b1 ) begin`ifdef FULL_RESET dc <= 1'b0 ;`endif // FULL_RESET end // if else if ( dc_we == 1'b1 ) begin dc <= dc_next_i ; end else if( status_we_i == 1'b1 ) begin dc <= data_i[1] ; end end // always // Z bit bit 2 always@( posedge clk_i) begin if( reset_i == 1'b1 ) begin`ifdef FULL_RESET z <= 1'b0 ;`endif // FULL_RESET end // if else if ( z_we == 1'b1 ) begin z <= z_next_i ; end else if( status_we_i == 1'b1 ) begin c <= data_i[2] ; end end // always // IRPi,IRP1,IRP0, bit[7:5] always@( posedge clk_i) begin if( reset_i == 1'b1 ) begin {irp, rp } <= 3'b000 ; end // if else if( status_we_i == 1'b1 ) begin {irp, rp } <= data_i[7:5] ; end end // always // to be implemented //to_n, // bit4 TO_ //pd_n, // bit3 PD_endmodule // status_reg// EOF status_reg.v
2007.08.10
コメント(0)
えー、コメントで指摘を受けたので、Verilog-2001を少しまじめにナナメ読みしてみました。主な変更点は、1)ポート宣言に、ANSI C風の宣言ができるようになった。2)多次元のarrayがつかえるようになった。3)always@のあとのセンシティヴィティ・リストに*が使えるようになった。4)generate文が使えるようになった。5)算術演算子にべぎ乗がつかえるようになった。てな、ところでしょうか1)、2)、5)は、便利というか、コーディングの量が減る。3)うーん、どうなんでしょう、@はもともと、変数の値の変化を「イベント」に「変換」する演算子なわけで、alwaysだけを特別扱いしてこんな拡張をするとは、なんと行き当たりばったりな・・・まあ、それをいうとVerilog-HDL自体が、アドホックな仕様ですけどね。単純ミスが減るので、よしとしましょう。4)イマイチ使いにくそう。私は、VHDLは「読めるけど、書けない」ので、絶対Verilog-HDL派なのだが、言語仕様上なんとかしてほしいと思うこともある。たとえば、module名のスコープはグローバルな上、事実上、一般的なコンピュータ言語でいうところの「ライブラリ」や「リンカ」の概念がなく、ソースコードレベルでリンクをするので、簡単にmodule名の「衝突」がおきてしまう。また、同じソースコードで異なるアーキテクチャを試すには、結局ifdefを使うくらいしか方法がない。2001ではgenerate文もあるけど・・・いっそのこと、System-Verilogに移行してしまうほうがよいか?とも思う。テストベンチ書くのがすごく便利。まあ、RTLは大差ないけどね。問題は、シュミでつかえるような処理系がみあたらないこと。菅原システムさんがんばってください(笑)。ということで、今日はお見せできるような成果はナシ。---本日の御託我が家は近くに公園があることもあって、この季節はミンミンゼミが夜明けまえからうるさい。ところが、庭に毎日のように「落ちてる」のはなぜかアブラゼミばかり。なぜだろう?で、この「落ちてる」やつが、「ったく、こんなところで死んでんじゃねえよ・・・」と拾おうとすると、実はまだ生きていて、飛んでいったりする。気の小さい家内などは、文字どおり「飛び上がって」びっくりしている。
2007.08.09
コメント(0)
今日は、ALUの右側入力に接続されているデータセレクタです。このデータセレクタは、演算系の命令で、オペランドをファイルレジスタからとるか、リテラル(イミディエイト)として、インストラクションの一部からとるかを選択するものです。記述は下記のように単純なものです。例によって、alwaysブロックの最初で、出力にx(Don't care)を代入して、必要に応じて、ファイルレジスタから(read_bus_i)か、インストラクションのLSB8ビット(instruction_i[7:0])からかを選択し、ALUの右側入力(bbus)に出力します。命令によっては(たとえばGOTO命令)ALUは使われないため、このような場合は、xを出力しています。 あと、今回からmoduleのポート宣言は、いわゆるANSI C式に変えました(Verilog2000).---本日の御託うちの家内が好きなカワイイ動物は -シロクマ(ホッキョククマ) -シマリス -ミナミコアリクイ(マニアックだな...笑)もちろん、子猫とかも好きだけど・・・で、ベルリン動物園のホームページからシロクマの赤ちゃん、「クヌート」の動画をダウンロードしてきてあげたら喜んでいた。確かにかわいい。ベルリン動物園は株式会社で、クヌート人気で株価が急上昇したそうである。そういえば、クヌート(Knut)はクヌース(Knuth,アルゴリズムの大家、TeXとか作った人)と一字違いだな。(それだけ) //// Literal data seledctor// (c)2007 BakaOyaji// $Id////`include "pic_instructions.h"`include "pic_def.h"module literal_dsel( input [(`Instruction_Len-1):0] instruction_i, input [7:0] read_bus_i , // data from READ BUS output [7:0] b_o // feeding data to b_bus); reg [7:0] b_o ; always@( instruction_i or read_bus_i) begin b_o <= 8'bxxxx_xxxx ; casex( instruction_i) // Byte oriented File Register Operations `INST_ADDWF , `INST_ANDWF , `INST_COMF , `INST_DECF , `INST_DECFSZ , `INST_INCF , `INST_INCFSZ , `INST_IORWF , `INST_MOVF , `INST_RLF , `INST_RRF , `INST_SUBWF , `INST_SWAPF , `INST_XORWF , `INST_BCF , `INST_BSF , `INST_BTFSC , `INST_BTFSS : b_o <= read_bus_i ; `INST_ADDLW , `INST_ANDLW , `INST_IORLW , `INST_MOVLW , `INST_RETLW , `INST_SUBLW , `INST_XORLW : b_o <= instruction_i[7:0] ; default : b_o <= 8'bxxxx_xxxx ; endcase // casex end // alwaysendmodule //literal_dsel// EOF literal_dsel.v
2007.08.08
コメント(2)

まず、報告を・・・。VritakのインテルHEXファイルを読むための機能、$convert_hex2verの不具合というか、ちょっと困った点だが、バージョン3.38Gで修正を確認した。日曜日に3.38Gがリリースされているのに気がついていたのだが、確認が遅くなってしまった。詳しくは、VeritakのFAQの429および431を参照してください。「菅原システム」さん、週末だというのに迅速な対応多謝。あまり、無理しないでね。さて、ALUとWレジスタを加えたテストだが、問題はなさそうである。波形の一部はこんな感じ。ALUの右側の入力(bbus)は、インストラクションの下位8ビットに直結しているので、演算命令はリテラル系の命令しか正しく動作しませんが、各フラグも正しく立っているようです。もっとも、ステータスレジスタの実装がまだなので、「保存」ができていないですけど。SKIP命令も問題なく動作するようですね。次回は、ALUの右側の入力に接続されている、ファイルレジスタのデータとリテラル系命令のデータを切り替えるデータセレクタの実装の予定。---- 本日の御託ケーブルTVでやっていた「キャプテンスカーレット」を見た。ジェリー・アンダーソンが、「サンダーバード」の次(要確認)に作った作品。当時は「サンダーバード」より面白いと思ったが、今見てみるとそれほどでもなかった。オリジナルの主題歌(多分、NHKで最初に放送したときのみ使われた。その後、日本語の別の歌になったはず)はちょっと懐かしい。スペクトラム基地(Cloud Baseっていうんだね)や追跡戦闘車(衝撃に備えて乗員は後ろ向きに乗車する(笑))とかはプラモデルを作ったな。また、ミニチュアセット(でいいのかな?)のシュミの良い未来的インテリアは「プリズナーNo.6」と明らかに共通性を感じさせる。エンジェルたちの乗る戦闘機は、ペンシル型の胴体、相対的に小さい翼、T尾翼など、「F-104スターファイター」の影響が感じられる。F-104は単発ジェットのため、エンジンが故障すると墜落である。そこで、「ウィドウ・メーカー」なんて、不名誉あだ名もある。ちょっと調べたら「U-2」ってベースなんだね。知らなかった。
2007.08.07
コメント(0)
今日は、ワークレジスタです。ワークレジスタは、File Register Operations系の命令の場合は、dフィールドが0の場合に更新、後は、リテラル系の命令のうち、ワークレジスタが対象の場合に更新され,それ以外では値はそのままなので、ソースコードはこんな感じでしょう。これで、ALUとワークレジスタができたので、演算系の命令も試して見れるようになりました。次回は、ALUとワークレジスタに加え、またプログラムをちょこっと動かしてみることにします。---- 本日の御託暑いので、コーラを買って、職場の冷蔵庫に入れようとしたら、「なめこおろし」があった。どういう、会社だ...//// Work register// (c)2007 BakaOyaji// $Id$//`include "pic_instructions.h"`include "pic_def.h"module w_reg( clk_i, full_reset_i, reg_o, reg_i, instruction_i // prefetched instruction from instruction reg.) ;input clk_i, full_reset_i ;output [7:0] reg_o ;input [7:0] reg_i ;input [(`Instruction_Len-1):0] instruction_i ;reg [7:0] w ; assign reg_o = w ; always@( posedge clk_i) begin if( full_reset_i == 1'b1 ) begin w <= 8'b0000_0000 ; end else begin casex( instruction_i) // Byte oriented File Register Operations `INST_ADDWF , `INST_ANDWF , `INST_COMF , `INST_DECF , `INST_DECFSZ , `INST_INCF , `INST_INCFSZ , `INST_IORWF , `INST_MOVF , `INST_RLF , `INST_RRF , `INST_SUBWF , `INST_SWAPF , `INST_XORWF : begin if( instruction_i[7] == 1'b0 ) begin w <= reg_i ; end //if end // Literal and control Operations and CLRW `INST_ADDLW , `INST_ANDLW , `INST_IORLW , `INST_MOVLW , `INST_RETLW , `INST_SUBLW , `INST_XORLW , `INST_CLRW : begin w <= reg_i ; end default : ; // hold, nothing to do endcase // casex end // else end // alwaysendmodule // w_reg// EOF w_reg.v
2007.08.06
コメント(0)
ALUのソースコード (一部省略) //// ALU ////// Based on section 15.0 , TABLE 15-2: PIC16F627A/628A/648A INSTRUCTION SET// PIC16F627A/628A/648A// (c) 2007 BakaOyaji// $Id$//`include "../pic_def.h"`include "../pic_instructions.h"module alu( y_o, a_i, b_i, c_o , dc_o, z_o , skip_o , c_i , instruction_i);output [7:0] y_o ;input [7:0] a_i, b_i ; // Abus Bbus inputoutput c_o , // carry out dc_o,// decimal carry out z_o ,// zero out skip_o; // test flaginput c_i ; // carry ininput [(`Instruction_Len-1):0] instruction_i ;reg [7:0] y_o ;reg c_o , dc_o, z_o, skip_o ;reg [2:0] bbb; // bbb slice in instruction always@( a_i or b_i or c_i or instruction_i ) begin bbb = instruction_i[9:7]; // reset everything here. hints for synthesis c_o = 1'bx ; dc_o = 1'bx; z_o = 1'bx ; y_o = 8'bxxxx_xxxx ; // skip flug must be strictly fully maintained skip_o = 1'b0 ; casex (instruction_i ) `INST_ADDWF , `INST_ADDLW : begin // { c_o , y_o } = {1'b0, a_i } + b_i + c_i ; { c_o , y_o } = a_i + b_i + c_i ; dc_o = ( y_o[3:0] > 'd9 ) ? 1'b1 : 1'b0 ; z_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end `INST_ANDWF , `INST_ANDLW : begin y_o = a_i & b_i ; z_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end `INST_CLRF , `INST_CLRW : begin y_o = 8'b0000_0000 ; z_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end `INST_COMF : begin y_o = ~b_i ; z_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end `INST_DECF , `INST_DECFSZ : begin y_o = b_i - 1'b1 ; if ( instruction_i == `INST_DECF ) begin z_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end // if else begin skip_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end // else end `INST_INCF , `INST_INCFSZ : begin y_o = b_i + 1'b1 ; if ( instruction_i == `INST_INCF ) begin z_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end // if else begin skip_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end // else end `INST_IORWF , `INST_IORLW : begin y_o = a_i || b_i ; z_o = ( y_o == 'h00 ) ? 1'b1 : 0 ; end `INST_MOVF : y_o = b_i ; `INST_MOVWF : y_o = a_i ; `INST_RLF : {c_o, y_o } = { b_i, c_i} ; `INST_RRF : {y_o, c_o } = { c_i, b_i} ; `INST_SUBWF , `INST_SUBLW : begin // physical adder can be shared with ADDWF, ADDLW { c_o , y_o } = b_i - a_i - ~c_i ; dc_o = ( y_o[3:0] > 'd9 ) ? 1'b1 : 1'b0 ; z_o = ( y_o == 'h00 ) ? 1'b1 : 0 : default : begin // nothing to do end endcase end // alwaysendmodule // ALU// EOF ALU.v
2007.08.05
コメント(0)
すっかり、「昼休みにまったり」というより、「週末にヤケクソ」というペースになっていますが、今回はALUです。(コードは最後に載せます)7/12の記事の図のALUの右側の入力をA、左側の入力をB、出力をYとします。出力には、ステータスレジスタへの各フラグのほかに、スキップ系の命令のスキップの条件を表す、skipという信号を追加しています。ALUは組み合わせ回路ですが、alwaysブロックで実装しています。alwaysブロックの中での代入文は強いて、ブロッキング代入(=)を使用しています。こういう書き方が嫌われることがあるのは、知っていますが、副作用(代入後の結果)を積極的に使いたいためです。たとえば、zフラグの生成などに、yの代入後の値を参照しています。 また、skipフラグ以外の出力に関して、alwaysブロックのはじめで、xを代入しています。その後、必要な場合のみ代入する形にしています。こういう書き方をすることで、論理合成時に意図しないラッチができてしまうことを防げます。また、この書き方は(まえにも書きましたが、)「Don't care」を表すため、デコーダのロジックを最小にするためのヒントを論理合成ツールに与えることにもなります。あとは、だらだらとcasex文でデコーダを書いています。書きあがってから、気がつきましたが、加算と減算は同じ部分でデコードするようにして、加算器をひとつに減らすこと(リソースシェアリング)ができますね。後で直せばいいことにしましょう...---- 本日の御託庭の芝生に、コガネムシの幼虫がいる。一匹見つけて捕まえたのだが、あとで庭を見ていたら、スズメが別のを見つけて、咥えていた。さすがに、スズメには大きすぎるので、そうとう苦戦した末、咥えたままどこかに飛んでいってしまった。農薬を撒けばいいのだが、クモなどの益虫にも害があると思うと、ちょっと躊躇する。
2007.08.05
コメント(0)
例によって、文字数制限に引っかかるので、一部省略 //// Reverse assembeler of PIC// (c)2007 BakaOyaji// $Id////`include "../pic_instructions.h"`include "../pic_def.h"module reverse_asm ( instruction_i); input [(`Instruction_Len-1):0] instruction_i;reg [15*8-1:0] str_inst ; // string to monitorreg d ;reg [6:0] f;reg [2:0] b ;reg [7:0] k8 ;reg [10:0] k11 ; always@( instruction_i ) begin d = instruction_i[7] ; f = instruction_i[6:0] ; b = instruction_i[9:7] ; k8 = instruction_i[7:0] ; k11 = instruction_i[10:0] ; casex( instruction_i) // Byte oriented File Register Operations `INST_ADDWF : str_inst = { "ADDWF ", hex2(f), ",", hex(d) } ; `INST_ANDWF : str_inst = { "ANDWF ", hex2(f), ",", hex(d) } ; `INST_CLRF : str_inst = { "CLRF ", hex2(f) } ; `INST_CLRW : str_inst = "CLRW" ; `INST_COMF : str_inst = { "COMF ", hex2(f), ",", hex(d) } ; `INST_DECF : str_inst = { "DECF ", hex2(f), ",", hex(d) } ; `INST_DECFSZ : str_inst = { "DECFSZ ", hex2(f), ",", hex(d) } ; `INST_INCF : str_inst = { "INCF ", hex2(f), ",", hex(d) } ; `INST_INCFSZ : str_inst = { "INCFSZ ", hex2(f), ",", hex(d) } ; `INST_IORWF : str_inst = { "IORWF ", hex2(f), ",", hex(d) } ; `INST_MOVF : str_inst = { "MOVF ", hex2(f), ",", hex(d) } ; `INST_MOVWF : str_inst = { "MOVWF ", hex2(f) } ; `INST_NOP : str_inst = "NOP" ; `INST_RLF : str_inst = { "RLF ", hex2(f), ",", hex(d) } ; `INST_RRF : str_inst = { "RRF ", hex2(f), ",", hex(d) } ; `INST_SUBWF : str_inst = { "SUBWF ", hex2(f), ",", hex(d) } ; `INST_SWAPF : str_inst = { "SWAPF ", hex2(f), ",", hex(d) } ; `INST_XORWF : str_inst = { "XORF ", hex2(f), ",", hex(d) } ; // BIT-Oriented File Register Operations `INST_BCF : str_inst = { "BCF ", hex2(f), ",", hex(b) } ; `INST_BSF : str_inst = { "BSF ", hex2(f), ",", hex(b) } ; `INST_BTFSC : str_inst = { "BTFSC ", hex2(f), ",", hex(b) } ; `INST_BTFSS : str_inst = { "BTFSS ", hex2(f), ",", hex(b) } ; // Literal and control Operations : : default : str_inst = "ERROR!" ; endcase // casex end // alwaysendmodule //reverse_asm()// EOF reverse_asem.v
2007.08.05
コメント(1)

最近、ど~も週末でも朝早く目が覚めてしまう。歳はとりたくないものである...というわけで、手段と目的が逆転してますが(笑)逆アセンブラ用のモジュールも作ってみた(ソースコードは次のページ)。最初はちょっと凝ったことも考えて、たとえば、ファイルレジスタの現在のバンクも併せて表示するようにしようとかも考えたのだが、よく考えたらそういう情報は別に波形で表示できるわけだし、複雑なものを作ると、デバッグが大変になってしまう。(もともとデバッグ用のモジュールなので、)これでは何をやっているかわからないので、結局思いっきりシンプルな実装にしました。なんの工夫もありません。モジュール内の、str_instを波形ビューアで見れば入力の命令を表示してくれます。また、モジュールを2つインスタンスして、インストラクションレジスタ(パイプラインレジスタ)の前後をモニターさせることもできます。昨日と同じアセンブラのコードを実行した結果はこんな感じ。表示を拡大しないと、逆アセンブルした命令が読めないので、一部しか表示してませんが、問題なさそうです。というわけで、W-REG、ALUあたりを次は実装していきます。----本日の御託 昨晩、テレビをザッピングしてたら、象がでてた。あぁ、「かわいそうなぞう」の話だなとピンと来てチャンネルを変えた。前にも書いたが、どうもこの話は涙腺のスイッチが入ってしまうんだよねぇ...ちなみに、家内は「ごんぎつね」で涙腺のスイッチが入ってしまうらしい。
2007.08.05
コメント(0)

せっかくの週末なのに、家内が遊んでくれない(なぜだー)ので、出来上がったところだけで、CPUの動作を確認していきます。前にも書いたように、集中型のインストラクションデコーダではなく、できるだけ個々のモジュールに必要なデコーダを持たせることにしたので、こんなことができる。おっと、せっかくなのでその前に名前をつけましょう。いろいろ考えたのですが、月並みですがYAPと名づけることにします。そうそう、巨大な石のお金で有名な南の島ですね、じゃなくて、Yet Another PICです(笑)。 ソースコードは、CPUがこんな感じ。// (c) 2007 BakaOyajimodule cpu( clk_i, reset_i, addr_o, instruction_i) ; input clk_i ; input reset_i ; output [15:0] addr_o ; input [13:0] instruction_i ; wire skip ; wire flush ; wire [13:0] instruction ; assign skip = 1'b0 ; ir i_ir( .clk_i(clk_i), .reset_i(reset_i), .skip_i(skip) , .instruction_i(instruction_i) , .instruction_o(instruction), // the instruction to execute .flush_o(flush) ); pc i_pc( .clk_i(clk_i), .reset_i(reset_i), .por_i(reset_i) , .instruction_i(instruction), .data_i( 8'b0 ) , // from FileReg write bus .pcl_we_i( 1'b0) , // write enable for pcl .program_counter_o( addr_o), // out put of program counter .pclath_i(8'b0), // from PCLATH reg .force_call4_i( 1'b0), // force call 0004 .hold_i(1'b0), // hold current address .pcl_o() // pcl );endmodule // pc適当ですね。まだ、実装してない機能に関連する部分は、入力は0固定にしています。CPUとコードメモリをあわせた部分はこんな感じ。// test PIC module// (c)2007 BakaOyajimodule yap( clk_i, reset_i ) ; input clk_i ; input reset_i ; wire [15:0] addr ; wire [13:0] code_data ; cpu i_cpu( .clk_i( clk_i), .reset_i(reset_i), .addr_o(addr) , .instruction_i(code_data ) ) ; codemem i_codemem ( .addr_i( addr) , .data_o(code_data) ) ;endmodule // yap これに、MicroChipのMPLAB用のアセンブラで適当なプログラムを書いて、HEXファイルを作ります。とりあえず、こんなプログラムを作りました。0000 00024 STARThere org 000000 0780 00025 addwf 0,10001 0781 00026 addwf 1,10002 2010 00027 call sub10003 0782 00028 addwf 2,10004 2011 00029 call sub20005 0782 00030 addwf 2,10006 2809 00031 goto branch0007 0000 00032 nop0008 0000 00033 nop0009 07B0 00034 branch addwf 30,1000A 0000 00035 nop000B 0000 00036 nop000C 2800 00037 goto 0 00038 0010 00039 sub1 org 100010 0008 00040 return 00041 0011 00042 sub20011 0790 00043 addwf 10,10012 2015 00044 call sub30013 0008 00045 return0014 0791 00046 addwf 11,10015 00047 sub3 0015 0008 00048 returnで実行するとこんな感じ。分岐後の強制NOPもちゃんと働いているし、サブルーチンコールからもちゃんと戻ることができてます。ここで見る限りは「バッチグー」ですね。でも、16進数で命令をトレースするのはちょとキツイな...トレース用の逆アセンブラを作る方がよさそう...---- 本日の御託いや~、シュミでVerilogのコードを書いたりするのは楽しいね~。納期はないし、手段と目的が逆になっても(仕事でもそうなっている人を時々見かけるが)だれも文句を言わないし...(笑)
2007.08.04
コメント(0)
文字数制限に引っかかってしまうので、肝心なところだけ //// (c)2007 BakaOyaji begin : readandwrite ifp = $fopen( infile_name, "r" ) ; if( ifp == 0 ) begin error_code = `IHEX_ERROR_READOPEN; disable readandwrite ; end // if ofp = $fopen( outfile_name, "w" ) ; if( ofp == 0 ) begin error_code = `IHEX_ERROR_WRITEOPEN; disable readandwrite ; end byteperword = (bitperword+7)/8 ; // need to check the varid range forever begin // perform a line if( $fgets( linebuf , ifp) == c_EOF ) begin error_code = `IHEX_ERROR_UNEXPECTED_EOF ; disable readandwrite ; end begin : find_comma // find ':' for( i = 0 ; i < `IHEX_MAXSTRLENGTH ; i = i+1 ) begin if( linebuf [(i*8) +:8] == ":" ) begin disable find_comma ; // found end // if if( linebuf [(i*8) +:8] == 8'h00 ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if end // for // line is too long error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // find_comma i = i -8 ; if( i < 2 ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if record_type = hex2int2( linebuf[(i*8) +: 16 ]) ; offset = hex2int4( linebuf[((i+2)*8) +: 32] ) ; record_length = hex2int2( linebuf[((i+6)*8) +: 16] ) ; if( ( record_length == -1 ) || (offset == -1 ) || (record_type == -1 ) ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if case( record_type ) `IHEX_REC_DATA : begin $fwrite( ofp , "@%4h ", (segment + offset)/byteperword ) ; repeat( record_length / byteperword ) begin i = i - 2 * byteperword ; if( i < 0 ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if j = i ; repeat( byteperword ) begin // put a word $fwrite( ofp , "%2s", linebuf[(j*8) +: 16] ) ; j = j+2 ; end // repeat $fwrite( ofp , " "); end // repeat $fwrite( ofp, "\n" ) ; end : : endcase end // forever end // readandwrite
2007.08.04
コメント(0)
PICを作ろう ,インテルHEXを読む(4) ~昼休みにまったり進めるプロジェクト~え~、たっくさんにスルドイツッコミをいただいてしまいました。というわけで、Verilog2001のLRM(Language Reference Manual,IEEE-1364-2001)を眺めてみたところ、[ +: ](または[ -: ])という部分ビット列の抽出演算子が追加されていて、右側(開始点)には一般式が使えることがわかった(LRMのセクション4.2.1 Vector bit-select and port-select addressing、52~53ページあたり)。これで、だいぶ文字列の扱いが楽になる。でもって、taskを書き直してみた。文字列の操作が楽にできるようになったので、データレコードのデータ列は、いままで数に変換していたが文字のまま吐き出すように、変更したのでますますエラーチェックはいい加減になった。ビット幅の値が、8の倍数でない場合も特にマスキングはしていないが、Verilog-HDLの$readmemh()で読み込むときに、余ったビットは捨てられるはずなので、このままでも問題はないだろう。突っ込みどころ満載(笑)で、次回は(今度こそ)、簡単なプログラムを動かす予定。---本日の御託LG電子、ブルーレイ/HD DVD両規格対応のドライブ、発売へ。なんかなー。ソニーとか、松下とか、東芝とか、セイジやカケヒキにかまけているとこういうことになる。(おっとソースコードが入らないや)
2007.08.04
コメント(0)
え~、もう少しインテルHEXファイルを読む話です。Veritakには、そのためのシステムタスクがある話しは昨日書いたけど、自分で書いたものが同じ結果が出るか、とりあえず確認しました。一応OKっぽいです。:100000000007000030280000000000000000000091:0E0010000000000000000000000000000000E2:04006000103E113EFF:00000001FF入力データ@00000000 00 07 00 00 30 28 00 00 00 00 00 00 00 00 00 00 @00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 @00000060 10 3E 11 3E 出力(莫迦オヤジ版)Veritakの$convert_hex2ver()は、入力のデータを、nビット単位でまとめて読む機能があります。もともとインテルHEXはバイトオリエンテッドなフォーマットなのですが、確かにこの機能があると便利そうです。PIC16シリーズのコードメモリは14ビットなのですが、HEXファイルからの読み込みを考えて、2007/07/31の記事では8ビット単位の実装にしてあります。(つまり、2ビット無駄にしているということ) ということで、$convert_hex2ver()のこの機能をパクることにします。コードはますます汚くなるがしょうがないですね。同じ入力データで、今度は16ビット単位で読んだ場合の結果は以下のとおり、@00000000 0700 0000 2830 0000 0000 0000 0000 0000 @00000008 0000 0000 0000 0000 0000 0000 0000 @00000030 3E10 3E11 出力(莫迦オヤジ版、16ビット単位)@00007 0000 3028 0000 0000 0000 0000 0000 @100000 0000 0000 0000 0000 0000 0000 @60103e 113e 出力(Veritak ver3.21Aの$convert_hex2ver()、16ビット単位)一致しません・・・orz。Veritakのバージョンを3.21Aから、3.38F(2007/8/4現在の最新版)に変えましたが、結果は同じ。(2007/8/8追記:Version3.38Gで対応済み。FAQ431)相違点は以下の2点 1)16ビット(2バイト)データのLSB,MSBが逆 2)アドレスが、$convert_hex2ver()の場合は、HEXファイルのアドレスと同じ。1)は、もともとバイトオリエンテッドなデータを、多バイトで解釈しようとするところに若干ムリがあるように思うが、インテル系のCPUがLitte Endianということを考えると、莫迦オヤジ版の方が自然に思える。2)は、アドレスはバイトオフセットではなく、ワードオフセットでないとおかしいと思うのだが?たとえば、莫迦オヤジ版の出力の3ワード目(2830)は もともとPIC16の「GOTO 30」という命令であるから、30番地に命令がないとおかしなことになる。 ということで、そのうちVeritakの開発元に確認をしてみよう...----本日の御託「Little Endian」,「Big Endian」は、複数バイトのデータを表現をする場合に、LSBから順にアドレスの小さい方から並べるか(Little Endian)、MSBから並べるか(Big Endian)を表すJargon。インテル系のMPUとモトローラ系のMPUの性格の違いの一端を表す面白い表現。もともとは、スイフトの「ガリバー旅行記」の卵を割るときに、尖った方から割ることを是とする種族(Litte Endian)と丸い方から割ることを是とする種族(Big Endian)からとった言い方だそうだ。物語では、この些細な違いにおいて二つの種族がいがみ合っていることを、揶揄する内容なのだが、コンピュータの世界でこの表現を使い始めたのはだれなのだろう?
2007.08.04
コメント(0)
「たっくさん」に指摘されてしまったが、今使っている、Verlogシミュレータ、Veritakには、独自の拡張として、$convert_hex2verというシステムタスク(組み込みタスク)がある。だが、$convert_hex2ver:ERROR Unknown record type.というエラーが出てしまい、MPLAB(7.6)のHEXファイルがうまく読めないのだ。(2007/8/8追記:Ver3.38Gで問題なくなりました。FAQ429)MPLABの出力した、HEXファイルをダンプしてみる。:020000040000FA:10000000000700003028000000000000 :どうも、最初の行の「拡張リニアアドレス」(レコードタイプ04)レコードに対応していないようですね。というわけで、だいたい同じものを自分で作りました。ソースコードはこんな感じ。//// (c)2007 BakaOyaji//`include "ihex2verilog.h"task ihex2verilog; input [799:0] infile_name ; output [799:0] outfile_name ; output integer error_code ; integer ifp, ofp ; integer record_length , offset ,record_type, data, segment ; integer c_EOF ; // constant reg [300*8*2-1:0]linebuf ; reg [7:0] strbuf [300*2-1:0] ; integer i ;begin c_EOF = -1 ; // constant segment = 0 ; outfile_name = { infile_name, ".ver" } ; begin : readandwrite ifp = $fopen( infile_name, "r" ) ; if( ifp == 0 ) begin error_code = `IHEX_ERROR_READOPEN; disable readandwrite ; end // if ofp = $fopen( outfile_name, "w" ) ; if( ofp == 0 ) begin error_code = `IHEX_ERROR_WRITEOPEN; disable readandwrite ; end forever begin // perform a line if( $fgets( linebuf , ifp) == c_EOF ) begin error_code = `IHEX_ERROR_UNEXPECTED_EOF ; disable readandwrite ; end // copy string begin : copy for( i = 0 ; i < 300*2 ; i = i+1 ) begin strbuf[i] = linebuf ; linebuf = linebuf >> 8 ; if( strbuf[i] == ":" ) begin disable copy ; // end of copy end // if if( strbuf[i] == 8'h00 ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if end // for // line is too long error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // begin : copy // get record_length(=2digits), offset(4),record_type(2), // total 8digit i = i -8 ; if( i < 2 ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if record_type = hex2int2( { strbuf[i+1] , strbuf[i]} ) ; offset = hex2int4( { strbuf[i+5] , strbuf[i+4], strbuf[i+3] , strbuf[i+2]} ) ; record_length = hex2int2( { strbuf[i+7] , strbuf[i+6]} ) ; if( ( record_length == -1 ) || (offset == -1 ) || (record_type == -1 ) ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if case( record_type ) `IHEX_REC_DATA : begin $fwrite( ofp , "@%4h ", segment + offset ) ; repeat( record_length ) begin i=i-2 ; if( i < 0 ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if data = hex2int2( { strbuf[i+1] , strbuf[i]} ) ; if( data == -1 ) begin error_code = `IHEX_ERROR_UNEXPECTEDFORMAT ; disable readandwrite ; end // if $fwrite( ofp , "%2h ", data[7:0] ) ; end // repeat $fwrite( ofp, "\n" ) ; end `IHEX_REC_END : begin error_code = `IHEX_NOERROR ; disable readandwrite ; end `IHEX_REC_EXTENDEDADDR : begin segment = offset << 4 ; end `IHEX_REC_STARTADDR : begin $display("%m Warning, Start Address record, Ignored"); end `IHEX_REC_EXTENDEDLINERADDR : begin segment = offset << 16 ; end `IHEX_REC_EXTENDEDLINERSTARTADDR : begin $display("%m Warning, Extended Liner Start Address record, Ignored"); end default : begin error_code = `IHEX_ERROR_UNEXPECTED_RECORD ; disable readandwrite ; end // CheckSum calc shuld be add around here, not inplemented yet endcase end // forever end // begin : readandwrite // errorhandle if( error_code == `IHEX_ERROR_READOPEN ) begin end else if ( error_code == `IHEX_ERROR_WRITEOPEN ) begin $fclose( ifp ) ; end else begin $fclose( ifp ) ; $fclose( ofp ) ; endendendtask // ihex2verilogfunction integer hex2int ; input [7:0] c ;begin if( "0" <= c && c <= "9" ) begin // '0' <= c <= '9' hex2int = c - "0" ; end // if else if( "A" <= c && c <= "F" ) begin // 'A' <= c <= 'F' hex2int = c - "A" + 'ha ; end // else if else if( "a" <= c && c <= "f" ) begin // 'a' <= c <= 'f' hex2int = c - "a" + 'ha ; end // else if else begin hex2int = -1 ; // error, out of range end // else endendfunction //hex2int ;function integer hex2int2 ; input [8*1+7:0] str ; integer msnibble, lsnibble ;begin msnibble = hex2int( str[8*1+7:8*1] ) ; lsnibble = hex2int( str[7:0] ) ; if( (lsnibble == -1) || (msnibble== -1)) begin hex2int2 = -1 ; end // if else begin hex2int2 = (msnibble << 4 ) + lsnibble ; end // elseendendfunction //hex2int2 ;// 4 digit versionfunction integer hex2int4 ; input [8*3+7:0] str ; integer msb, lsb ;begin msb = hex2int2( str[8*3+7:8*2] ) ; lsb = hex2int2( str[8*2+7:0] ) ; if( (lsb == -1) || (msb== -1)) begin hex2int4 = -1 ; end // if else begin hex2int4 = (msb << 8 ) + lsb ; end // elseendendfunction //hex2int4 ;`includeしているファイルは、`IHEX_xxx のマクロ定義をしています。なんか、汚いコードですね(笑)。Verilog-HDLにおける文字列の取り扱いは、ビット列になります。1文字=8bit と、考えれば8*(文字数)の長さのビット列であつかうのですが、いざコードを書いてみるといろいろな問題にぶち当たります。まず、代入ですが、ビット列で扱っているため、いわゆる右詰めで、余ったところには、'h00がはいることになります。したがって、文字列を前からスキャンするにはちょっと工夫が必要です。また、Verilogでは、ビット列の部分列を取り出す演算子[:]があるのですが、この中には定数式しかつかえません。このおかげで、一日分の書いたコードをほとんど無駄にしてしまいました(忘れてました、orz...)。仕方ないので、今回は8ビット幅の配列に一回コピーして、作業をしています。 begin : copy : のあたりが、それに相当します。また、部分ビット列の取り出しに定数式以外が使えないので、一番右から処理するので、forループの中で、 strbuf[i] = linebuf ; linebuf = linebuf >> 8 ;としています。linebufは4800ビット(600バイト)の長さがありますので、この部分はすんごいオーバーヘッドが多そうです。さらに、一度キャラクター単位にしたものを、 {strbuf[i+1] , strbuf[i]}として、文字列(=ビット列)に戻したりとかやってます(なにやってんだか…)。まあ、このtaskの性格から言って、繰り返し使われるわけではないので、いいことにします。あとは、少しでも見通しをよくするため、disable文を大域脱出のために、多用しています。大域脱出したい部分を、名前付ブロック(named block)にし、大域脱出するときに、そのブロックをdisableします。 begin : readandwrite : disable readandwrite ; : endこんな感じ。c言語と違って、breakやcontinueに相当するしかけがないために、このような書き方をVerilogでは良くします。このほかに、再トリガー付のワンショット(retriggable one-shot)マルチバイブレータをモデリングする際にも使いますが、これは、ウォッチドッグタイマの時にでも再度書くことにします。 あと、チェックサムの計算はしていません。RS-232でROMライタに送るわけではないので、これもネグります。さて、これで、プログラムカウンタとインストラクションレジスタ、さらにHEXファイルで初期化可能なコードメモリが準備できたので、次回はプログラムを動かしてみます。---本日の御託林野庁「緑のオーナー制度」で元本割れ・リスク示さずひでえニュース。民間企業でこんなことやったら間違いなく出資法違反に問われると思うぞ。もちろん、儲かっていれば誰も文句はいわんだろうが・・・
2007.08.03
コメント(2)
インテルHEXファイルのフォーマットだが、適当なページが見つからない。VectorのインテルHEXツールに同梱されている「インテルHEXフォーマットについて.txt」という資料が役にたった。インテルHEXファイルを読んで、Verilogの$readmemhで読める形式のファイルに変換するtaskを作っているが、ちょっとデバッグに手間取っている... Verilogって文字列操作とかはマジで向いてない...orz----本日の御託寝言編。家内によると私は非常にはっきり寝言を言うことがあるらしいが、この間は、ひとしきりむにゃむにゃいっていたとおもったら、大声で「だめじゃん、東芝!」と言って、またいびきをかいて寝てしまったらしい。東芝のなににダメだししていたのだろう...(笑)
2007.08.02
コメント(2)
全26件 (26件中 1-26件目)
1
![]()

![]()