![見出し画像](https://assets.st-note.com/production/uploads/images/151148499/rectangle_large_type_2_fcc4fc265c48b5ca84b89d5abebc7926.png?width=1200)
14.レジスタを実装して汎用I/Oポートを作る
ここではCPU側に対しての一般的なインターフェースとレジスタを実装するとともに汎用I/Oポートの機能を持つ回路作成について触れていきます。
問題
以下の回路モジュール(8本汎用I/Oポート)を作成してください。
<レジスタ解説書>
アドレス 属性 解説 データ
0x00 リードライト ポート出力値 8bit
0x01 リードライト ポート方向 8bit
(H:出力 L:入力)
0x02 リードライト ポート入力値 8bit
#0x は16進数表記
![](https://assets.st-note.com/img/1723967761563-gp8UiFWKAm.png)
入力信号解説
adr[1:0] 2ビットのアドレス信号
wdata[7:0] ライト時のデータ信号
cs_n チップ(モジュール)セレクト信号 Lアクティブ
wr_n ライト信号 Lアクティブ
rd_n リード信号 Lアクティブ
reset_n リセット信号 非同期リセットLアクティブ
出力信号
rdata[7:0] 8ビットの演算結果出力信号(CPU側 I/F用)
pt[7:0] 汎用ポート(8本)
![](https://assets.st-note.com/img/1723969721392-6AGV6kTFSJ.png?width=1200)
さてどう作る?
汎用ポートを考える前に、まず双方向I/Oのポートとはどういうものかについて頭にイメージしておく必要があると思います。今回は以下をイメージしています。
![](https://assets.st-note.com/img/1723970020742-MM66tYTOcB.png)
ibinは外部pt端子から入力される信号
iboutは外部pt端子から出力される信号
ibcntはこのI/Oを入力とするか出力とするかを決める信号
(H:出力 L:入力)
ibcntがLならばZ(ハイインピーダンス)となるので入力ポートとして指示したこととなります。お分かりになりますでしょうか。
あとは前章(13.レジスタを実装して和差算回路を作る)同様にレジスタ解説書を見て実装していけばよいです。
VHDLで書いてみる
主に5つのprocess文で構成しています。
上から順にこんな感じになっています。
・ポート出力値を設定するレジスタ
・ポート入力値を格納する
・ポートの入出力を設定するレジスタ
・各レジスタの値をリードする
・ポート8本を作る
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity pt8 is
Port ( clk : in STD_LOGIC;
reset_n : in STD_LOGIC;
adr : in STD_LOGIC_VECTOR (1 downto 0);
cs_n : in STD_LOGIC;
wr_n : in STD_LOGIC;
wdata : in STD_LOGIC_VECTOR (7 downto 0);
rd_n : in STD_LOGIC;
rdata : out STD_LOGIC_VECTOR (7 downto 0);
pt : inout STD_LOGIC_VECTOR (7 downto 0));
end pt8;
architecture rtl of pt8 is
signal ibout,iregin,ibin,ibcnt :STD_LOGIC_VECTOR (7 downto 0);
begin
process(clk, reset_n)
begin
if reset_n = '0' then
ibout <= (others => '0');
elsif rising_edge(clk) then
if cs_n='0' and wr_n='0' and adr="00" then
ibout <= wdata;
end if;
end if;
end process;
process(clk, reset_n)
begin
if reset_n = '0' then
iregin <= (others => '0');
elsif rising_edge(clk) then
iregin <= ibin;
end if;
end process;
process(clk, reset_n)
begin
if reset_n = '0' then
ibcnt <= (others => '0');
elsif rising_edge(clk) then
if cs_n='0' and wr_n='0' and adr="01" then
ibcnt <= wdata;
end if;
end if;
end process;
process(clk, reset_n)
begin
if reset_n = '0' then
rdata <= (others => '0');
elsif rising_edge(clk) then
if cs_n = '0' and rd_n = '0' then
case adr is
when "00" =>
rdata <= ibout;
when "01" =>
rdata <= ibcnt;
when "10" =>
rdata <= iregin;
when others =>
rdata <= (others => '0');
end case;
end if;
end if;
end process;
ibin <= pt;
process(ibcnt,ibout)
begin
for i in 0 to 7 loop
if ibcnt(i) = '0' then
pt(i) <= 'Z';
else pt(i) <= ibout(i);
end if;
end loop;
end process;
end rtl;
Verilogで書いてみる
VHDLコードをChatGPTでVerilog変換してみました。うまく変換できているようには見えます。
module pt8 (
input wire clk,
input wire reset_n,
input wire [1:0] adr,
input wire cs_n,
input wire wr_n,
input wire [7:0] wdata,
input wire rd_n,
output reg [7:0] rdata,
inout wire [7:0] pt
);
reg [7:0] ibout, iregin, ibin, ibcnt;
// Process for writing to ibout
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
ibout <= 8'b0;
end else if (!cs_n && !wr_n && adr == 2'b00) begin
ibout <= wdata;
end
end
// Process for writing to iregin
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
iregin <= 8'b0;
end else begin
iregin <= ibin;
end
end
// Process for writing to ibcnt
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
ibcnt <= 8'b0;
end else if (!cs_n && !wr_n && adr == 2'b01) begin
ibcnt <= wdata;
end
end
// Process for reading data
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
rdata <= 8'b0;
end else if (!cs_n && !rd_n) begin
case (adr)
2'b00: rdata <= ibout;
2'b01: rdata <= ibcnt;
2'b10: rdata <= iregin;
default: rdata <= 8'b0;
endcase
end
end
// Assign pt to ibin
assign ibin = pt;
// Process for controlling pt based on ibcnt and ibout
always @(*) begin
integer i;
for (i = 0; i < 8; i = i + 1) begin
if (ibcnt[i] == 1'b0) begin
pt[i] = 1'bz;
end else begin
pt[i] = ibout[i];
end
end
end
endmodule
シミュレーション結果
図に直接解説しましたのでご覧ください。
![](https://assets.st-note.com/img/1723971707916-frCbOEbk3A.png?width=1200)
おわりに
今回はCPU側に対しての一般的なインターフェースとレジスタを実装し、汎用I/Oポートの作成についてご紹介しました。双方向I/Oポートとはどういうものかを理解する必要がありますが、逆に言うとそれが分かっていれば難しくありません。ありがとうございました。