0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Tang Mega 138K ProのDDR3テスト

0
Last updated at Posted at 2025-12-30

Tang Primer 138K Pro DockにはDDR3 SDRAMが搭載されている.
SipeedのExample の中にddr_test というものがあり,DDR3 SDRAMが正常に動作するかどうかを確認できる.

Micron用 と skhynix用 のデザインが用意されているが,ボード本体を見てもどちらのデザインに対応しているかは分からない.両方動かしてみたところ,手元のボードではskhynix に対応しているようだった(ボード上のLEDで確認).

Gowin IDEでプロジェクトを開くと,5個の Verilog ソースコードが含まれている.

  • button.v
     ボタン入力の検知用.おそらくこのデザインでは使われていない…(なぜプロジェクトに入れた?)
  • ddr3_memory_interface
     GowinのDDR3 Controller IP(暗号化されている)
  • ddrtest.v
     DDR3メモリテスト用のコード
  • gowin_pll.v
     GowinのPLL IP
  • top.v
     トップ・モジュール

 このデザインを読み解くために必要なのは, ddrtest.v と top.v なので,コード中にコメントを入れたもの本稿に張り付ける.

サンプル・デザインの動作

 デザインの動作状態はボード上の6個のLEDで示される.
 DDR3の検証結果についてはLED3の点灯状態で示される(エラーなしを示す).LED3が点灯すれば正常である.筆者のボードでは Micronのデザインでは点灯しないので,点灯しない場合は,まずはもう一方のデザインを試した方がよさそう.

LED0が点灯すれば初期化完了.LED4は動作中には約1秒周期で点滅する.

 ビットストリームが書き込まれると,すぐにテストが動作するが,リセットしたい場合は
ボード上の S0 がリセットにアサインされているので,これを押す.

リファレンス

DDR3 コントローラIP

 GowinのDDR3 Memory Interface IPのドキュメント が参考になる.このドキュメントはSipeedの example の docs フォルダに含まれている(いいの?)が,日本語版も存在するので,Gowin公式サイトからたどるとよい(上記にリンクも張ったが,本来ログインしてから参照できるドキュメントだと思われ).

Verilogコード

topモジュール

module top(
    clk,
    rst_n,
    ddr_addr,
    ddr_bank,
    ddr_cs,
    ddr_ras,
    ddr_cas,
    ddr_we,
    ddr_ck,
    ddr_ck_n,
    ddr_cke,
    ddr_odt,
    ddr_reset_n,
    ddr_dm,
    ddr_dq,
    ddr_dqs,
    ddr_dqs_n,
    test_pt,
    state_led
);    
    input clk;
    output [15-1:0]             ddr_addr;       //ROW_WIDTH=15
    output [3-1:0]              ddr_bank;       //BANK_WIDTH=3
    output                      ddr_cs;
    output                      ddr_ras;
    output                      ddr_cas;
    output                      ddr_we;
    output                      ddr_ck;
    output                      ddr_ck_n;
    output                      ddr_cke;
    output                      ddr_odt;
    output                      ddr_reset_n;
    output [4-1:0]              ddr_dm;         //DM_WIDTH=2
    inout  [32-1:0]             ddr_dq;         //DQ_WIDTH=32
    inout  [4-1:0]              ddr_dqs;        //DQS_WIDTH=2
    inout  [4-1:0]              ddr_dqs_n;      //DQS_WIDTH=2
    input                       rst_n;
    output                      test_pt;

    output [5:0]                state_led;                 

    wire                        app_wdf_wren;
    wire  [32-1:0]              app_wdf_mask;    //APP_MASK_WIDTH=16
    wire                        app_wdf_end; 
    wire [256-1:0]              app_wdf_data;    //APP_DATA_WIDTH=256
    wire                        app_en;
    wire [2:0]                  app_cmd;
    wire [29-1:0]               app_addr;        //ADDR_WIDTH=29
    wire                        app_sre_req;
    wire                        app_ref_req;
    wire                        app_burst;
    wire                        app_sre_act;
    wire                        app_ref_ack;
    wire                        app_wdf_rdy;
    wire                        app_rdy;
    wire                        app_rd_data_valid; 
    wire                        app_rd_data_end;
    wire [256-1:0]              app_rd_data;     //APP_DATA_WIDTH=256
    
    

