見出し画像

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へ落としていることが分かると思います。

シミュレーション結果図

おわりに

今回はパラレルシリアル変換回路をご紹介しました。コードを書きながら考えると難しいので、書く前にある程度の設計方針を立てることをおすすめします。できればこの時点で動作イメージ図を手書きでノートに書き留めておければベストでしょう。ありがとうございました。

この記事が気に入ったらサポートをしてみませんか?