Posts Issued in October, 2026

posted by sakurai on October 28, 2026 #1140

Fig. 1140.1

On October 27, 2026, FS Micro Laboratory※1, a research laboratory specializing in ISO 26262※2, announced that a paper by its principal researcher, Atsushi Sakurai, has been accepted for the 73rd Annual Reliability and Maintainability Symposium (RAMS 2027)※3, an international conference sponsored by the IEEE※4 Reliability Society.

This marks the eighth consecutive year, since 2020, that Sakurai's papers have been accepted at RAMS. The paper will be presented at RAMS 2027, to be held in Florida, USA, in January 2027.

Sakurai's contributions to ISO 26262 began with a paper accepted at an IEEE international conference in 2017, which received the Best Paper Award, and have continued with a more accurate PMHF※5 formula proposed at RAMS 2020, among other work.

The new paper analyzes the origin of a PMHF formula frequently found in the literature, expressed as a simple sum of failure rates, and identifies its source in the PFH※7 formula of IEC 61508※6. The paper then rigorously derives PMHF and PFH on a common mathematical model, and shows that the resulting expressions contain a term that the simple sum of failure rates does not.

This result means that the simple-sum PMHF formula overestimates safety and can even reverse a compliance decision against a safety integrity target. The paper further shows that the PFH formula of IEC 61508 is exact in its simple-sum form only under an idealized condition: perfect and continuous proof testing. This condition is rarely met in practice, in the automotive domain or elsewhere.

These results support a clearer understanding and proper application of both metrics, especially PMHF, in automotive safety analysis.

Fig. 1140.3

【Notes】
※1:FS Micro Laboratory (Nagoya, Japan; Principal Researcher: Atsushi Sakurai): A research laboratory specializing in the functional safety of automotive systems. https://fs-micro.com/
※2:ISO 26262: An international standard for the functional safety of automotive electrical and electronic systems, aimed at reducing the risk of hazardous events during driving to an acceptable level.
※3:RAMS (the Reliability and Maintainability Symposium): An international conference on reliability engineering sponsored by the IEEE Reliability Society and others. The 73rd symposium will be held in Florida, USA, in 2027. https://rams.org/
※4:IEEE (Institute of Electrical and Electronics Engineers): One of the world's largest technical professional organizations dedicated to advancing electrical and electronic technology. https://ieee.org/
※5:PMHF (Probabilistic Metric for Random Hardware Failures): A metric representing the time-averaged probability of dangerous failures caused by random hardware failures, used as a hardware design target in ISO 26262.
※6:IEC 61508: The generic functional safety standard for electrical and electronic systems, on which sector-specific functional safety standards, including ISO 26262, are based.
※7:PFH (average frequency of a dangerous failure per hour): A quantitative metric used in IEC 61508 for safety functions operating in high-demand or continuous mode.


【Contact】
Company            FS Micro Laboratory
Representative   Atsushi Sakurai
Established        August 21, 2013
Business            Research on functional safety of automotive electronics under ISO 26262
Email                  info@fs-micro.com
URL                    https://fs-micro.com/


左矢前のブログ 次のブログ右矢

posted by sakurai on October 27, 2026 #1139

図1139.1

2026年10月27日、ISO 26262※1の研究を行うFSマイクロ研究所※2は、代表研究員 桜井 厚の論文が、IEEE※3信頼性部会が主催する国際会議 第73回RAMS 2027※4に採択されたことを発表しました。

桜井の論文がRAMSに採択されるのは、2020年から8年連続となります。この論文は2027年1月に米国フロリダ州で開催されるRAMS 2027において発表される予定です。

桜井は2017年のIEEE国際会議での論文採択ならびに最優秀論文賞受賞に始まり、RAMS 2020でのより正確なPMHF※5式の提案など、ISO 26262に関する貢献を積み重ねてきました。

今回の論文は、文献にしばしば見られる、単純な故障率の和で表されるPMHF式の由来を分析し、それがIEC 61508※6のPFH※7式から来ることを特定しました。そのうえで、PMHFとPFHを共通の数学モデルの上で厳密に導出し、それらの式には単純な故障率の和には含まれない項が存在することを示しました。

この結果は、単純な和のPMHF式では安全性が過大評価され、安全目標への適合判定が覆りうることを意味します。さらに本論文は、IEC 61508のPFH式が単純な和の形で厳密に成立するのは、完全かつ連続的なプルーフテストという理想化された条件の下に限られることを明らかにしました。この条件は自動車分野に限らず現実にはほぼ成立しません。

本研究の成果は、自動車の安全解析における両指標、とりわけPMHFの正しい理解と適切な適用に資するものです。

