Dies Aliquanti

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PICを作ろう ,RCS ~昼休みにまったり進めるプロジェクト~

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

スポンサーサイト

PICを作ろう 新逆アセンブラ ~昼休みにまったり進めるプロジェクト~

逆アセンブラを新調しました。今までのものと異なり、特別なレジスタに関してはレジスタ名を、さらに一部のレジスタではビット名も表示できるようにしました。これでだいぶデバッグが楽になります。Veritakのちょっとした「クセ」に嵌ってしまいました。

新逆アセンブラ
---
本日の御託
月食は見られませんでした...



PICを作ろう timer1 ~昼休みにまったり進めるプロジェクト~

デバッグもちょっと飽きたので、PIC16F648Aへの対応を少し考えました。timer1という16ビットのタイマがあるのですが、これがアタマが痛いですね。同期モードと非同期モードがあるのですが、非同期モードでので、タイマの読み書きが問題です。書き込みのほうは原則的に、タイマを停止した状態で書き込みをしなさい、とのことなので、何とかなりそうですが、問題は読み出しですね。読み出しは特別なことをしなくても正しく読み出せることになっているので、ひと工夫しないといけないです。うぅぅ。
---
本日の御託
 今週は、首藤さんは夏休みか・・・ちぇっ



PICを作ろう ,近況報告 ~昼休みにまったり進めるプロジェクト~

え~、しばらく更新をしていなかったが、何にもしていなかったわけではありません。
実は、PIC16F84A相当のモノは既に出来上がっていて、デバッグをしています。
まあ、よく判っていないPICのアセンブラをテキトーに使いながら、テストプログラムを書いている(笑)のだが、期待どおりに動作してない場合、Verilogのコードに誤りがあるのか、そもそもアセンブラのプログラムがおかしいのか解析するのに時間がかかってしまう。バグそのものは単純なものがほとんどなのだが、単純なものほどツボに嵌ると、わけが判らなくて困る。そんなこんなでなかなか先に進まない状態。

 前回timer0ユニットのいい加減なコードを載せたが、これも問題ありだ。timer0そのものは、PICのマスタークロックのクロックドメインに属しているが、プリスケーラはそうではない。プリスケーラ→timer0については、ダブルラッチによるシンクロナイザがPICのデータブックにあるブロックダイアグラムにも示されていて、いわゆるCDC(Clock Domain Crossing)問題は一応ケアされている。
 問題は、逆方向。プリスケーラは、timer0に対する書き込みで、リセットされることになっている。前回載せた実装では、単純にハザードフリーのリセット信号を非同期リセットとして与えているが、うるさく言うとこれではCDCに関しては失格だ。どうすっかな・・・
----
本日の御託
 暑い...

PICを作ろう ,Timer0 ~昼休みにまったり進めるプロジェクト~

今日は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 free
endmodule // timer0_reg
// EOF timer0_reg.v



PICを作ろう ,WDTとクロックジェネレータ ~昼休みにまったり進めるプロジェクト

 WDT(ウォッチドッグタイマ)とクロックジェネレータです。WDTはもともと(私にとっては)どーでもいい部分(だって使うつもりないもん)だし、SLEEP命令も使うつもりはないので(したがって、クロックも止める必要なし)、完全にビヘイビアモデルで実装。
WDTのリトリガブルワンショットは、Verillog-HDLの規格書(IEEE-1364.2001)に類似の例があります。
(う~ん、意外にはかどらないな...)
----
本日の御託
「7人のメタボ侍、内臓脂肪を斬る」
笑えない、というか,ほとんど切ないニュース。労災になるのだろうか?


//
//  Watch Dog Timet
//  (c) 2007 BakaOyaji
// $Id$
//
//  Behavior implementation

`timescale 1ns/1ns

module 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 ;
    end
endmodule // watchdogtimer(
// EOF watchdogtimer.v

//
//  Clock Generater
//  (c) 2007 BakaOyaji
// $Id$
//
//  Behavior implementation
//  (c) 2007 BakaOyaji
`timescale 1ns/1ns
// 1MHz
`define CYCLE 1000
module 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 // initial
endmodule // clockgen
// EOF clockgen.v



PICを作ろう ,インタラプトハンドラのテスト ~昼休みにまったり進めるプロジェクト

Skip系の命令の実行と割り込みが同時に起きた場合のテストです。まずは、skipが起きない場合。

Int without skip
逆アセンブラのトレースの BTFSC 03,2 はBTFSC STATUS,Z に相当します。Zフラグはセットされていますので、skipは起きません。
次は、skipが起きる場合です。

int with skip
逆アセンブラのトレースの BTFSS 03,2 はBTFSS STATUS,Z に相当します。Zフラグはセットされていますので、skipします。stack_topに積まれているリターンアドレスが上記の例と異なっていることに注意してください。

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



PICを作ろう ,インタラプトハンドラ ~昼休みにまったり進めるプロジェクト

PICを作ろう ,インタラプトハンドラ ~昼休みにまったり進めるプロジェクト
今日は、インタラプトハンドラです。インタラプト時の制御は、2007/07/212007/07/222007/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 // always
endmodule // interrupt handler
// EOF interrupt handler.v

 



PICを作ろう ,ここまでのテスト ~昼休みにまったり進めるプロジェクト

ファイルレジスタとそのコントローラを実装したので、簡単なテストをやってみました。
PICのプログラムを書かないと始まらないので、簡単なコードを書きました(最後に乗っけます)。
 最初に、STATUSフラグをクリアして、Zフラグのみセットされるかチェック。

CLRF_STATUS
ここはうまく行っているようです。引き続き、addwf PCLでいわゆる「計算型GOTO」を使用してテーブル引きで、Wレジスタの値を4倍してます。

PCL_Write_NG
おっと、しくじってますね。ADDWF 02,1、flush信号が立って次のサイクルで強制的にNOPになってなければなりません。
インストラクションレジスタのフラッシュ制御に、PCLの書き込みの条件を忘れてました。修正後はこんな感じ。

PCL_write_OK
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



PICを作ろう ,ファイルレジスタ ~昼休みにまったり進めるプロジェクト

ファイルレジスタだが、思いっきり面倒くさい。とりあえず、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



FC2Ad

まとめ

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。