12.パラレルシリアル変換回路を作る
ここでは、パラレルで入力される8bitをシリアルデータとして出力する回路を作成します。
問題
外部から8bitのデータが入力されると、シリアルで出力する回路を作りなさい。
入力条件:en1クロックHのタイミングで入力dinデータ8ビットを取り込む
出力条件:入力dinデータ8ビットを取り込んだら、1クロック毎に1ビット(パラレルの上位ビット順に)出力doutする。データ出力期間中は、valid信号をHにし、出力期間外はLにする
さてどう作る?
さあどうしましょうか。まず方針を立ててみましょう。
・パラレル受信回路(enがHのタイミングでデータ取得)が必要
・入力enがHレベルを起点に3bitカウンタのカウントダウンさせる
・カウンタの値によって出力doutに乗せる値を変える
(例:カウンタの値が6ならば、受信したパラレルデータの6ビット目のデータを乗せる)
・出力validは、カウンタを動作させるイネーブル信号と同じ
まずはこんな感じでイメージできれば良いと思います。また動作イメージ図の詳細を紙に書いておかないと難しいかもしれません。(頭でイメージしたものは紙に書いておくと良いと思います)
VHDLで書いてみる
一番上にある process(clk, reset_n) はパラレル受信回路になります。
二番目の process(clk, reset_n) はカウンタを進めるicnten信号を作っています。またこの信号は出力validそのものでもあります。
三番目の process(clk, reset_n) は icnten信号に従ってデクリメントさせています。
最下段の process(icnt,id) はカウンタの値に従って受信回路で獲得したデータのどのビットの値を乗せるかを指定しています。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity ps8 is
Port ( clk : in STD_LOGIC;
reset_n : in STD_LOGIC;
en : in STD_LOGIC;
din : in STD_LOGIC_VECTOR (7 downto 0);
valid : out STD_LOGIC;
dout : out STD_LOGIC);
end ps8;
architecture rtl of ps8 is
signal id : STD_LOGIC_VECTOR (7 downto 0);
signal icnt: STD_LOGIC_VECTOR (2 downto 0);
signal icnten :STD_LOGIC;
begin
process(clk, reset_n)
begin
if reset_n = '0' then
id <= (others => '0');
elsif rising_edge(clk) then
if en = '1' then
id <= din;
end if;
end if;
end process;
process(clk, reset_n)
begin
if reset_n = '0' then
icnten <= '0';
elsif rising_edge(clk) then
if icnt = "000" then
icnten <= '0';
elsif icnt = "111" and en = '1' then
icnten <= '1';
end if;
end if;
end process;
valid <= icnten;
process(clk, reset_n)
begin
if reset_n = '0' then
icnt <= "111";
elsif rising_edge(clk) then
if icnten = '0' then
icnt <= "111";
elsif icnten = '1' then
icnt <= icnt - '1';
end if;
end if;
end process;
process(icnt,id)
begin
case icnt is
when "000" => dout <= id(0);
when "001" => dout <= id(1);
when "010" => dout <= id(2);
when "011" => dout <= id(3);
when "100" => dout <= id(4);
when "101" => dout <= id(5);
when "110" => dout <= id(6);
when "111" => dout <= id(7);
when others => dout <= id(7);
end case;
end process;
end rtl;
Verilogで書いてみる
VHDLコードをChatGPTでVerilog変換してみました。一か所おかしなところがあったので手修正しています。これでどうでしょうか。
module ps8 (
input wire clk, // クロック入力
input wire reset_n, // アクティブローのリセット入力
input wire en, // イネーブル入力
input wire [7:0] din, // 8ビットデータ入力
output reg valid, // 有効フラグ出力
output reg dout // データ出力
);
reg [7:0] id; // データ保存用レジスタ
reg [2:0] icnt; // カウンタ用レジスタ
reg icnten; // カウンタ有効フラグ
// データ保存プロセス
always @(posedge clk or negedge reset_n) begin
if (!reset_n)
id <= 8'b00000000;
else if (en)
id <= din;
end
// カウンタ有効フラグの設定プロセス
always @(posedge clk or negedge reset_n) begin
if (!reset_n)
icnten <= 1'b0;
else if (icnt == 3'b000)
icnten <= 1'b0;
else if (icnt == 3'b111 && en)
icnten <= 1'b1;
end
// valid信号の生成
always @(*) begin
valid = icnten;
end
// カウンタの設定プロセス
always @(posedge clk or negedge reset_n) begin
if (!reset_n)
icnt <= 3'b111;
else if (icnten == 1'b0)
icnt <= 3'b111;
else if (icnten == 1'b1)
icnt <= icnt - 1;
end
// dout信号の生成プロセス
always @(*) begin
case (icnt)
3'b000: dout = id[0];
3'b001: dout = id[1];
3'b010: dout = id[2];
3'b011: dout = id[3];
3'b100: dout = id[4];
3'b101: dout = id[5];
3'b110: dout = id[6];
3'b111: dout = id[7];
default: dout = id[7];
endcase
end
endmodule
シミュレーション結果
実は動作イメージ図がシミュレーション結果になっていますが、再度掲載します。入力enがHを起点にデータを受信し、valid信号を出しながら受信したデータの上位ビットのデータから順番にdoutに出力しています。8ビット分を送ったところでvalidをLへ落としていることが分かると思います。
おわりに
今回はパラレルシリアル変換回路をご紹介しました。コードを書きながら考えると難しいので、書く前にある程度の設計方針を立てることをおすすめします。できればこの時点で動作イメージ図を手書きでノートに書き留めておければベストでしょう。ありがとうございました。
この記事が気に入ったらサポートをしてみませんか?