図1139.3

【注釈】
※1:ISO 26262:車載電気電子システムの機能安全に関する国際規格。運転中に生じ得る危険事象のリスクを許容水準まで低減することを目的とする。
※2:FSマイクロ研究所(本社:名古屋市。代表研究員:桜井 厚):車載システムの機能安全に関する研究所。https://fs-micro.com/
※3:IEEE(Institute of Electrical and Electronics Engineers、電気電子技術者協会):電気電子技術の進歩を推進する世界最大級の専門技術者組織。 https://ieee.org/
※4:RAMS(the Reliability and Maintainability Symposium):IEEE信頼性部会などが主催する信頼性工学の国際会議。第73回は2027年に米国フロリダ州で開催予定。https://rams.org/
※5:PMHF(Probabilistic Metric for Random Hardware Failures):ランダムハードウェア故障に起因する危険側故障の時間平均確率を表す指標。ISO 26262でハードウェア設計目標として用いられる。
※6:IEC 61508:汎用の電気電子システムの機能安全規格。ISO 26262をはじめ各分野の機能安全規格の基礎となっている。
※7:PFH(average frequency of a dangerous failure per hour):単位時間当たりの危険側故障の平均頻度であり、IEC 61508で高頻度または連続運用モードの安全機能に用いられる量的指標。


【お問い合わせ先】
会社名     FSマイクロ研究所
代表者     桜井 厚
設立年月日   2013年8月21日
事業内容    ISO 26262車載電子機器の機能安全の研究
メールアドレス info@fs-micro.com
URL      https://fs-micro.com/


左矢前のブログ 次のブログ右矢

俺の勉強会#8 LT予告

posted by sakurai on October 19, 2026 #1138

俺の勉強会#8においてLTを行います。テーマは「BSVによるインベーダゲームのフルハードウエアによる再設計」というもので、ライブデモを行います。

図1138.1
図1138.1 俺の勉強会#8

図1138.2
図1138.2 BSVによるインベーダゲームのフルハードウエアでの再設計

以下に目次を示します。

  • 自己紹介と用語
  • Bluespec SystemVerilog (BSV)
  • BSVのサンプルプログラム
  • 私的インベーダ設計の歴史
  • 私的インベーダ設計の歴史 (2)
  • 機材
  • まとめ
  • ライブデモ実行

左矢前のブログ 次のブログ右矢

posted by sakurai on October 16, 2026 #1137

Studio 500 3D Pop Up Wall Artの修理の続きです。

図1137.1
図1137.1 Studio 500

Claudeの能力が上がってきており、自分でEagleも操作できるので、思い切って論理図とレイアウトを設計して貰いました。前回は

なおAIの部品配置は配線が省略され適当なので、部品間の配線は人手で接続しています。

このように一部人手でしたが、部品間の配線もやってもらいました。つまり全てがClaudeの設計です。

図1137.2
図1137.2 点滅回路図

次にレイアウト図を示します。前回は配置はAIを使わずに人手で設計しましたが、今度はClaudeにEagleを操作して貰います。つまりレイアウトも全てがClaudeの設計です。

やってもらった印象ではあまり速くありませんでした。AIだと目にもとまらぬ速さで操作しそうですが、意外にEagleを実行してその画面を取得して分析してるようで、かなり遅いです。

さらに、前回は

出来上がりをClaudeにみせたところ、背面GNDと前面GNDの間のVIAが少なく、前面GNDパッド位置でVIAを打ち、背面の大きなGNDプレーンにコンタクトすべきとのことで、VIAを追加しました。

ところが今回は貫通VIAが無かったので、その旨を伝えて修正して貰いました。また、PCBサイズは26 × 27 mmとなりました。全般的に配線長が短くなって良い配置のように見えます。

図1137.3
図1137.3 点滅回路レイアウト図

このようにAIがEDAツールまで使いこなすようになったため、設計手法は大きく変わるように思います。


左矢前のブログ 次のブログ右矢

メモリをBSVで書く (5)

posted by sakurai on October 5, 2026 #1136

4点目 運用

bsc付属のライブラリVerilogが3つ増えました。mkFIFOF1のFIFO1.v、mkBRAMCore1LoadのBRAM1Load.v、mkSyncBRAMCore2LoadのBRAM2Load.vで、bscはこれらを生成せず、インストール先のlib/Verilogにあるものをインスタンスします。教科書版のMakefileはこれをsrcに写して、生成Verilogと同じ扱いにします。

