Skip to content

Instantly share code, notes, and snippets.

@kazuokada
Last active March 19, 2023 14:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kazuokada/e3fa7f3ec82dd69b9c1f555688f5f917 to your computer and use it in GitHub Desktop.
Save kazuokada/e3fa7f3ec82dd69b9c1f555688f5f917 to your computer and use it in GitHub Desktop.
wishbone→PSRAM interface bridge
`timescale 1ns/1ps
// wishbone → PSRAM バスブリッジ
// 64burst(64byte) 転送
// data幅 32bit
module brd_wb2ps (
input RST,
input cpuclk, // wishbone clk
// wishbone
// reg i/f
// 不要?
// Tcmd間隔はHDMI側にも必要なので共通regにする方がよいのでは?
//input wire [11:0] reg_mem_addr,
//input wire [31:0] reg_mem_wdata,
//output reg [31:0] reg_mem_rdata,
//input wire [3:0] reg_mem_wstrb,
//input wire reg_mem_valid,
//output wire reg_mem_ready,
// PSRAM 32Mbit x 2
// cpuclk domain
input wire [20:0] ps_mem_addr,
input wire [31:0] ps_mem_wdata,
output reg [31:0] ps_mem_rdata,
input wire [3:0] ps_mem_wstrb,
input wire ps_mem_valid,
output wire ps_mem_ready,
// PSRAM i/f
// psramclk domain
input wire half_psramclk, // 83MHz clk
output reg cmd0, //input cmd0
output reg cmd_en0, //input cmd_en0
output reg [20:0] addr0,
output wire [31:0] wr_data0,
input wire [31:0] rd_data0,
input wire rd_data_valid0,
output wire [3:0] data_mask0,
// PSRAM parameter
input [5:0] tcmd // cmd間隔 64burst = 26
);
wire psramclk = half_psramclk;
wire WSHRST;
wire PSRAMRST;
reg RST_cpuclk_sync1;
reg RST_cpuclk_sync2;
reg RST_psramclk_sync1;
reg RST_psramclk_sync2;
reg ready_high;
wire psmem_bst_end_cpuclk_1shot;
wire start_cputrans;
reg run_cputrans;
reg cpucmd_assert;
reg cpucmd_assert_sync1; // psramclk
reg cpucmd_assert_sync2;
reg cpucmd_assert_sync3;
wire cpucmd_assert_rise_psramclk;
reg cpucmd_assert_rise_detect;
reg cpucmd_assert_sync1_cpuclk; // cpuclk
reg cpucmd_assert_sync2_cpuclk;
reg [3:0] psram_rbst_cnt; // psramclk
reg [3:0] psram_wbst_cnt; // psramclk
reg [4:0] cmd_interval_timer_memclk;
reg cmd_interval_ok;
reg wait_rd_valid; // psramclk, read cmd発行からrd_data_valid受けつけまで
reg psmem_bst_end; // psramclk
reg psmem_bst_end_sync1; // cpuclk
reg psmem_bst_end_sync2;
reg psmem_bst_end_sync3;
reg clr_psmem_bst_end_sync1; // psramclk
reg clr_psmem_bst_end_sync2; // psramclk
reg clr_psmem_bst_end_sync3; // psramclk
reg [20:0] ps_mem_addr_psramclk;
reg [31:0] ps_mem_data_psramclk;
reg [3:0] ps_mem_wstrb_psramclk;
reg [31:0] psram_data_fifo[0:15]; // 64byte
wire RHIT; // read cache hit
reg RVAL; // read cache valid
reg [20:6] read_cache_addr; // read cache addr
// ---------------------------------
// 各種リセット同期化
// ---------------------------------
always@(posedge cpuclk or posedge RST)
if(RST) begin
RST_cpuclk_sync1 <= 1'b1;
RST_cpuclk_sync2 <= 1'b1;
end
else begin
RST_cpuclk_sync1 <= RST;
RST_cpuclk_sync2 <= RST_cpuclk_sync1;
end
assign WSHRST = RST_cpuclk_sync2;
always@(posedge psramclk or posedge RST)
if(RST) begin
RST_psramclk_sync1 <= 1'b1;
RST_psramclk_sync2 <= 1'b1;
end
else begin
RST_psramclk_sync1 <= RST;
RST_psramclk_sync2 <= RST_psramclk_sync1;
end
assign PSRAMRST = RST_psramclk_sync2;
// ---------------------------------
// ps_mem_ready
// ---------------------------------
assign ps_mem_ready = ready_high;
always@(posedge cpuclk or posedge WSHRST)
if(WSHRST)
ready_high <= 1'b0;
else if (ready_high)
ready_high <= 1'b0;
else if (psmem_bst_end_cpuclk_1shot | RHIT)
ready_high <= 1'b1;
// ---------------------------------
// ps_mem_rdata
// ---------------------------------
always@(posedge cpuclk)
if(RHIT|psmem_bst_end_cpuclk_1shot) begin
ps_mem_rdata <= psram_data_fifo[ps_mem_addr[5:2]];
end
// ---------------------------------
// RHIT
// cache read hit
// ---------------------------------
assign RHIT = start_cputrans & RVAL &
(ps_mem_wstrb==4'h0) &
(read_cache_addr[20:6]== ps_mem_addr[20:6]);
// ---------------------------------
// run_cputrans (transcation中)
// start_cputrans (transcation開始パルス)
// ---------------------------------
always@(posedge cpuclk or posedge WSHRST)
if(WSHRST)
run_cputrans <= 1'b0;
else
run_cputrans <= ( ~ps_mem_ready & ps_mem_valid);
assign start_cputrans = ps_mem_valid & (~run_cputrans);
// ---------------------------------
// cpucmd_assert
// ---------------------------------
always@(posedge cpuclk or posedge WSHRST)
if(WSHRST)
cpucmd_assert <= 1'b0;
else if(start_cputrans & ~RHIT)
cpucmd_assert <= 1'b1;
else if(cpucmd_assert_sync2_cpuclk)
cpucmd_assert <= 1'b0;
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST) begin
cpucmd_assert_sync1 <= 1'b0;
cpucmd_assert_sync2 <= 1'b0;
cpucmd_assert_sync3 <= 1'b0;
end
else begin
cpucmd_assert_sync1 <= cpucmd_assert;
cpucmd_assert_sync2 <= cpucmd_assert_sync1;
cpucmd_assert_sync3 <= cpucmd_assert_sync2;
end
assign cpucmd_assert_rise_psramclk = cpucmd_assert_sync2&(~cpucmd_assert_sync3);
always@(posedge cpuclk or posedge WSHRST)
if(WSHRST) begin
cpucmd_assert_sync1_cpuclk <= 1'b0;
cpucmd_assert_sync2_cpuclk <= 1'b0;
end
else begin
cpucmd_assert_sync1_cpuclk <= cpucmd_assert_sync2;
cpucmd_assert_sync2_cpuclk <= cpucmd_assert_sync1_cpuclk;
end
// ---------------------------------
// 64byte 単面キャッシュ
// ---------------------------------
always@(posedge cpuclk or posedge WSHRST)
if(WSHRST)
RVAL <= 1'b0;
else if(start_cputrans) begin
// read cacheのアドレスと今回のwrite要求アドレスが一致ならvalidを破棄
if( (|ps_mem_wstrb)&
(RVAL & (read_cache_addr[20:6]== ps_mem_addr[20:6])) )
RVAL <= 1'b0;
else if(ps_mem_wstrb==0)
RVAL <= 1'b1;
else
RVAL <= 1'b0;
end
always@(posedge cpuclk)
if(ps_mem_wstrb==4'h0)
read_cache_addr[20:6] <= ps_mem_addr[20:6];
// ---------------------------------
// cpucmd_assert_rise_detect // psramclk
// cpucmd_assert riseエッジ検出(psramclk)
// ---------------------------------
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
cpucmd_assert_rise_detect <= 1'b0;
else if(cmd_en0)
cpucmd_assert_rise_detect <= 1'b0;
else if(cpucmd_assert_rise_psramclk)
cpucmd_assert_rise_detect <= 1'b1;
// ---------------------------------
// 一旦CPU I/F信号をラッチ
// ---------------------------------
always@(posedge psramclk)
if(cpucmd_assert_rise_psramclk) begin
ps_mem_addr_psramclk <= ps_mem_addr;
ps_mem_data_psramclk <= ps_mem_wdata;
ps_mem_wstrb_psramclk <= ps_mem_wstrb;
end
// ---------------------------------
// PSRAM I/F
// ---------------------------------
always@(posedge psramclk)
if(cpucmd_assert_rise_detect & cmd_interval_ok)
cmd0 <= |ps_mem_wstrb_psramclk; // r:0 , w:1
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
cmd_en0 <= 1'b0;
else if(cmd_en0)
cmd_en0 <= 1'b0;
else if(cpucmd_assert_rise_detect & cmd_interval_ok)
cmd_en0 <= 1'b1;
assign data_mask0 = (ps_mem_addr_psramclk[5:2] == psram_wbst_cnt) ?
(~ps_mem_wstrb_psramclk) : 4'hf;
always@(posedge psramclk)
if(cpucmd_assert_rise_detect & cmd_interval_ok)
addr0 <= {ps_mem_addr_psramclk[20:6],6'h00}; // 64byteバウンダリ
assign wr_data0 = ps_mem_data_psramclk;
always@(posedge psramclk)
if(rd_data_valid0) begin
//$write("psram_data_fifo[%d]=%h\n",psram_rbst_cnt,rd_data0);
psram_data_fifo[psram_rbst_cnt] <= rd_data0;
end
// ---------------------------------
// psram_bst_cnt
// (PSRAM burst counter)
// ---------------------------------
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
psram_wbst_cnt <= 4'h0;
else if(cpucmd_assert_rise_psramclk)
psram_wbst_cnt <= 4'h0;
else if(cmd_en0&cmd0) // write時
psram_wbst_cnt <= 4'h1;
//else if(wait_rd_valid & rd_data_valid0) // read
// psram_bst_cnt <= 4'h1;
else if(psram_wbst_cnt != 4'h0)
psram_wbst_cnt <= psram_wbst_cnt + 4'h1;
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
psram_rbst_cnt <= 4'h0;
else if(cpucmd_assert_rise_psramclk)
psram_rbst_cnt <= 4'h0;
else if(wait_rd_valid & rd_data_valid0) // read
psram_rbst_cnt <= 4'h1;
else if((psram_rbst_cnt != 4'h0)&rd_data_valid0)
psram_rbst_cnt <= psram_rbst_cnt + 4'h1;
// ---------------------------------
// wait_rd_valid
// (read cmd発行からrd_data_valid受けつけまで)
// ---------------------------------
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
wait_rd_valid <= 1'b0;
else if(cmd_en0&(~cmd0))
wait_rd_valid <= 1'b1;
else if(rd_data_valid0)
wait_rd_valid <= 1'b0;
// ---------------------------------
// psmem_bst_end
// ---------------------------------
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
psmem_bst_end <= 1'b0;
else if( (psram_wbst_cnt==4'hf)|((psram_rbst_cnt==4'hf)&rd_data_valid0) )
psmem_bst_end <= 1'b1;
else if(clr_psmem_bst_end_sync2&(~clr_psmem_bst_end_sync3))
psmem_bst_end <= 1'b0;
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST) begin
clr_psmem_bst_end_sync1 <= 1'b0;
clr_psmem_bst_end_sync2 <= 1'b0;
clr_psmem_bst_end_sync3 <= 1'b0;
end
else begin
clr_psmem_bst_end_sync1 <= psmem_bst_end_sync2;
clr_psmem_bst_end_sync2 <= clr_psmem_bst_end_sync1;
clr_psmem_bst_end_sync3 <= clr_psmem_bst_end_sync3;
end
// ---------------------------------
// cmd_interval_timer_memclk
// ---------------------------------
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
cmd_interval_timer_memclk <= 5'h00;
else if(cpucmd_assert_rise_psramclk)
cmd_interval_timer_memclk <= 5'h00;
else if(cmd_en0)
cmd_interval_timer_memclk <= 5'h01;
else if(cmd_interval_timer_memclk != 5'h00) begin
if(cmd_interval_timer_memclk == (tcmd-5'h03))
cmd_interval_timer_memclk <= 5'h00;
else
cmd_interval_timer_memclk <= cmd_interval_timer_memclk + 5'h01;
end
// ---------------------------------
// cmd_interval_ok
// ---------------------------------
always@(posedge psramclk or posedge PSRAMRST)
if(PSRAMRST)
cmd_interval_ok <= 1'b0;
else
cmd_interval_ok <= (cmd_interval_timer_memclk==5'h00);
// ---------------------------------
// psmem_bst_end_sync1/2/3
// psmem_bst_endをcpuclkで同期化
// ---------------------------------
always@(posedge cpuclk or posedge WSHRST)
if(WSHRST) begin
psmem_bst_end_sync1 <= 1'b0;
psmem_bst_end_sync2 <= 1'b0;
psmem_bst_end_sync3 <= 1'b0;
end
else begin
psmem_bst_end_sync1 <= psmem_bst_end;
psmem_bst_end_sync2 <= psmem_bst_end_sync1;
psmem_bst_end_sync3 <= psmem_bst_end_sync2;
end
assign psmem_bst_end_cpuclk_1shot =
psmem_bst_end_sync2 & (~psmem_bst_end_sync3);
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment