PICを作ろう ,プログラムカウンタ ~昼休みにまったり進めるプロジェクト~
んじゃ,プログラムカウンタ(PC)行ってみましょう.PC(スタックを含む)に必要な機能は,昨日書いたように,以下の6種類- 分岐 GOTO命令- サブルーチンコール CALL命令- サブルーチンからの復帰 RETURN,RETLW,RETFIE命令- +1 (インクリメント)その他の命令- 割り込みハンドルルーチン(0004h番地)へのコール- ホールド(割り込みサイクル)このうち,割り込みハンドルルーチン(0004h番地)へのコールとホールドの機能は,命令ではなく,インタラプトコントローラからの信号によって機能します.また,SKIP系の命令はインストラクションレジスタのフラッシュ(リセット)によって実装するので,PCには関係する機能はありません.//// Program counter// (c) 2007 BakaOyaji// $Id$////`include "../pic_instructions.h"`include "../pic_def.h"module pc( clk_i, reset_i, por_i , instruction_i, // instruction from instruction reg. data_i , // from FileReg write bus pcl_we_i , // write enable for pcl program_counter_o, // out put of program counter pclath_i, // from PCLATH reg force_call4_i, // force call 0004 hold_i, // hold current address pcl_o // pcl );input clk_i, reset_i, por_i ;input [(`Instruction_Len-1):0] instruction_i ;input [7:0] data_i ; // from FileReg write businput pcl_we_i ; // write enable for pcloutput [(`PC_Length-1):0] program_counter_o ; input [7:0] pclath_i ; // from PCLATH reginput force_call4_i; // force call 0004input hold_i; // hold current addressoutput pcl_o ; // pcl out reg [(`PC_Length-1):0] ProgramCounter ; // program counter reg [(`PC_Length-1):0] stack[(`StackDepth-1):0];reg [(`SP_Length-1):0] StackPointer; assign program_counter_o = ProgramCounter; assign pcl_o = ProgramCounter[7:0] ; always@( posedge clk_i ) begin if( por_i== 1'b1 ) begin ProgramCounter <= 'b0 ; StackPointer <= 'b0 ; end // if else if( reset_i == 1'b1 ) begin ProgramCounter <= 'b0 ; end // else if else if( pcl_we_i == 1'b1 ) begin ProgramCounter <= {pclath_i , data_i } ; end // else if else if(force_call4_i == 1'b1 ) begin ProgramCounter <= 'h0004 ; // Push note that PC is always advance stack[StackPointer] <= ProgramCounter ; StackPointer <= StackPointer + 1 ; end // else if else begin casex ( instruction_i ) `Inst_GOTO : begin ProgramCounter <= {pclath_i[7:3] , instruction_i[10:0] } ; end `Inst_CALL : begin ProgramCounter <= {pclath_i[7:3] , instruction_i[10:0] } ; // Push note that PC is always advance stack[StackPointer] <= ProgramCounter ; StackPointer <= StackPointer + 1 ; end `Inst_RETURN , `Inst_RETFIE, `Inst_RETLW : begin // pop & branch ProgramCounter <= stack[ StackPointer - 1 ] ; StackPointer <= StackPointer - 1 ; end // pop default : begin if( hold_i == 1'b1 ) begin end // if else begin ProgramCounter <= ProgramCounter + 1 ; end // else end // default endcase // Instruction end // else end // alwaysendmodule // pc // EOF pc.vまあ,こんな感じでしょうか? 信号名は入力は最後に_iを,出力は_oをつけています.リセットは,por_i(PowerOnReset)とreset_iの2系統にしてあります.論理合成してインプリメントする場合は同じ扱いでよいと思いますが,PICの仕様ではリセット時に不定になるレジスタがあり,シミュレーションでもそのように動作させるべく分けました.pcl_we_iは,PCLレジスタのWriteEnableです.計算型GOTOに相当する機能ですね.分岐アドレスの計算は,PCLレジスタに書き込みの場合は,8ビット目から上をpclathで補うので, ProgramCounter <= {pclath_i , data_i } ;その他リテラル命令の場合は,11ビット目から上を,pclathの3ビット目から上を補うので, ProgramCounter <= {pclath_i[7:3] , instruction_i[10:0] } ;としています.ホールドの機能は, if( hold_i == 1'b1 ) begin end // ifという記述で実現しています.条件が成立したら「何もしない」という感じです.スタックはスタックポインターを使って実装していますが,書き上げてから気がついたのですが,所詮8レベルしかないので,シフトレジスタで書いたほうがよさそうです.また,alwaysブロックの中のif ~ else if ~ else ifとそれに続くcasexの条件は,相互排他(mutual exclusive)になっているところがあるので,論理合成時にはparallel caseにした方がよいです.この辺は,全体が出来上がってからなおすことにしましょう.次回は、インストラクションレジスタの予定です。---本日の御託庭の芝刈りをしました.先週サボったために結構大変だった.雑草は気にせず雑草ごと刈り込みしてしまう.春先に気になっていた,スギナも毎週芝刈りをしていれば,それほど生えてはこない.一方,「野芝」が最近は目立つ.野芝はイネ科のため,芝用の除草剤でも駆除できないので,気長に手で摘み取るしかない.コガネムシの幼虫発見。そのうち、薬を撒こう。その他、カナヘビの子供2匹目撃.