# bsc 付属の Verilog ライブラリ。mkBlitter が使う FIFO1 と BRAM1Load、
# mkVram が使う BRAM2Load はここから src に写す
BSC_VLIB     ?= $(abspath $(dir $(shell which $(BSC)))../lib/Verilog)
BSC_LIB_V    := FIFO1.v BRAM1Load.v BRAM2Load.v
$(addprefix $(RTL_DIR)/,$(BSC_LIB_V)): $(RTL_DIR)/%.v: $(BSC_VLIB)/%.v
	@mkdir -p $(RTL_DIR)
	cp $< $@

1つのソースから2つのモジュールを出す規則は、グループターゲットで3つの生成物を1回のレシピに結びます。Blitter.bsvからはmkBlitter.vとmkProm.vとBlitter.bo、SoundFSM.bsvからは変種ごとにmkSoundFSMn.vとmkSoundROMn.vです。

$(RTL_DIR)/mkBlitter.v $(RTL_DIR)/mkProm.v $(VOBJ_DIR)/Blitter.bo &: $(SRC_DIR)/Blitter.bsv
	@mkdir -p $(RTL_DIR) $(VOBJ_DIR)
	$(TIME) $(BSC) $(BSC_RT_OPTS) $(VLOG_FLAGS) $(PFLAGS) $(STEPFLAGS) \
	    -bdir $(VOBJ_DIR) -vdir $(RTL_DIR) -g mkBlitter -g mkProm $(SRC_DIR)/Blitter.bsv
$(RTL_DIR)/mkSoundFSM0.v $(RTL_DIR)/mkSoundROM0.v &: $(SRC_DIR)/SoundFSM.bsv $(SRC_DIR)/SoundCodes.vh
	$(call BSC_GEN_D,mkSoundFSM0 mkSoundROM0,$(SRC_DIR)/SoundFSM.bsv,FSM0)

make checkはライブラリ3つの所在も確認します。ライブラリが別の場所にあるときはmake BSC_VLIB=場所で指定します。Vivadoには、srcの他の.vと同様にこの3つと、新しく増えたmkProm.v、mkVram.v、mkSoundROM0.vから3を登録します。memの.memはライブラリのVerilogの中から同じ名前で読まれるので、登録は今までのままです。

手書きVerilogからはvram.v、rom.v、sndch.vが消え、master.vからROMのインスタンスが消えました。残るのはtop.v、clock.v、master.v、sound.vの4つで、clock.vのMMCMと分周以外は配線です。

Yosysで試すときは1つ注意があります。read_verilogに-deferを付けないと、BRAM1Load.vがパラメータの既定値である空のファイル名で$readmemhを評価して止まります。-deferを付けると、パラメータが確定してから本体を解釈します。

まとめ

比べる前は、ブリッタの起動をFIFOにした版で、ROMとVRAMは手書きVerilogです。後はこの記事の3点を入れた版です。LUTとFFはYosysのsynth_xilinxでフラットに合成した概算で、mkGameFSMの行はmkBlitterとmkPromを含みます。動作はVerilatorでmkGameFSMを1,200万サイクル回し、VRAM書き込みとサウンドコードの系列と時刻を比べました。

メモリのBSV化前後 前 後 備考
ソース Blitter.bsvとGameFSM.bsv[行] 1,870 1,883 mkPromを足し、ポート2つとレジスタ1つが消えた
Vram.bsv[行] 0 41 vram.vの34行が置き換わった
SoundFSM.bsv[行] 261 306 rom.vの26行とsndch.vの65行が置き換わった
生成Verilog[行] 32,863 32,911 mkBlitter.v、mkProm.v、mkGameFSM.vの合計
mkBlitter LUT 183 198 ROMを3個のBRAMに分ける選択論理
FF 160 149 p_addrの15ビットが消えた
RAMB36 0 3 mkProm 25728 x 4
mkGameFSM LUT 5,695 5,790 後はROMを含む
FF 2,168 2,157
mkVram RAMB36 8 8 前はvram.v
mkSoundFSMn ポート 2本 0本 rom_addressとrom_dataが消えた
動作 mkGameFSMの系列と時刻 一致 1,200万サイクル
サウンド4チャネルの出力 一致 300万サイクル、852コマンド

mkGameFSMのLUTが95増えていますが、前の値にはmaster.vにあったROMが入っていません。ROMの3個のBRAMを選ぶアドレスの比較と出力の選択がmkGameFSMの側に移った分で、設計全体では増えていません。FFの減りはp_addrの15ビットそのもので、読み出しデータのレジスタはBRAMの出力レジスタに置き換わりました。

