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