ROMのRTL記述
ROMは、アドレスを入力としてデータを出力するデコーダと同じだからcase文で書ける。
/* シングルポートROM - case文で書く*/ always @(posedge clk) case(adr) 12'd0: dat <= 8'h00; 12'd1: dat <= 8'h11; 12'd2: dat <= 8'h22; ... 12'd4095: dat <= 8'hff; endcase |
◇
別の書き方として、FPGAの場合、コンフィギュレーション時にブロックRAMに初期値がロードされるので、ライトなしのRAMをRTL記述すればROMになる。コンフィギュレーション時の初期値代入はinitial文で書く。
/* シングルポートROM - initial文で値を書く */ reg[7:0] rom[0:4095]; always @(posedge clk) dat <= rom[adr]; initial begin rom[0] = 8'h00; rom[1] = 8'h11; rom[2] = 8'h22; ... rom[4095] = 8'hff; end |
この書き方だと2-port ROMも書ける。(2-port ROMは、処理を並列にするため同じROM値を並列にリードするときに必要になる)
/* デュアルポートROM - initial文で値を書く */ reg[7:0] rom[0:4095]; always @(posedge clk) dat0 <= rom[adr0]; always @(posedge clk) dat1 <= rom[adr1]; initial begin rom[0] = 8'h00; rom[1] = 8'h11; rom[2] = 8'h22; ... rom[4095] = 8'hff; end |
◇◇
ユーザガイドには、$readmemh()でテキストファイルから値を読み込む方法が載っているが、ソースファイルとテキストファイルに分けてしまうと管理しにくくなるのでよくない。
/* シングルポートROM - initial文で値をファイルから読み込む */ reg[7:0] rom[0:4095]; always @(posedge clk) dat <= rom[adr]; initial begin $readmemh("rom.txt",rom); end |
/* rom.txt */ 00 11 22 ... ff |
◇◇◇
もし値が数式で表せるならばfor文で書いてもよい。
/* シングルポートROM - initial文で値を数式で与える */ reg[7:0] rom[0:4095]; always @(posedge clk) dat <= rom[adr]; integer i; initial begin for(i=0; i<4096; i=i+1) rom[i] = (i%255); end |