メモリをBSVに移して得たものは、ブリッタのインタフェースからROMが消えたことです。ROMを読むのはブリッタだけなのに、アドレスとデータの2ポートがブリッタ、mkGameFSM、master.vの3階層を貫いていました。使う側の中に置けば、その経路は丸ごと要らなくなります。一方でFSMとROMは機能が別なので、ブリッタの中でもmkProm、サウンドFSMの中でもmkSoundROMnという別のモジュールにし、FSMはそれをメソッドで呼びます。パターンROMとサウンドROMが同じ形になりました。VRAMは2つのクロック域にまたがるのでトップに残りますが、クロックを引数で受けるBSVのモジュールになり、手書きVerilogは配線とクロック生成だけになりました。


左矢前のブログ 次のブログ右矢

メモリをBSVで書く (4)

posted by sakurai on October 4, 2026 #1135

3点目 サウンドROMをmkSoundROMにする

図1135.1
図1135.1 Sound ROM書き換え前後

サウンドは4チャネルあり、チャネルごとに手書きのsndch.vがFSMのmkSoundFSMnとROMのrom.vを並べ、rom_addressとrom_dataの2本で結んでいました。パターンROMと同じ形にして、ROMをmkSoundROMnという別モジュールにし、FSMがその中に置いてメソッドで呼ぶようにしました。FSMはWAVを読んでPCMを出す機能、ROMは内容を持つ機能で、機能が別なので別モジュールのままです。

書き換え前のsndch.vはCHに加えてDEPTHとFILEをパラメータに取り、sound.vがチャネルごとに語数とファイル名を渡していました。

module sndch #(
   parameter CH    = 0,
   parameter DEPTH = 21650,
   parameter FILE  = "ch00.mem"
) (
   rom #(.WIDTH(8), .AWIDTH(15), .DEPTH(DEPTH), .FILE(FILE)) u_rom (
      .clk  (clk),
      .addr (rom_addr),
      .q    (rom_q)
   );
   sndch #(.CH(0), .DEPTH(21650), .FILE("ch00.mem")) u_ch0 (

FSMの側は、アドレスをレジスタaddrに置いてrom_addressポートから出し、rom_dataポートから毎周期romdataレジスタに取り込んでいました。

書き換え前

interface FSM_ifc;
   method Action sound(SoundCode_t incode);
   method Action rom_data(Data_t indata);
   method Action sync(Bool lrclk);
   method Action empty(Bool flag);
   method Addr_t rom_address();
   method Data_t sdout();
   method Bool soundon();
   method Bool fifo_ren();
endinterface
   Reg#(Data_t) romdata <- mkRegU,      // ROM 読み出しデータ(毎サイクル入力)
                   dout <- mkReg(`NULL); // PCM 出力(無音=`NULL)
   Reg#(UInt#(32)) workd <- mkRegU;
   Reg#(UInt#(15)) dcount <- mkRegU;    // 残りサンプル数(WAV data チャンクサイズ)
   Reg#(Addr_t) worka <- mkRegU,        // readMem への引数(読みたい番地)
                   romaddr <- mkRegU,   // WAV 読み出しポインタ
                   addr <- mkReg(0);      // rom_address ポートへの出力値
   function Stmt readMem;
      return (seq
         addr <= worka;
         noAction;
         noAction;
      endseq);
   endfunction
            if (ii == 3) dcount <= truncate(workd<<8) | extend(romdata);
            else workd <= workd<<8 | extend(romdata);
   method Action rom_data(Data_t indata);
      romdata <= indata;
   endmethod
   method Addr_t rom_address();
      return addr;
   endmethod

書き換え後は、SoundFSM.bsvの末尾にROMのモジュールを足しました。FSMと同じ-D FSM0から3で作り分け、語数とファイル名は変種ごとにここで決まります。

// =================================================================
// SoundROM: 効果音 ROM(1ソース4変種)
//   FSM と同じ -D FSM0〜FSM3 で mkSoundROM0〜3 を作り分け、語数と
//   ファイル名を変種毎に持つ。実体は BRAMCore ライブラリの
//   mkBRAMCore1Load で、生成 Verilog では bsc 付属の BRAM1Load.v が
//   $readmemh でファイルを読む。req したアドレスの内容が次の周期から
//   data に出て次の req まで保持される同期 ROM。
//   FSM とは機能が別なので、同じソースに置くが別モジュールにしてある。
// =================================================================
`ifdef FSM0
`define ROM_DEPTH 21650
`define ROM_FILE  "ch00.mem"
`elsif FSM1
`define ROM_DEPTH 4622
`define ROM_FILE  "ch01.mem"
`elsif FSM2
`define ROM_DEPTH 6586
`define ROM_FILE  "ch02.mem"
`elsif FSM3
`define ROM_DEPTH 27814
`define ROM_FILE  "ch03.mem"
`endif

interface ROM_ifc;
   (* always_ready *) method Action req(Addr_t addr);
   (* always_ready *) method Data_t data();
endinterface

(* synthesize *)
`ifdef FSM0
module mkSoundROM0(ROM_ifc);
`elsif FSM1
module mkSoundROM1(ROM_ifc);
`elsif FSM2
module mkSoundROM2(ROM_ifc);
`elsif FSM3
module mkSoundROM3(ROM_ifc);
`endif
   BRAM_PORT#(Addr_t, Data_t) rom <- mkBRAMCore1Load(`ROM_DEPTH, False, `ROM_FILE, False);
   method Action req(Addr_t addr) = rom.put(False, addr, ?);
   method Data_t data = rom.read;
