A2PDP11 (10) 4MB RAM の実装
Tang Nano 9K の PSRAM を使って、RAM を 4MB に拡張します。
PSRAM のリードアクセスが遅いため、リードサイクルを引き延ばす必要があります。そのための制御信号用のポートが足りないので、配線を変更しました。
BS<1:0> と DAL<21:16> を、DAL<15:0> に多重化し、/DALHI_OE と /DALLO_OE で切り替えるようにしました。
.cst ファイルを回路に合わせて修正します。
//File Title: Physical Constraints file
//Tool Version: V1.9.10 (64-bit)
//Part Number: GW1NR-LV9QN88PC6/I5
//Device: GW1NR-9
//Device Version: C
//Created Time: Sun 08 11 14:16:13 2024
// TEST8 2024.08.31 4MB RAM
IO_LOC "mclk" 52
IO_PORT "mclk" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "dal[6]" 25;
IO_PORT "dal[6]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[7]" 26;
IO_PORT "dal[7]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[8]" 27;
IO_PORT "dal[8]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[0]" 28;
IO_PORT "dal[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[9]" 29;
IO_PORT "dal[9]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[10]" 30;
IO_PORT "dal[10]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[11]" 33;
IO_PORT "dal[11]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[12]" 34;
IO_PORT "dal[12]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[13]" 40;
IO_PORT "dal[13]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[14]" 35;
IO_PORT "dal[14]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[15]" 41;
IO_PORT "dal[15]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[1]" 42;
IO_PORT "dal[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[2]" 51;
IO_PORT "dal[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[3]" 53;
IO_PORT "dal[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[4]" 54;
IO_PORT "dal[4]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dal[5]" 55;
IO_PORT "dal[5]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dallo_oe_n" 56;
IO_PORT "dallo_oe_n" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "dalhi_oe_n" 57;
IO_PORT "dalhi_oe_n" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "nxm_n" 63;
IO_PORT "nxm_n" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "aio[0]" 86
IO_PORT "aio[0]" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "aio[1]" 85
IO_PORT "aio[1]" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "aio[2]" 84
IO_PORT "aio[2]" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "aio[3]" 83
IO_PORT "aio[3]" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "bufctl_n" 82
IO_PORT "bufctl_n" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "ale_n" 81
IO_PORT "ale_n" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "sctl_n" 80
IO_PORT "sctl_n" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "clk" 79
IO_PORT "clk" IO_TYPE=LVCMOS33OD18 PULL_MODE=UP BANK_VCCIO=1.8;
IO_LOC "dv" 77;
IO_PORT "dv" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "miss_n" 76;
IO_PORT "miss_n" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[0]" 68;
IO_PORT "ad[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[1]" 69;
IO_PORT "ad[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[2]" 75;
IO_PORT "ad[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[3]" 74;
IO_PORT "ad[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[4]" 73;
IO_PORT "ad[4]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[5]" 72;
IO_PORT "ad[5]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[6]" 71;
IO_PORT "ad[6]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "ad[7]" 70;
IO_PORT "ad[7]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "rrdy" 48;
IO_PORT "rrdy" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "rstb" 49;
IO_PORT "rstb" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "wrdy" 31;
IO_PORT "wrdy" IO_TYPE=LVCMOS33 PULL_MODE=UP BANK_VCCIO=3.3;
IO_LOC "wstb" 32;
IO_PORT "wstb" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8 BANK_VCCIO=3.3;
Tang Nano 9K の FPGA GW1NR-9 には、二つの 32Mb HyperBus pSRAM(W955D8MBYA)が内蔵されています。PSRAM のインターフェースは、PSRAM Memory Interface HS 2CH V2.0 を使いました。
Option タブで、Burst Mode を 16 に変更します。
上記の設定では、1 CH 当たり 1 回のバーストアクセスで、16 バイトのデータの読み出し、または、書き込みが行われます。
アドレスは、以下のように割り当てられます。GOWIN のマニュアルを読んでもよくわからなかったので、実際に試して確認しました。アドレス addr は、1 ワード(2 バイト)単位の位置です。data0 から data3 が、一回のバーストアクセスで読み書きされるデータです。アドレスは、8 ワード(16 バイト)境界で折り返されます。
たとえば、addr = 000002 に指定すると、data3 は 000000、data0 は 000002、data1 は 000004、data2 は 000006 から読み書きされます。
PSRAM アクセスのモジュール ram.sv を作成します。
O_psram_ck から O_psram_reset_n は、PSRAM 用の接続端子名です。これも、GOWIN の IP マニュアルではわからないので、リファレンスデザインを参考にしました。
ram_read は、読み出し時に HIGH にします。
ram_write は、書き込み時に HIGH にします。
ram_byte は、バイト書き込み時に HIGH にします。
ram_addr は、RAM アクセスアドレス(バイト単位)です。
ram_rdata は、読み出しデータです。
ram_wdata は、書き込みデータです。
mclk は、Tang Nano 9K の 27 MHz クロックです。
`default_nettype none
// PSRAM interface module
// TEST8 2024.08.31 4MB RAM
module ram (
output wire [1:0] O_psram_ck,
output wire [1:0] O_psram_ck_n,
inout wire [15:0] IO_psram_dq,
inout wire [1:0] IO_psram_rwds,
output wire [1:0] O_psram_cs_n,
output wire [1:0] O_psram_reset_n,
input wire ram_read,
input wire ram_write,
input wire ram_byte,
input wire [21:0] ram_addr,
output reg [15:0] ram_rdata,
input wire [15:0] ram_wdata,
input wire mclk
);
PSRAM アクセス用のクロックを生成します。
memory_clk は、150 MHz としました。
Enable LOCK をチェックして、pll_lock 信号を出力します。
PLL Phase And Duty Cycle Adjustment を Static にして、memory_clk_p を、位相 90 度で生成します。
clk_d は、memory_clk の 4 分周 37.5 MHz に設定します。
ram.sv の続きです。PSRAM 制御用の信号と、PSRAM IP のインスタンスを記述します。
Gowin_rPLL_ram pll_ram(
.clkout(memory_clk), //output clkout
.lock(pll_lock), //output lock
.clkoutp(memory_clk_p), //output clkoutp
.clkoutd(clk_d), //output clkoutd
.clkin(mclk) //input clkin
);
logic clk_d;
logic rst_n;
logic memory_clk;
logic memory_clk_p;
logic pll_lock;
logic init_calib0;
logic init_calib1;
logic clk_out;
logic cmd0;
logic cmd1;
logic cmd_en0;
logic cmd_en1;
logic [20:0] addr0;
logic [20:0] addr1;
logic [31:0] wr_data0;
logic [31:0] wr_data1;
logic [31:0] rd_data0;
logic [31:0] rd_data1;
logic rd_data_valid0;
logic rd_data_valid1;
logic [3:0] data_mask0;
logic [3:0] data_mask1;
assign rst_n = 1'b1;
assign cmd1 = 1'b0;
assign cmd_en1 = 1'b0;
assign addr1 = 21'b0;
assign wr_data1 = 32'b0;
assign data_mask1 = 4'b0;
PSRAM_Memory_Interface_HS_2CH_V2_Top psram(
.clk_d(clk_d), //input clk_d
.rst_n(rst_n), //input rst_n
.memory_clk(memory_clk), //input memory_clk
.memory_clk_p(memory_clk_p), //input memory_clk_p
.pll_lock(pll_lock), //input pll_lock
.O_psram_ck(O_psram_ck), //output [1:0] O_psram_ck
.O_psram_ck_n(O_psram_ck_n), //output [1:0] O_psram_ck_n
.IO_psram_rwds(IO_psram_rwds), //inout [1:0] IO_psram_rwds
.O_psram_reset_n(O_psram_reset_n), //output [1:0] O_psram_reset_n
.IO_psram_dq(IO_psram_dq), //inout [15:0] IO_psram_dq
.O_psram_cs_n(O_psram_cs_n), //output [1:0] O_psram_cs_n
.init_calib0(init_calib0), //output init_calib0
.init_calib1(init_calib1), //output init_calib1
.clk_out(clk_out), //output clk_out
.cmd0(cmd0), //input cmd0
.cmd1(cmd1), //input cmd1
.cmd_en0(cmd_en0), //input cmd_en0
.cmd_en1(cmd_en1), //input cmd_en1
.addr0(addr0), //input [20:0] addr0
.addr1(addr1), //input [20:0] addr1
.wr_data0(wr_data0), //input [31:0] wr_data0
.wr_data1(wr_data1), //input [31:0] wr_data1
.rd_data0(rd_data0), //output [31:0] rd_data0
.rd_data1(rd_data1), //output [31:0] rd_data1
.rd_data_valid0(rd_data_valid0), //output rd_data_valid0
.rd_data_valid1(rd_data_valid1), //output rd_data_valid1
.data_mask0(data_mask0), //input [3:0] data_mask0
.data_mask1(data_mask1) //input [3:0] data_mask1
);
PSRAM の制御は clk_out に同期して行います。
ram_read と ram_write を、clk_out に同期させ、rd1 および wr1 とします。
logic rd0;
logic rd1;
logic wr0;
logic wr1;
always_ff@(posedge clk_out) begin
rd0 <= ram_read;
rd1 <= rd0;
wr0 <= ram_write;
wr1 <= wr0;
end
メモリアクセスはステートマシンで制御します。
mcycle が、状態を示します。
0:アイドル状態で、読み出し(rd1)または、書き込み(wr1)を待ちます。
1 - 14:読み出しサイクルです。
15 - 28:書き込みサイクルです。
init_calib0 は、PSRAM の初期化が完了すると HIGH になります。
rst_n は、PSRAM のリセットです。本実装では使っていません(常に HIGH)。
読み出し要求(rd1 = 1)があると、addr0 を ram_addr の LSB をカットした、ワード単位のアドレスに設定します。cmd0 を READ (0)にし、cmd_en0 を 1 にします。mcycle を 1 にし、読み出しサイクルに移ります。
書き込み要求(wr1 = 1)があると、ワードまたはバイトアクセスに従い、data_mask0 を設定します。mask の各ビットが 1 バイトに対応し、0 が書き込み許可となります。 バイトアクセス時は、ram_addr の LSB をみて、偶数バイトなら下位バイトが有効、奇数バイトなら上位バイトが有効です。
cmd0 を WRITE(1)にし、cmd_en0 を 1 にします。mcycle を 15 にし、書き込みサイクルに移ります。
読み出しサイクルでは、cmd_en0 を 0 に戻し、mcycle を 14 までカウントアップし、rd1 が LOW になるのを待ちます。
書き込みサイクルでは、cmd_en0 を 0 に戻し、data_mask0 を全ビット 1 にして、後続の書き込みデータを抑制します。mcycle を 28 までカウントアップし、wr1 が LOW になるのを待ちます。
logic [5:0] mcycle;
always_ff@(posedge clk_out or negedge rst_n) begin
if (!rst_n) begin
mcycle <= 0;
wr_data0 <= 32'b0;
cmd_en0 <= 0;
data_mask0 <= 4'b1111;
end else if (init_calib0) begin
if (mcycle == 0) begin
if (rd1) begin
addr0 <= ram_addr[21:1];
cmd0 <= 0; // READ
cmd_en0 <= 1;
mcycle <= 1;
end else if (wr1) begin
if (ram_byte) begin
data_mask0 <= {ram_addr[0], !ram_addr[0], 2'b11};
end else begin
data_mask0 <= 4'b0011;
end
wr_data0[31:16] <= ram_wdata;
addr0 <= ram_addr[21:1];
cmd0 <= 1; // WRITE
cmd_en0 <= 1;
mcycle <= 15;
end
end else if (mcycle == 1) begin
cmd_en0 <= 0;
mcycle <= 2;
end else if (mcycle < 14) begin
mcycle <= mcycle + 1'b1;
end else if (mcycle == 14) begin
if (!rd1) begin
mcycle <= 0;
end
end else if (mcycle == 15) begin
cmd_en0 <= 0;
data_mask0 <= 4'b1111;
mcycle <= 16;
end else if (mcycle < 28) begin
mcycle <= mcycle + 1'b1;
end else if (mcycle == 28) begin
if (!wr1) begin
mcycle <= 0;
end
end
end
end
PSRAM の読み出しデータが確定すると、rd_data_valid0 が、HIGH になります。読み出しは 4 クロックで行われるので、rcycle でカウントし、最初のクロックの上位ワードデータを ram_rdata に取り込みます。
always_ff@(posedge clk_out) begin
if (rd1) begin
if (rd_data_valid0 && (rcycle == 1'b0)) begin
ram_rdata <= rd_data0[31:16];
end
end else begin
ram_rdata <= 16'bz;
end
end
logic [1:0] rcycle;
always_ff@(posedge clk_out) begin
if (mcycle == 1) begin
rcycle <= 0;
end else if (rd_data_valid0) begin
rcycle <= rcycle + 1'b1;
end
end
endmodule
`default_nettype wire
top.sv を修正します。
top モジュールのインターフェースを回路の変更に合わせて修正します。
`default_nettype none
// DCJ11 TangNano interface
// TEST2 2024.07.28 Bus read, nanja.info
// TSET3 2024.08.03 Start-Up config, nanja.info
// TEST4 2024.08.07 NXM abort signal
// TEST5 2024.08.12 Console ODT output
// TEST6 2024.08.25 Console ODT input
// TEST7 2024.08.26 2KB RAM
// TEST8 2024.08.31 4MB RAM
module top (
inout wire [15:0] dal, // DAL<21:0>, BS<1:0>
input wire [3:0] aio, // AIO<3:0>
input wire bufctl_n,
input wire ale_n,
output wire nxm_n,
input wire sctl_n,
input wire clk,
output reg dv,
output reg miss_n,
output reg dallo_oe_n,
output reg dalhi_oe_n,
input wire rrdy, // Ready to read from DCJ11's ODT data
output reg rstb, // Strobe for read from DCJ11's ODT data
input wire wrdy, // Ready to write to DCJ11's ODT data
output reg wstb, // Strobe for write to DCJ11's ODT data
inout wire [7:0] ad, // ODT data
output wire [1:0] O_psram_ck,
output wire [1:0] O_psram_ck_n,
inout wire [15:0] IO_psram_dq,
inout wire [1:0] IO_psram_rwds,
output wire [1:0] O_psram_cs_n,
output wire [1:0] O_psram_reset_n,
input wire mclk
);
// AIO CODE
parameter NIO = 4'b1111; // internal operation only, no I/O
parameter GP_READ = 4'b1110; // General-Purpose read
parameter INTERRUPT_ACK = 4'b1101; // Interrupt acknowledge, vector read
parameter REQEST_READ = 4'b1100; // Instruction-stream request read
parameter RMW_NOLOCK = 4'b1011; // Read/Modify/Write - no bus lock
parameter RMW_BUSLOCK = 4'b1010; // Read/Modify/Write - bus lock
parameter DATA_READ = 4'b1001; // Data-stream read
parameter DEMAND_READ = 4'b1000; // Instruction-stream demand read
parameter GP_WRITE = 4'b0101; // General-Purpose word write
parameter BYTE_WRITE = 4'b0011; // Bus byte write
parameter WORD_WRITE = 4'b0001; // Bus word write
// BANK SELECT
parameter BS_MEM = 2'b00; // Memory
parameter BS_SYS = 2'b01; // System register
parameter BS_EXT = 2'b10; // Extarnal I/O
parameter BS_INT = 2'b11; // Internal register
// GP CODE
parameter POWER_UP0 = 8'o000; // Reads the power-up mode
parameter POWER_UP2 = 8'o002; // Reads the power-up mode, clears the FPA’s FPS
// DLART
parameter DLART = 19'o1777756; // DLART registers
parameter RCSR = 22'o17777560; // Receiver Control and Status Register
parameter RBUF = 22'o17777562; // Receiver Buffer Register
parameter XCSR = 22'o17777564; // Transmitter Control And Status Register
parameter XBUF = 22'o17777566; // Transmitter Buffer Register
top.sv を修正します。
DAL と BS が有効な期間は、T1 が HIGH の間だけです。
この期間に、下位ワードと上位ワードを切り替えて読み込むために CLK の2倍信号 clk_x2 を生成します。ALE の立ち下がりから、最初の clk_x2 の立ち上がりで、DAL の下位ワードを取り込みます。次の clk_x2 の立ち上がり(CLK T1 の立ち下がり)で、DAL の上位ワードと BS を取り込みます。
logic clk_x4; // clk x 4 = 72MHz
logic clk_x2; // clk x 2 = 36MHz
Gowin_rPLL rpll(
.clkout(clk_x4), //output clkout
.clkoutd(clk_x2), //output clkoutd
.clkin(clk) //input clkin
);
logic [7:0] count;
logic [15:0] mdallo;
logic [21:0] mdal;
logic [3:0] maio;
logic [1:0] mbs;
logic [7:0] gp_code;
always_ff@(posedge clk_x2) begin
if (ale_n) begin
count <= 0;
end else begin
if (count == 7'd0) begin
dallo_oe_n <= 1'b1;
dalhi_oe_n <= 1'b0;
if ((aio == GP_READ) || (aio == GP_WRITE)) begin
gp_code <= dal[7:0];
end else begin
gp_code <= 8'b11111111;
end
mdallo <= dal;
end else if (count == 7'd1) begin
maio <= aio;
mbs[0] <= dal[6];
mbs[1] <= dal[7];
mdal[21] <= dal[8];
mdal[20] <= dal[0];
mdal[19] <= dal[9];
mdal[18] <= dal[10];
mdal[17] <= dal[11];
mdal[16] <= dal[12];
mdal[15:0] <= mdallo;
dallo_oe_n <= 1'b0;
dalhi_oe_n <= 1'b1;
end
count <= count + 1'b1;
end
end
POWER_UP の処理は、変更ありません。
NXM(Non-existent Memory)アボートの判定を、177760000 以上に変更します。
always_ff@(negedge bufctl_n) begin
if ((gp_code == POWER_UP0) || (gp_code == POWER_UP2)) begin
dal_out <= 16'b0000000_0_0000_0_01_1;
// BOOT_ADDRESS, FPE, UNUSED, HALT, MODE, POK
end else begin
dal_out <= 0;
end
end
assign nxm_n = sctl_n ? 1'b1 : !nxm;
logic nxm;
always_ff@(negedge sctl_n) begin
if ((maio[3:2] == 2'b10) || (maio[3:2] == 2'b00)) begin
// RMW_BUSLOCK, RMW_NOLOCK, DATA_READ, DEMAND_READ, WORD_WRITE, BYTE_WRITE
if (mbs == BS_MEM) begin
if (mdal >= 22'o17760000) begin
nxm <= 1'b1;
end
end
if (mbs == BS_EXT) begin
if (mdal[21:3] == DLART) begin
nxm <= 1'b0;
end else begin
nxm <= 1'b1;
end
end
end else begin
nxm <= 1'b0;
end
end
コンソール ODT の入力を取りこぼすことがあったので、wxrdy の解除タイミングを修正しました。
logic rxrdy;
logic rrdy1;
logic rrdy0;
logic [7:0] rdata;
always_ff@(negedge clk) begin
rrdy0 <= rrdy;
rrdy1 <= rrdy0;
end
always_ff@(negedge clk) begin
if ((sctl_n == 0) && (mdal == XBUF)) begin
rstb <= 1'b1;
rxrdy <= 1'b0;
rdata <= dal[7:0];
end else if (!rrdy1) begin
rstb <= 1'b0;
end else if (!rstb) begin
rxrdy <= 1'b1;
end
if (gp_code == 8'o014) begin
rxrdy <= 1'b1;
rstb <= 1'b0;
end
end
assign ad = rstb ? rdata : 8'bz;
logic wxrdy;
logic wrdy1;
logic wrdy0;
logic [7:0] wdata;
always_ff@(negedge clk) begin
wrdy0 <= wrdy;
wrdy1 <= wrdy0;
end
always_ff@(negedge clk) begin
if (wrdy1) begin
wstb <= 1'b1;
end else if (wstb) begin
wdata <= ad;
wstb <= 1'b0;
wxrdy <= 1'b1;
end else if ((mdal == RBUF) && (!sctl_n)) begin
wxrdy <= 1'b0;
end
if (gp_code == 8'o014) begin
wxrdy <= 1'b0;
wstb <= 1'b0;
end
end
logic [15:0] dal_out;
logic [15:0] odt_out;
logic [15:0] mem_out;
assign dal = bufctl_n ? 16'bz : dal_out | odt_out | mem_out;
always_ff@(negedge bufctl_n) begin
if ((maio == DATA_READ) && (mbs == BS_EXT)) begin
if (mdal == RCSR) begin
odt_out <= {8'b0, wxrdy, 7'b0};
end
if (mdal == XCSR) begin
odt_out <= {8'b0, rxrdy, 7'b0};
end
if (mdal == RBUF) begin
odt_out <= wdata;
end
end else begin
odt_out <= 16'bz;
end
end
RAM の制御部です。
BS が メモリー(00)で、AIO が(x0xx)の時、ram_addr を確定します。
AIO が(10xx)の時、MISS をアサートし、読み出しサイクルを延長します。
SCTL がアサートの期間に DV を HIGH にし、読み出しデータが確定したとこを DCJ11 に通知します。
AIO が(00xx)の時、書き込み処理を行います。
ram u_ram(
.*
);
logic [21:0] ram_addr;
logic [15:0] ram_rdata;
logic [15:0] ram_wdata;
logic ram_read;
logic ram_write;
logic ram_byte;
always_ff@(posedge clk) begin
if ((mbs == BS_MEM) && (maio[2] == 1'b0)) begin
ram_addr <= mdal;
if (maio[3] == 1'b1) begin
miss_n <= (!ale_n && !bufctl_n) ? 1'b0 : 1'b1;
ram_read <= 1'b1;
mem_out <= ram_rdata;
dv <= !sctl_n;
end
end else begin
ram_read <= 1'b0;
mem_out <= 16'bz;
end
end
always_ff@(posedge clk) begin
if ((mbs == BS_MEM) && (maio[3:2] == 2'b00) && (!sctl_n)) begin
if (maio[1] == BYTE_WRITE) begin
ram_byte <= 1'b1;
end else begin
ram_byte <= 1'b0;
end;
ram_write <= 1'b1;
ram_wdata <= dal[15:0];
end else begin
ram_write <= 1'b0;
end
end
endmodule
`default_nettype wir
アドレス 000000 から、データを読み出す様子を観察してみます。
黄色マーカーの位置で、ram モジュールに読み出し要求を出しています。
赤マーカーの位置で、PSRAM の読み出しコマンドを発行しています。
白マーカーの位置で、最初の PSRAM データ読み出しが行われます。データ 000011 が読み出されています。
オレンジマーカーは、次の命令処理の開始位置です。
アドレス 00000 に、データ 000010 を書き込む様子を観察します。
白マーカー位置で、書き込み命令を判定します。
黄色マーカー位置で、ram モジュールに書き込み要求を出しています。
赤マーカー位置で、PSRAM の書き込みコマンドを発行しています。
オレンジマーカーは、次の命令の開始位置です。
参考文献
DCJ11 Microprocessor User's Guide, 3.5 BUS READ CYCLE, 1983
Gowin PSRAM Memory Interface HS IP User Guide