assign  test_pt = clk_x1;

assign state_led[5] = ~app_wdf_rdy;
assign state_led[4] = ~led;
assign state_led[3] = ~error;
assign state_led[2] = ~pll_stop;
assign state_led[1] = ~pll_lock; 
assign state_led[0] = ~init_calib_complete; //DDR3_init_indicator

wire clk;
wire pll_lock;
wire memory_clk;
wire err;
wire clk_x1;
wire clk50m;
wire init_calib_complete;

wire pll_stop;

reg led;

assign error = ~err;
//assign error1 = err;


/* LED点滅 */
reg [31:0] led_cnt;
always@(posedge clk_x1)begin // clk_x1 (DDR IPから出力されるクロック)
    if(led_cnt >= 50_000_000) begin
            led <= ~led;
            led_cnt <= 'd0;
    end
    else
            led_cnt <= led_cnt + 1'b1;
end


Gowin_PLL Gowin_PLL_inst(
.lock(pll_lock), 
.clkout0(), 
.clkout1(clk50m), 
.clkout2(memory_clk),
.clkin(clk), 
.reset(1'b0),
.enclk0(1'b1), //input enclk0
.enclk1(1'b1), //input enclk1
.enclk2(pll_stop) //input enclk2
);

/* テストベンチ */
ddr3_test1  #
    (
     .ADDR_WIDTH(29) ,          //ADDR_WIDTH=29
     .APP_DATA_WIDTH(256) ,     //APP_DATA_WIDTH=256
     .APP_MASK_WIDTH (32),      //APP_MASK_WIDTH=32
     .USER_REFRESH("OFF")
    )u_rd(
// テストベンチ入力
    .clk                (clk_x1),             // <- DDR IP
    .rst                (~rst_n),             // <- ボード
    .app_rdy            (app_rdy),            // <- DDR IP
    .app_rd_data_valid  (app_rd_data_valid),  // <- DDR IP 読み出しデータ有効
    .app_rd_data        (app_rd_data),        // <- DDR IP 読み出しデータ
    .init_calib_complete(init_calib_complete),// <- DDR IP IPの初期化完了
    .wr_data_rdy        (app_wdf_rdy),        // <- DDR IP データ受信可能

//出力
    .app_en             (app_en),
    .app_cmd            (app_cmd),
    .app_addr           (app_addr),           // -> DDR IP
    .app_wdf_data       (app_wdf_data),       // -> DDR IP 書き込みデータ
    .app_wdf_wren       (app_wdf_wren),
    .app_wdf_end        (app_wdf_end),
    .app_wdf_mask       (app_wdf_mask),
    .app_burst          (app_burst),
    .sr_req             (sr_req),
    .error              (err),                // -> board LED
    .ref_req            (ref_req)
    );

/* DDR3 IP */
//DDR3_Memory_Interface_Top u_ddr3 (
    D3_400 u_ddr3 (
    .memory_clk      (memory_clk),              // メモリ用クロック(入力)
    .pll_stop        (pll_stop),
    .clk             (clk),                     // リファレンスクロック(入力)
    .rst_n           (rst_n),                   //rst_n システムリセット(入力)
    .cmd_ready       (app_rdy),                 // コマンドおよびアドレスを受信可能(出力)
    .cmd             (app_cmd),                 // コマンド(入力) 1:read  0:write
    .cmd_en          (app_en),                  // アドレスおよびコマンド・イネーブル    1:有効(入力)
    .addr            (app_addr),                // アドレス入力  Rank + Bank + Row + Column
    .wr_data_rdy     (app_wdf_rdy),             // データ受信可能(出力)
    .wr_data         (app_wdf_data),            // 書き込みデータ
    .wr_data_en      (app_wdf_wren),            // 書き込みイネーブル(入力)
    .wr_data_end     (app_wdf_end),             // バースト転送の最終サイクルを示す    1:最終サイクル
    .wr_data_mask    (app_wdf_mask),            // 
    .rd_data         (app_rd_data),             // 読み出しデータ(出力)
    .rd_data_valid   (app_rd_data_valid),       // rd_data 有効(出力)
    .rd_data_end     (app_rd_data_end),         // 書き込みの最終サイクルであることを示す(入力)
    .sr_req          (1'b0),                    // セルフリフレッシュ要求(入力)
    .ref_req         (1'b0),                    // ユーザーリフレッシュ要求(入力)
    //.zq_req          (1'b0),
    .sr_ack          (app_sre_act),             // セルフリフレッシュ応答(出力)
    .ref_ack         (app_ref_ack),             // ユーザーリフレッシュ応答(出力)
    .init_calib_complete(init_calib_complete),  // キャリブレーション完了(出力)
    `ifdef DEBUG_PORT_ENABLE
    .dbector4_out            (),
    .dbg_vector3_out         (),
    .dbg_vector2_out         (), 
    .dbg_vector1_out         (), 
    `endif
    .clk_out         (clk_x1),        // ユーザデザインのクロック(出力)
    .pll_lock        (pll_lock),      // PLLロック(入力) 使わない場合は1
    //.pll_lock        (1'b1), 
    //`ifdef ECC
    //.ecc_err         (ecc_err),
    //`endif
    .burst           (app_burst),    // OTF制御ポート  1:BL8モード,  0:BC4モード. OTFモードでのみ有効 
    // mem interface メモリ・インターフェース
    .ddr_rst         (ddr_rst),        // IP内で使われるグローバルリセット,ユーザ回路にも出力
    .O_ddr_addr      (ddr_addr),       // Rowアドレス(アクティブコマンド)、Columnアドレス(読み出し、書き込みコマンド) 
    .O_ddr_ba        (ddr_bank),       // Bankアドレス
    .O_ddr_cs_n      (ddr_cs),         // チップセレクト信号、アクティブLow 
    .O_ddr_ras_n     (ddr_ras),
    .O_ddr_cas_n     (ddr_cas),
    .O_ddr_we_n      (ddr_we),
    .O_ddr_clk       (ddr_ck),
    .O_ddr_clk_n     (ddr_ck_n),
    .O_ddr_cke       (ddr_cke),
    .O_ddr_odt       (ddr_odt),
    .O_ddr_reset_n   (ddr_reset_n),     // _DDR3 SDRAMリセット信号
    .O_ddr_dqm       (ddr_dm),
    .IO_ddr_dq       (ddr_dq),
    .IO_ddr_dqs      (ddr_dqs),
    .IO_ddr_dqs_n    (ddr_dqs_n)
);
endmodule

ddr3_testモジュール



`timescale 1ps/1ps
//////////////////////////////////////////////////////////////////////////////////
// Create Date: 2016/07/27 10:58:47
// Module Name: user_test
// Revision 0.01 - File Created
//////////////////////////////////////////////////////////////////////////////////

module ddr3_test1 #(
    parameter ADDR_WIDTH = 28,
    parameter APP_DATA_WIDTH = 256,
    parameter APP_MASK_WIDTH = 32,
    parameter USER_REFRESH = "OFF"
    )
    (
    //input
    clk, 
    rst, 
    app_rdy, 
    app_rd_data_valid, 
    app_rd_data, 
    init_calib_complete,
    wr_data_rdy,
    //output
    app_en,
    app_cmd, 
    app_addr, 
    app_wdf_data, 
    app_wdf_wren,
    app_wdf_end, 
    app_wdf_mask, 
    app_burst,
    sr_req, 
    ref_req,
    error
    
    );

    input clk;
    input rst;
    input app_rdy;
    input app_rd_data_valid;
    input wr_data_rdy;
    input [APP_DATA_WIDTH-1:0] app_rd_data;        // <- DDRR3 IP 読み出しデータ
    input init_calib_complete;

    output reg           app_en;
    output reg     [2:0] app_cmd;
    output reg     [ADDR_WIDTH-1:0] app_addr ;    // -> DDR3 IP
    output reg     [APP_DATA_WIDTH-1:0] app_wdf_data ;
    output reg     app_wdf_wren;                  // -> DDR3 IP 書き込みイネーブル
    output     app_wdf_end;
    output [APP_MASK_WIDTH-1:0] app_wdf_mask ;
    output app_burst;
    output sr_req;
    output ref_req; 
    output error;

    reg [15:0] error_int1;
    
	    reg app_rd_data_valid_r;
    reg [APP_DATA_WIDTH-1:0] app_rd_data_r/* synthesis syn_preserve = 1 */;
    reg app_rd_data_valid_rr;
    reg [APP_DATA_WIDTH-1:0] app_rd_data_rr/* synthesis syn_preserve = 1 */;

/* 読み出しデータ FF 2段で受ける */
    always@(posedge clk or posedge rst)begin
        if(rst)begin
            app_rd_data_valid_r <= 1'b0;
            app_rd_data_r <= 'd0;
            app_rd_data_valid_rr <= 1'b0;
            app_rd_data_rr <= 'd0;
        end
        else begin
            app_rd_data_valid_r <= app_rd_data_valid;
            app_rd_data_r <= app_rd_data;
            app_rd_data_valid_rr <= app_rd_data_valid_r;
            app_rd_data_rr <= app_rd_data_r;
        end
    end

    assign app_wdf_mask = 0;
    assign sr_req = 0;
    assign ref_req = 0;
    assign app_burst = 0;
	
	wire [63:0] EYE_MEM [0:7];
/* 書き込みデータ群 */	
	assign	EYE_MEM[0] = 64'h5883adb4c88ad596;
	assign	EYE_MEM[1] = 64'h1122334455667788;
	assign	EYE_MEM[2] = 64'h99aabbccddeeff00;
	assign	EYE_MEM[3] = 64'h0000ffff0000ffff;
	assign  EYE_MEM[4] = 64'hffff0000ffff0000;
	assign  EYE_MEM[5] = 64'h00000000ffff0000;
	assign  EYE_MEM[6] = 64'haf5d632fc8b91658;
	assign  EYE_MEM[7] = 64'hffffffff0000ffff;

	wire [63:0] EYE_MEM_C [0:7];

/* 検証 比較用データ群 */	
	assign	EYE_MEM_C[0] = 64'h5883adb4c88ad596;
//	assign	EYE_MEM_C[0] = 64'h4883adb4c88ad596;
	assign	EYE_MEM_C[1] = 64'h1122334455667788;
	assign	EYE_MEM_C[2] = 64'h99aabbccddeeff00;
	assign	EYE_MEM_C[3] = 64'h0000ffff0000ffff;
	assign  EYE_MEM_C[4] = 64'hffff0000ffff0000;
	assign  EYE_MEM_C[5] = 64'h00000000ffff0000;
	assign  EYE_MEM_C[6] = 64'haf5d632fc8b91658;
	assign  EYE_MEM_C[7] = 64'hffffffff0000ffff;

    reg [63:0] comp_data;

    localparam IDLE                     =   7'b0000001;
    localparam WR_BANK_CH               =   7'b0000010;//BANK0~7,ROW0,COL0
    localparam RD_BANK_CH               =   7'b0000100;
    localparam WR_ROW_CH                =   7'b0001000;//BANK0,ROW0~16384,COL0
    localparam RD_ROW_CH                =   7'b0010000;
    localparam WR_COL_CH                =   7'b0100000;//BANK0,ROW0,COL0~1024
    localparam RD_COL_CH                =   7'b1000000;

    reg [6:0] c_s;
    reg [6:0] n_s;
    reg [2:0] bank;
    reg [13:0] row;
    reg [9:0] col;
	
	reg [2:0] cnt_r;
	
    reg [2:0] cnt1;    // bank データ選択カウンタ
    reg [13:0] cnt2;   // row データ選択カウンタ 0~16384
    reg [6:0] cnt3;    // col データ選択カウンタ 0~1024

    always@(posedge clk or posedge rst)begin
        if(rst)
            c_s <= IDLE;
        else
            c_s <= n_s;
    end

/* テスト項目 順次切り替え ステートマシン */
   always@(*)begin
        case(c_s)
            IDLE                 :begin
                if(init_calib_complete)
                    n_s = WR_BANK_CH;
                else
                    n_s = IDLE;
            end
            WR_BANK_CH           :begin //BANK0~7,ROW0,COL0
                if((app_rdy & wr_data_rdy) & (&cnt1))
                    n_s = RD_BANK_CH;
                else
                    n_s = WR_BANK_CH;
            end 
            RD_BANK_CH           :begin
                if(app_rdy & (&cnt1))
                    n_s = WR_ROW_CH;
//                    n_s = IDLE;
                else
                    n_s = RD_BANK_CH;
            end 
            WR_ROW_CH            :begin
                if((app_rdy & wr_data_rdy) & (&cnt2))
                    n_s = RD_ROW_CH;
                else
                    n_s = WR_ROW_CH;
            end 
            RD_ROW_CH            :begin
                if(app_rdy & (&cnt2))
                    n_s = WR_COL_CH;
                else
                    n_s = RD_ROW_CH;
            end 
            WR_COL_CH            :begin
                if((app_rdy & wr_data_rdy) & (&cnt3))
                    n_s = RD_COL_CH;
                else
                    n_s = WR_COL_CH;
            end 
            RD_COL_CH            :begin
                if(app_rdy & (&cnt3))
                    n_s = IDLE;
                else
                    n_s = RD_COL_CH;
            end 
 
            default:n_s = IDLE;
        endcase
    end
	
	//assign app_en = (c_s == WR_BANK_CH | c_s == WR_ROW_CH | c_s == WR_COL_CH) ?  (app_rdy & wr_data_rdy) : 
	//				(c_s == RD_BANK_CH | c_s == RD_ROW_CH | c_s == RD_COL_CH) ? app_rdy : 1'b0;
    always@(posedge clk or posedge rst)
        if(rst)
            app_en <= 1'b0;
        else if((c_s == WR_BANK_CH | c_s == WR_ROW_CH | c_s == WR_COL_CH) & app_rdy & wr_data_rdy)
            app_en <= 1'b1;
        else if((c_s == RD_BANK_CH | c_s == RD_ROW_CH | c_s == RD_COL_CH) & app_rdy)
            app_en <= 1'b1;
        else
            app_en <= 1'b0;

	//assign app_cmd = (c_s == WR_BANK_CH | c_s == WR_ROW_CH | c_s == WR_COL_CH) ? 3'b000 : 3'b001;
/* 読み書き信号切り替え */
    always@(posedge clk or posedge rst)
        if(rst)
            app_cmd <= 3'b000;
        else if(c_s == WR_BANK_CH | c_s == WR_ROW_CH | c_s == WR_COL_CH)
            app_cmd <= 3'b000;
        else
            app_cmd <= 3'b001;
	
	//assign app_wdf_wren = (c_s == WR_BANK_CH | c_s == WR_ROW_CH | c_s == WR_COL_CH) ?  (app_rdy & wr_data_rdy) : 1'b0;
/* 書き込みイネーブル信号 */
    always@(posedge clk or posedge rst)
        if(rst)
            app_wdf_wren <= 1'b0;
        else if((c_s == WR_BANK_CH | c_s == WR_ROW_CH | c_s == WR_COL_CH) & app_rdy & wr_data_rdy)
            app_wdf_wren <= 1'b1;
        else
            app_wdf_wren <= 1'b0;
	assign app_wdf_end = app_wdf_wren;
	
/* bank  カウンタ インクリメント */	
	always@(posedge clk or posedge rst)begin
		if(rst)
			cnt1 <= 'd0;
		else if((c_s == WR_BANK_CH & app_rdy & wr_data_rdy) | (c_s == RD_BANK_CH & app_rdy))begin
            if(&cnt1)
                cnt1 <= 'd0;
            else
                cnt1 <= cnt1 + 1'b1;
		end
	end

/* row カウンタ インクリメント */
	always@(posedge clk or posedge rst)begin
		if(rst)
			cnt2 <= 'd0;
		else if((c_s == WR_ROW_CH & app_rdy & wr_data_rdy) | (c_s == RD_ROW_CH & app_rdy))begin
            if(&cnt2)
                cnt2 <= 'd0;
            else
                cnt2 <= cnt2 + 1'b1;
		end
	end

/* col カウンタ インクリメント */
    always@(posedge clk or posedge rst)begin
		if(rst)
			cnt3 <= 'd0;
		else if((c_s == WR_COL_CH & app_rdy & wr_data_rdy) | (c_s == RD_COL_CH & app_rdy))begin
            if(&cnt3)
                cnt3 <= 'd0;
            else
                cnt3 <= cnt3 + 1'b1;
		end
	end

/* 書き込みアドレス選択 */
	//assign app_addr = {1'b0,bank,row,col};
    always@(posedge clk or posedge rst)
        if(rst)
            app_addr <= 'd0;
        else
            app_addr <= {1'b0,bank,row,col};

/* アドレスインクリメント */
    always@(posedge clk or posedge rst)begin
        if(rst)begin
            bank <= 3'd0;
            row <= 14'd0;
            col <= 10'd0;
        end
        else begin
            case(c_s)
            IDLE                 :begin
                bank <= 3'd0;
                row <= 14'd0;
                col <= 10'd0;
            end
            
            WR_BANK_CH           :begin //BANK0~7,ROW0,COL0
                if(app_rdy & wr_data_rdy)begin
                    if(&cnt1)
                        bank <= 'd0;
                    else 
                        bank <= bank + 1'b1;
                end
            end 
            RD_BANK_CH           :begin
                if(app_rdy)begin
                    if(&cnt1)
                        bank <= 'd0;
                    else 
                        bank <= bank + 1'b1;
                end
            end 
            
            WR_ROW_CH            :begin
                if(app_rdy & wr_data_rdy)begin
                    if(&cnt2)
                        row <= 'd0;
                    else
                        row <= row + 1'b1;
                end
            end 
            RD_ROW_CH            :begin
                if(app_rdy)begin
                    if(&cnt2)
                        row <= 'd0;
                    else
                        row <= row + 1'b1;
                end
            end 
            WR_COL_CH            :begin
                if(app_rdy & wr_data_rdy)begin
					if(&cnt3)
						col <= 'd0;
					else
						col <= col + 4'd8;
				end
            end 
            RD_COL_CH            :begin
                if(app_rdy)begin
					if(&cnt3)
						col <= 'd0;
					else
						col <= col + 4'd8;
				end
            end 
            
            default:;
            endcase
        end
    end

/* 書き込みデータ 組み立て */
    always@(posedge clk or posedge rst)
        if(rst)
            app_wdf_data <= 'd0;
        else if(c_s == WR_BANK_CH)
            app_wdf_data <= {EYE_MEM[cnt1],EYE_MEM[cnt1],EYE_MEM[cnt1],EYE_MEM[cnt1]};
        else if(c_s == WR_ROW_CH)
            app_wdf_data <= {EYE_MEM[cnt2[2:0]],EYE_MEM[cnt2[2:0]],EYE_MEM[cnt2[2:0]],EYE_MEM[cnt2[2:0]]};
        else if(c_s == WR_COL_CH)
            app_wdf_data <= {EYE_MEM[cnt3[2:0]],EYE_MEM[cnt3[2:0]],EYE_MEM[cnt3[2:0]],EYE_MEM[cnt3[2:0]]};
        else
            app_wdf_data <= 'd0;

    
    always@(posedge clk or posedge rst)begin
		if(rst)
			cnt_r <= 'd0;
		else if(app_rd_data_valid_r)
			cnt_r <= cnt_r + 1'b1;
	end

/* 比較データ読み出し */
    always@(posedge clk or posedge rst)begin
        if(rst)
            comp_data <= 'd0;
        else
            comp_data <= EYE_MEM_C[cnt_r];
    end
 
 /* データ比較 */
    generate
    genvar uei,uej;
        for(uei=0;uei<4;uei=uei+1)begin:user_err_gen1
            for(uej=0;uej<4;uej=uej+1)begin:user_err_gen2
            always@(posedge clk or posedge rst)begin
                if(rst)
                    error_int1[uei*4+uej] <= 1'b0;
                else if(app_rd_data_valid_rr & app_rd_data_rr[(uei*64+uej*16)+:16] != comp_data[uej*16+:16])
                    error_int1[uei*4+uej] <= 1'b1;
//                else
//                    error_int1[uei*4+uej] <= 1'b0;
            end
            end
        end
    endgenerate

	assign error = |error_int1;
endmodule

(1)
https://wiki.sipeed.com/hardware/en/tang/tang-mega-138k/mega-138k-pro.html
(2)Tang Mege 138K Pro Dockを味見
https://fpga.tokyo/138k-2/
(3)Gowin DDR3 Memory Interface
https://www.gowinsemi.com/ja/support/ip_detail/14/

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?