endmodule

FSMはそれを中に置き、readMemでreqを呼び、データはrom.dataで読みます。インタフェースからrom_dataとrom_addressが消え、addrとromdataの2つのレジスタも消えました。

interface FSM_ifc;
   method Action sound(SoundCode_t incode);
   method Action sync(Bool lrclk);
   method Action empty(Bool flag);
   method Data_t sdout();
   method Bool soundon();
   method Bool fifo_ren();
endinterface
   // 効果音 ROM。機能が別なので末尾の別モジュール mkSoundROMn にしてあり、
   // 本FSMはそれを置いて readMem で req と data を呼ぶ。
`ifdef FSM0
   ROM_ifc rom <- mkSoundROM0;
`elsif FSM1
   ROM_ifc rom <- mkSoundROM1;
`elsif FSM2
   ROM_ifc rom <- mkSoundROM2;
`elsif FSM3
   ROM_ifc rom <- mkSoundROM3;
`endif
   function Stmt readMem;
      return (seq
         rom.req(worka);
         noAction;
         noAction;
      endseq);
   endfunction
            if (ii == 3) dcount <= truncate(workd<<8) | extend(rom.data);
            else workd <= workd<<8 | extend(rom.data);
               action
                  son <= True;
                  dout <= rom.data;
               endaction

reqの中身は次の周期からdataに出て、次のreqまで保持されます。前の形ではaddrレジスタ、rom.vの出力レジスタ、romdataレジスタの3段を経てデータが届いていたので、readMemの2つのnoActionはそのための待ちでした。ROMの読み出しが1段になった後も、noActionはそのまま残してサイクル数を変えていません。ROMのreqはFSMの状態からだけ呼ばれるので、always_enabledは付けず、呼ばれた周期だけBRAMのENが立ちます。

sound.vはmkSoundFSM0から3を直接4つ置く形になり、sndch.vとrom.vは消えました。

   mkSoundFSM0 u_ch0 (
      .CLK(snd_fsmclk), .RST_N(snd_xrst), .sync_lrclk(LRCLK), .sound_incode(scode),
      .empty_flag(fifo_empty), .fifo_ren(ren0), .sdout(ch_out0), .soundon(ch_on0)
   );

動作は、旧sndch.vと新mkSoundFSMnを4チャネルとも同じ乱数のROM内容、同じコマンド列、同じlrclkで並走させて確かめました。SND_FSMCLKで300万サイクル、コマンド852件、再生中の周期がチャネル合計で488万あり、fifo_ren、soundon、sdoutの3出力が全周期一致しました。


左矢前のブログ 次のブログ右矢

メモリをBSVで書く (3)

posted by sakurai on October 3, 2026 #1134

2点目 VRAMをmkVramにする

図1134.1
図1134.1 VRAM書き換え前後

VRAMは2ポート2クロックのTrue Dual Portです。ポートAはゲームFSMの2MHzで読み書き、ポートBはグラフィクスFSMの49.5MHzで読み出しだけです。手書きのvram.vはこうでした。

書き換え前

module vram #(
   parameter DEPTH = 65536,
   parameter FILE  = "vram.mem"
) (
   input  wire        clka,
   input  wire        wea,
   input  wire [15:0] addra,
   input  wire [3:0]  dina,
   output reg  [3:0]  douta,

   input  wire        clkb,
   input  wire [15:0] addrb,
   output reg  [3:0]  doutb
);

   reg [3:0] mem [0:DEPTH-1];
   initial $readmemh(FILE, mem);

   always @(posedge clka) begin
      if (wea) mem[addra] <= dina;
      douta <= mem[addra];
   end

   always @(posedge clkb) doutb <= mem[addrb];

endmodule

書き換え後のVram.bsvは次のとおりで、これが全文です。

package Vram;

// ================= VRAM =================
// 256x256、4bit/画素の画面メモリ。True Dual Port で、ポート A はゲーム FSM の
// クロックで読み書き、ポート B はグラフィクス FSM のピクセルクロックで読み出し。
// BRAMCore ライブラリの mkSyncBRAMCore2Load がそのまま実体で、初期値は
// vram.mem を $readmemh で読む。両ポートとも毎周期アクセスする always_enabled で、
// 生成 Verilog の BRAM2Load は EN が常に 1 になる。

import BRAMCore::*;

typedef Bit#(16) VAddr_t;
typedef Bit#(4)  Pattern_t;

interface Vram_ifc;
   // ポート A: ゲーム FSM 側。既定クロック
   (* always_ready, always_enabled *)
   method Action    a_req(Bool we, VAddr_t addr, Pattern_t d);
   (* always_ready *)
   method Pattern_t a_data;
   // ポート B: グラフィクス側。pixClk
   (* always_ready, always_enabled *)
   method Action    b_req(VAddr_t addr);
   (* always_ready *)
   method Pattern_t b_data;
endinterface

(* synthesize *)
module mkVram#(Clock pixClk, Reset pixRst)(Vram_ifc);
   Clock clkA <- exposeCurrentClock;
   Reset rstA <- exposeCurrentReset;
   BRAM_DUAL_PORT#(VAddr_t, Pattern_t) ram <-
      mkSyncBRAMCore2Load(65536, False, clkA, rstA, pixClk, pixRst, "vram.mem", False);

   method Action    a_req(Bool we, VAddr_t addr, Pattern_t d) = ram.a.put(we, addr, d);
   method Pattern_t a_data = ram.a.read;
   method Action    b_req(VAddr_t addr) = ram.b.put(False, addr, ?);
   method Pattern_t b_data = ram.b.read;
endmodule

endpackage

2つ目のクロックはモジュールの引数で受けます。mkVram#(Clock pixClk, Reset pixRst)と書くと、生成VerilogにCLK_pixClkとRST_N_pixRstの入力が増えます。自分のクロックはexposeCurrentClockで取り出し、mkSyncBRAMCore2Loadの2組のクロックとリセットに渡します。ポートBのメソッドb_reqとb_dataは、BRAMのポートBがpixClkで動いていることからbscがクロック域を推論するので、clocked_byを書く必要がありません。両ポートにalways_enabledを付けたのは、vram.vと同じく毎周期読む形にするためで、生成VerilogのBRAM2LoadはENAとENBが定数1になります。

トップの接続は、vram.vのパラメータ付きインスタンスがbsc生成モジュールの接続に変わるだけです。

書き換え前

   vram #(.DEPTH(65536), .FILE("vram.mem")) u_vram (
      .clka  (clk_2m),
      .wea   (vwe_a),
      .addra (vaddr_a),
      .dina  (vdout_a),
      .douta (vdin_a),
      .clkb  (C49_5MHz),
      .addrb (vaddr_b),
      .doutb (vram_qb)
   );

書き換え後

   mkVram u_vram (
      .CLK          (clk_2m),
      .RST_N        (locked),
      .CLK_pixClk   (C49_5MHz),
      .RST_N_pixRst (locked),
      .a_req_we     (vwe_a),
      .a_req_addr   (vaddr_a),
      .a_req_d      (vdout_a),
      .a_data       (vdin_a),
      .b_req_addr   (vaddr_b),
      .b_data       (vram_qb)
   );

1つだけ振る舞いの違いがあります。vram.vはポートAで書き込みと同じ周期に読んだ値が書き込み前の内容になる読み出し優先で、bscのBRAM2Load.vは書き込んだ値が出る書き込み優先です。ブリッタは読む状態と書く状態を分けていて、書く周期の読み出し値を使う箇所がありません。それを確かめるために、vram.vとmkVramを同じ乱数の読み書きで並走させました。ポートAは2MHz、ポートBは49.5MHzで、ポートAは書き込みの無い周期の読み出し値を20万周期分比べて不一致0、書き込みの周期だけが46,666回違いました。ポートBは、ポートAが同じ番地に書いている瞬間を除いた4,799,764回の読み出しが全て一致しました。同じ番地への同時アクセスはどちらのモデルでも未定義で、設計上も起きません。

Yosysでは、mkVramがRAMB36E1を8個使い、LUTとFFは0です。vram.vのVivadoでの実装も8個でしたから、物量は同じです。


左矢前のブログ 次のブログ右矢

メモリをBSVで書く (2)

posted by sakurai on October 2, 2026 #1133

書き換え後は、Blitter.bsvにmkPromというROMのモジュールを立て、ブリッタはそれを置いてreqとdataを呼ぶだけにします。mkPromの実体はBRAMCoreのmkBRAMCore1Loadで、引数は語数、出力レジスタの有無、ファイル名、ファイルが2進かどうかです。

import StmtFSM::*;
import FIFOF::*;
import BRAMCore::*;
// MemPort: 画面メモリ側の面。PROM は内蔵なので VRAM のポート A だけが出る
interface MemPort;
   (* always_ready *) method VAddr_t   vaddr;
   (* always_ready *) method Bool      vwe;
   (* always_ready *) method Pattern_t vdout;
   (* always_enabled *) method Action vdin(Pattern_t d);
endinterface
// ================= パターン ROM =================
// 25728 x 4 の同期 ROM。prom.mem を $readmemh で読む。req したアドレスの内容が
// 次の周期から data に出る。実体は BRAMCore ライブラリの mkBRAMCore1Load で、
// 生成 Verilog では bsc 付属の BRAM1Load.v がインスタンスされる。
// FSM とは機能が別なので、ブリッタの中に置く別モジュールにしてある。
// 語数は PROM_DEPTH で作り分けられる(テストベンチ用)。
`ifdef PROM_DEPTH
   Integer promDepth = `PROM_DEPTH;
`else
   Integer promDepth = 25728;
