見出し画像

11.シリアルパラレル変換回路を作る

ここでは、シリアルで入力される8bitをパラレルデータとして出力する回路を作成します。

問題

 外部からシリアルで8bitのデータが入力されると(ENがHレベル1クロックで1bit入力)、パラレル8bit出力(出力中はvalid信号をHにし、出力期間外はLにする)する回路を作りなさい。
#出力の上位bitには、一番早くシリアル入力したデータが入ります

シンボル図
動作イメージ図

さてどう作る?

さあどうしましょうか。まず方針を立ててみましょう。
 ・シリアル受信回路(D型フリップフロップを並べる)が必要
 ・パラレル出力する際、相手に取得してもらうタイミングvalidをカウンタで作る
 ・パラレル出力は、D型フリップフロップ群の各出力をつなげればよい
まずはこんな感じでイメージできれば良いと思います。(頭でイメージしたものは紙に書いておくと良いと思います)

VHDLで書いてみる

 上部のprocess(clk, reset_n)では、シリアルデータを受けて記憶するためD型フリップフロップ8個を直列に並べています。入力enがHの時にこのフリップフロップ群(シフトレジスタとも言う)は動作します。
 下部のprocess(clk, reset_n)では、出力のvalid信号(出力データが確定したことを示す信号)がHになるタイミングを作る回路になります。入力enの数を数えて8個入力されたら(=8ビット入力されたら)0に戻しています。
それでその下段にある、valid <= icnt(3); はすなわちカウンタ4ビット目がvalid信号だと定義していますが、8個(2進数”1000”)数えたら0に戻るカウンタになっていますから実質8個データが入力されるごとにvalidが1クロック分Hになる設計になっています。
 最下段にある 出力dout <= id7&id6&id5&id4&id3&id2&id1&id0; はフリップフロップ群に入っている出力データを単純に8ビット化しています。要するに8個データが入力されるとデータが揃うということになります。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity sp8 is
    Port ( 	clk 	: in  STD_LOGIC;
           	reset_n     : in  STD_LOGIC;
           	en 	: in STD_LOGIC;
           	d 	: in STD_LOGIC;
           	valid	: out STD_LOGIC;
           	dout	: out STD_LOGIC_VECTOR (7 downto 0));
end sp8;

architecture rtl of sp8 is
    signal id0,id1,id2,id3,id4,id5,id6,id7 : STD_LOGIC;
    signal icnt: STD_LOGIC_VECTOR (3 downto 0);
begin

	process(clk, reset_n)
    begin
        if reset_n = '0' then
            id0 <= '0';
            id1 <= '0';
            id2 <= '0';
            id3 <= '0';
            id4 <= '0';
            id5 <= '0';
            id6 <= '0';
            id7 <= '0';
        elsif rising_edge(clk) then
        	if en = '1' then
            	id0 <= d;
            	id1 <= id0;
            	id2 <= id1;
            	id3 <= id2;
            	id4 <= id3;
            	id5 <= id4;
            	id6 <= id5;
            	id7 <= id6;	
            end if;
        end if;
	end process;
	    
    process(clk, reset_n)
    begin
        if reset_n = '0' then
            icnt <= "0000";
        elsif rising_edge(clk) then
        	if icnt = "1000" then
            	icnt <= "0000";
            elsif en = '1' then
            	icnt <= icnt + '1';
        	end if;
        end if;
    end process;
  
    valid <= icnt(3);

   	dout <= id7&id6&id5&id4&id3&id2&id1&id0;
   	
end rtl;

Verilogで書いてみる

VHDLコードをChatGPTでVerilog変換してみました。ざっと見たところ問題なさそうですね。忠実にVHDLから変換できていると思います。

module sp8 (
    input wire clk,           // クロック入力
    input wire reset_n,       // アクティブローのリセット入力
    input wire en,            // イネーブル入力
    input wire d,             // データ入力
    output wire valid,        // 有効フラグ出力
    output wire [7:0] dout    // データ出力
);

    reg id0, id1, id2, id3, id4, id5, id6, id7; // シフトレジスタ用レジスタ
    reg [3:0] icnt; // カウンタ用レジスタ

    // シフトレジスタ処理
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            id0 <= 1'b0;
            id1 <= 1'b0;
            id2 <= 1'b0;
            id3 <= 1'b0;
            id4 <= 1'b0;
            id5 <= 1'b0;
            id6 <= 1'b0;
            id7 <= 1'b0;
        end else if (en) begin
            id0 <= d;
            id1 <= id0;
            id2 <= id1;
            id3 <= id2;
            id4 <= id3;
            id5 <= id4;
            id6 <= id5;
            id7 <= id6;
        end
    end

    // カウンタ処理
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            icnt <= 4'b0000;
        end else if (icnt == 4'b1000) begin
            icnt <= 4'b0000;
        end else if (en) begin
            icnt <= icnt + 1;
        end
    end

    // valid信号の生成
    assign valid = icnt[3];

    // dout信号の生成
    assign dout = {id7, id6, id5, id4, id3, id2, id1, id0};

endmodule

シミュレーション結果

実は動作イメージ図がシミュレーション結果になっていますが、再度掲載します。入力enが8個入るごとに出力データが確定してそのタイミングで出力validが1クロック分Hが出ていることが分かると思います。

シミュレーション結果図

おわりに

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

いいなと思ったら応援しよう!