2対4デコーダの論理構成
2ビットの選択信号に基づき、4本の出力線の中から1本のみをアクティブレベルに切り替える組合せ回路です。制御信号が非アクティブの場合は全出力がリセットされます。
module dec_2to4 (
input wire enable_ctrl,
input wire [1:0] addr_sel,
output reg [3:0] led_drv
);
always @(*) begin
if (enable_ctrl) begin
case (addr_sel)
2'b00: led_drv = 4'b0001;
2'b01: led_drv = 4'b0010;
2'b10: led_drv = 4'b0100;
2'b11: led_drv = 4'b1000;
default: led_drv = 4'b0000;
endcase
end else begin
led_drv = 4'b0000;
end
end
endmodule
4対2エンコーダの実装
4本の入力信号のうち、ハイ状態にあるビットのインデックスを2ビットのバイナリ値に変換します。複数の入力が同時にハイとなる場合は、定義された優先順位または排他制御が想定されます。
module enc_4to2 (
input wire enable_ctrl,
input wire [3:0] btn_req,
output reg [1:0] bin_code
);
always @(*) begin
if (enable_ctrl) begin
if (btn_req == 4'b0001) bin_code = 2'b00;
else if (btn_req == 4'b0010) bin_code = 2'b01;
else if (btn_req == 4'b0100) bin_code = 2'b10;
else if (btn_req == 4'b1000) bin_code = 2'b11;
else bin_code = 2'b00;
end else begin
bin_code = 2'b00;
end
end
endmodule
優先度エンコーダ(4入力および8入力)
複数の入力が同時にアサートされた場合、最上位ビット(MSB側)の信号を優先して符号化します。有効な入力の存在を検知するためのバリデーション信号も併設します。
4入力優先エンコーダ
module prio_enc_4to2 (
input wire enable_ctrl,
input wire [3:0] data_in,
output reg [1:0] out_val
);
integer k;
always @(*) begin
out_val = 2'b00;
if (enable_ctrl) begin
for (k = 0; k <= 3; k = k + 1) begin
if (data_in[k]) begin
out_val = k[1:0];
end
end
end
end
endmodule
8入力優先エンコーダと7セグメント表示連動
8ビット入力を受け付け、3ビットコードに変換すると同時に、結果を7セグメントLEDドライバに渡して可視化します。
module prio_enc_8to3 (
input wire enable_ctrl,
input wire [7:0] data_bus,
output reg [2:0] code_out,
output wire valid_flag
);
assign valid_flag = enable_ctrl && (|data_bus);
always @(*) begin
if (enable_ctrl) begin
casez (data_bus)
8'b1???????: code_out = 3'b111;
8'b01??????: code_out = 3'b110;
8'b001?????: code_out = 3'b101;
8'b0001????: code_out = 3'b100;
8'b00001???: code_out = 3'b011;
8'b000001??: code_out = 3'b010;
8'b0000001?: code_out = 3'b001;
8'b00000001: code_out = 3'b000;
default: code_out = 3'b000;
endcase
end else begin
code_out = 3'b000;
end
end
endmodule
module seg_driver (
input wire [2:0] hex_in,
output wire [7:0] seg_lines
);
reg [7:0] pattern;
always @(*) begin
case (hex_in)
3'b000: pattern = 8'b11111101;
3'b001: pattern = 8'b01100000;
3'b010: pattern = 8'b11011010;
3'b011: pattern = 8'b11110010;
3'b100: pattern = 8'b01100110;
3'b101: pattern = 8'b10110110;
3'b110: pattern = 8'b10111110;
3'b111: pattern = 8'b11100000;
default: pattern = 8'b11111111;
endcase
end
assign seg_lines = ~pattern; // 共カソード/アノード反転対応
endmodule
module top_system (
input wire [7:0] sw_in,
input wire enable_sw,
output wire [2:0] led_code,
output wire led_valid,
output wire [7:0] seg_disp
);
prio_enc_8to3 u_enc (
.enable_ctrl(enable_sw),
.data_bus(sw_in),
.code_out(led_code),
.valid_flag(led_valid)
);
seg_driver u_seg (
.hex_in(led_code),
.seg_lines(seg_disp)
);
endmodule
検証環境の構築とハードウェア連携
C++シミュレーションテストベンチ
VerilatorおよびNVBoard双方で利用可能な検証スキャフォールディングです。波形取得とクロック単位の評価を分離し、テストベクタの投入を簡素化します。
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vtop_system.h"
static VerilatedContext* ctx_handle = nullptr;
static VerilatedVcdC* trace_ptr = nullptr;
static Vtop_system* dut_ptr = nullptr;
void setup_context() {
ctx_handle = new VerilatedContext;
trace_ptr = new VerilatedVcdC;
dut_ptr = new Vtop_system;
ctx_handle->traceEverOn(true);
dut_ptr->trace(trace_ptr, 0);
trace_ptr->open("waveform.vcd");
}
void apply_input_and_step(const uint8_t en, const uint32_t data) {
dut_ptr->enable_sw = en;
dut_ptr->sw_in = data;
dut_ptr->eval();
ctx_handle->timeInc(1);
trace_ptr->dump(ctx_handle->time());
}
void teardown_context() {
apply_input_and_step(0, 0);
trace_ptr->close();
delete dut_ptr;
delete trace_ptr;
delete ctx_handle;
}
int main(int argc, char** argv) {
setup_context();
// 検証ベクタ投入
apply_input_and_step(0b0, 0x00);
apply_input_and_step(0b1, 0x03);
apply_input_and_step(0b1, 0x06);
apply_input_and_step(0b1, 0x04);
apply_input_and_step(0b1, 0x08);
apply_input_and_step(0b1, 0x10);
apply_input_and_step(0b1, 0x40);
apply_input_and_step(0b1, 0x80);
teardown_context();
return 0;
}
NVBoard連携用エントリーポイント
ハードウェアボード上でリアルタイムに入出力を反映させるためのバインディングループです。
#include <nvboard.h>
#include "Vtop_system.h"
static Vtop_system board_dut;
void nvboard_bind_all_pins(Vtop_system* top);
void clock_tick() {
board_dut.eval();
}
int main() {
nvboard_bind_all_pins(&board_dut);
nvboard_init();
while (true) {
nvboard_update();
clock_tick();
}
return 0;
}
ピンアサイン定義(.nxdc)
top=top_system
sw_in (SW7, SW6, SW5, SW4, SW3, SW2, SW1, SW0)
enable_sw (SW8)
led_code (LD2, LD1, LD0)
led_valid (LD4)
seg_disp (SEG0A, SEG0B, SEG0C, SEG0D, SEG0E, SEG0F, SEG0G, DEC0P)
ビルドおよび実行ワークフロー
# 1. VerilatorによるC++コード生成とコンパイル
verilator -Wall --trace -cc top_system.v seg_driver.v --exe sim_main.cpp
# 2. Makefileを用いた実行ファイル生成
make -C obj_dir -f Vtop_system.mk
# 3. シミュレーション実行とVCD波形生成
./obj_dir/Vtop_system
# 4. GTKWaveによる波形可視化
gtkwave waveform.vcd
# 5. NVBoard環境でのハードウェアビルド
make
cd build
./top_system