`endif

interface Prom_ifc;
   (* always_ready *) method Action    req(PAddr_t addr);
   (* always_ready *) method Pattern_t data;
endinterface

(* synthesize *)
module mkProm(Prom_ifc);
   BRAM_PORT#(PAddr_t, Pattern_t) rom <- mkBRAMCore1Load(promDepth, False, "prom.mem", False);
   method Action    req(PAddr_t addr) = rom.put(False, addr, ?);
   method Pattern_t data = rom.read;
endmodule
   Reg#(VAddr_t) v_addr <- mkRegU;
   Reg#(Bool) fvwe <- mkReg(False);
   Reg#(Bool) fobj  <- mkReg(False),
              fbase <- mkReg(False);
   Reg#(Pattern_t) vd <- mkRegU;
   Wire#(Pattern_t) vdata <- mkWire;

   // パターン ROM。機能は mkProm という別のモジュールで、ブリッタはそれを置いて
   // req と data を呼ぶだけ。階層図では mkBlitter の中に mkProm の箱として見える。
   Prom_ifc prom <- mkProm;
               action
                  prom.req({pack(ys)[7:0], pack(xs)[6:0]});
                  UInt#(8) y_addr = truncate(yd);
                  UInt#(8) x_addr = truncate(xd);
                  v_addr <= {pack(y_addr), pack(x_addr)};
               endaction
               noAction; // リード待ち(1サイクル)
               action
                  case (b.op)
                     BLIT_COPY:  vd <= prom.data;
                     BLIT_OR:    vd <= vdata | prom.data;
                     BLIT_ANDN:  vd <= vdata & ~prom.data;
                     BLIT_ERASE: vd <= 0;
                  endcase
                  xs <= xs + 1;
                  xd <= xd + 1;
               endaction
   interface MemPort mem;
      method VAddr_t   vaddr     = v_addr;
      method Bool      vwe       = fvwe;
      method Pattern_t vdout     = vd;
      method Action vdin(Pattern_t d); vdata   <= d; endmethod
   endinterface

アドレスを置くactionはレジスタへの代入からprom.reqに、ラッチのactionはワイヤからprom.dataに変わりました。reqしたアドレスの内容は次の周期からdataに出るので、間のnoActionを含めて1画素あたりのサイクル数は変わりません。消えたのはp_addrレジスタ、romdataワイヤ、MemPortの2ポート、mkGameFSMの同名の2ポート、master.vのROMインスタンスと2本の配線です。mkPromは(* synthesize *)付きなので生成物にmkProm.vが1つ増え、Vivadoの階層図ではmkBlitterの中にmkPromの箱が出ます。ブリッタのFSMとROMが別のモジュールであることが、字面でも階層図でも見えます。

生成されたmkProm.vの中では、bsc付属のBRAM1Load.vがFILENAMEにprom.mem、MEMSIZEに25728を与えてインスタンスされます。BRAM1Load.vの中が$readmemhなので、memの運用は今までと同じです。語数はpromDepthにあり、テストベンチのように別の語数で作りたいときは-D PROM_DEPTH=32768のように与えます。


左矢前のブログ 次のブログ右矢

メモリをBSVで書く

posted by sakurai on October 1, 2026 #1132

教科書版の手書きVerilogは、トップの配線、メモリ、クロック生成の3つでした。このうちメモリは、BSVの標準ライブラリBRAMCoreがそのまま当てはまる部分で、手書きのVerilogを残す理由がありません。パターンROM、VRAM、サウンドROMの3つをBSVのモジュールにしました。どれも初期値は今までどおりmemの$readmemhで読み、Vivadoの運用は変わりません。合成はYosysのsynth_xilinx、動作確認はVerilatorとiverilogで、前回までと同じ条件です。

置き場所を決める物差しは、機能が別なら別モジュール、というものです。FSMはROMを読む機能、ROMは内容を持つ機能で、2つは別のモジュールにします。そのうえで、ROMを読むのがそのFSMだけなら、ROMのモジュールはそのFSMの中に置き、FSMがメソッドで呼びます。パターンROMはブリッタの中に、サウンドROMはサウンドFSMの中に置きました。VRAMは2つのクロック域から共有されるので、独立のモジュールとしてトップに置いたままです。

1点目 パターンROMをブリッタの中に置く

図1132.1
図1132.1 パターンROM書き換え前後

パターンROMを読むのはブリッタだけです。それなのにROMはmaster.vにあり、ブリッタはアドレスをレジスタp_addrに置いて外に出し、読み出しデータをワイヤromdataで受けていました。ブリッタのMemPortにはprom_addrとpdinの2ポートがあり、mkGameFSMにも同じ名前のポートが素通しで並んでいました。

書き換え前

// MemPort: 画面メモリ側の面
interface MemPort;
   (* always_ready *) method PAddr_t   prom_addr;
   (* always_ready *) method VAddr_t   vaddr;
   (* always_ready *) method Bool      vwe;
   (* always_ready *) method Pattern_t vdout;
   (* always_enabled *) method Action pdin(Pattern_t d);
   (* always_enabled *) method Action vdin(Pattern_t d);
endinterface
   Reg#(PAddr_t) p_addr <- mkRegU;
   Reg#(VAddr_t) v_addr <- mkRegU;
   Reg#(Bool) fvwe <- mkReg(False);
   Reg#(Bool) fobj  <- mkReg(False),
              fbase <- mkReg(False);
   Reg#(Pattern_t) vd <- mkRegU;
   Wire#(Pattern_t) vdata <- mkWire,
                    romdata <- mkWire;
               action
                  p_addr <= {pack(ys)[7:0], pack(xs)[6:0]};
                  UInt#(8) y_addr = truncate(yd);
                  UInt#(8) x_addr = truncate(xd);
                  v_addr <= {pack(y_addr), pack(x_addr)};
               endaction
               noAction; // リード待ち(1サイクル)
               action
                  case (b.op)
                     BLIT_COPY:  vd <= romdata;
                     BLIT_OR:    vd <= vdata | romdata;
                     BLIT_ANDN:  vd <= vdata & ~romdata;
                     BLIT_ERASE: vd <= 0;
                  endcase
                  xs <= xs + 1;
                  xd <= xd + 1;
               endaction
   interface MemPort mem;
      method PAddr_t   prom_addr = p_addr;
      method VAddr_t   vaddr     = v_addr;
      method Bool      vwe       = fvwe;
      method Pattern_t vdout     = vd;
      method Action pdin(Pattern_t d); romdata <= d; endmethod
      method Action vdin(Pattern_t d); vdata   <= d; endmethod
   endinterface

master.vにはROMのインスタンスと、そこへ渡す2本の配線がありました。

   wire [14:0] prom_addr;
   wire [3:0]  prom_dout;

   mkGameFSM u_game (
      .CLK          (clk),
      .RST_N        (rst_n),
      .COUNT        (COUNT),
      .START_BUTTON (start_db),
      .LEFT_BUTTON  (left_db),
      .RIGHT_BUTTON (right_db),
      .FIRE_BUTTON  (fire_db),
      .tick         (tick),
      .empty        (fifo_empty),
      .fifo_wen     (fifo_wen),
      .SCODE        (scode),
      .prom_addr    (prom_addr),
      .pdin         (prom_dout),
      .vaddr        (vaddr),
      .vdout        (vdout),
      .vwe          (vwe),
      .vdin         (vdin),
      .Gun_Exp      (gun_exp)
   );

   rom #(.WIDTH(4), .AWIDTH(15), .DEPTH(25728), .FILE("prom.mem")) u_prom (
      .clk  (clk),
      .addr (prom_addr),
      .q    (prom_dout)
   );

左矢前のブログ 次のブログ右矢