見出し画像

A2PDP11 (14) バスサイクルの調整

メモリ読み出し時の、バスサイクル延長を修正し、8 サイクルで完了するように修正します。

バスサイクルの延長は、T4 の立ち下がり時に CONT をアサートすることで終了します。

バス読み出しサイクル

元の回路では、PDP-11/HACK を参考に、SCTL と CONT を直結しているので、CONT がアサートされるタイミングは、1 回目の T4 の立ち下がり時に間に合いません。そのため、T4 が 2 サイクル分追加されます。
下図の、赤マーカーが T4 の立ち上がり、白マーカー部が CONT が検出される T4 の立ち下がりです。

メモリリードサイクル(修正前)

CONT を GND に接続し、常にアサート状態にします。

Tang Nano 9K 接続回路(CONT 常時アサート)

このままでは、メモリ読み出しが追いつかないので、メモリクロックを 165 MHz に変更します。

PSRAM 用メモリクロック
PSRAM IP

DAL HI/LO 切り替え用のクロックを、36MHz から 54MHz にします。

DAL 切り替えクロック

ram.sv を修正します。

`default_nettype none
// DCJ11 TangNano interface by nanja.info
// PSRAM interface module
// TEST8 2024.08.31 4MB RAM
// TEST9 2024.09.03 Byte Data Write
// TEST10 2024.09.13 Add rst_n and init interface
// TEST11 2024.09.20 Modify read timing

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,
    input wire rst_n,
    output wire init
);

assign init = init_calib0;      // for debug

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 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
);

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

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

logic [1:0] rcycle;
always_ff@(negedge clk_out) begin
    if (mcycle == 1) begin
        rcycle <= 0;
    end else if (rd_data_valid0) begin
        if (rcycle == 1'b0) begin
            ram_rdata <= rd_data0[31:16];
        end
        rcycle <= rcycle + 1'b1;
    end
end

endmodule

`default_nettype wire

top.sv を変更します。

`default_nettype none
// DCJ11 TangNano interface by nanja.info
// TEST2 2024.07.28 Bus read
// TSET3 2024.08.03 Start-Up config
// 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
// TEST9 2024.09.03 Byte Data Write
// TEST10 2024.09.13 Paper Tape Reader/Punch dummy response
// TEST11 2024.09.21 Modify read timing

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,
    input wire rst_n,
    output wire led1
);

// 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 REQUEST_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

// PC11 Paper Tape Reader/Punch
parameter PC11          = 19'o1777755;  // PC11 registers
parameter PRS           = 22'o17777550; // Paper Tape Reader Status Register
parameter PRB           = 22'o17777552; // Paper Tape Reader Buffer Register
parameter PPS           = 22'o17777554; // Paper Tape Punch Status Register
parameter PPB           = 22'o17777556; // Paper Tape Punch Buffer Register

parameter HIMEM         = 22'o17757777; // End of RAM

logic sclk;
Gowin_OSC osc(
    .oscout(sclk) //output oscout
);

logic clk_x3;   // clk x 3 = 54MHz
Gowin_rPLL rpll(
    .clkout(clk_x3), //output clkout
    .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_x3) begin
    if (ale_n) begin
        count <= 0;
    end else begin
        if (count == 8'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 == 8'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

assign nxm_n = sctl_n ? 1'b1 :
    ((maio[2] == 0) && (mbs == BS_MEM) && (mdal > HIMEM)) ? 1'b0 :
    ((maio[2] == 0) && (mbs == BS_EXT) && ((mdal[21:3] != DLART) && (mdal[21:3] != PC11))) ? 1'b0 :
    1'b1;

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

assign dal = bufctl_n ? 16'bz : 
    (mdal == RCSR) ? {8'b0, wxrdy, 7'b0} :
    (mdal == XCSR) ? {8'b0, rxrdy, 7'b0} :
    (mdal == RBUF) ? wdata :
    (mdal == PRS) ? 16'b1000_0000_0000_0000 :
    (mdal == PRB) ? 16'b0 :
    (mdal == PPS) ? 16'b0000_0000_1000_0000 :
    (gp_code == POWER_UP0) ? 16'b0000000_0_0000_0_01_1 :
    (gp_code == POWER_UP2) ? 16'b0000000_0_0000_0_01_1 :
    (mdal <= HIMEM) ? ram_rdata : 16'bz;

logic init;
assign led1 = init;
ram u_ram(
    .*
);

assign dv = 1'b1;
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_x3) begin
    if ((mbs == BS_MEM) && (count == 2)) begin
        ram_addr <= mdal;
        if ((maio[3:2] == 2'b10) || (maio == REQUEST_READ)) begin
            miss_n <= 1'b0;
            ram_read <= 1'b1;
        end
    end else if (count == 0) begin
        miss_n <= 1'b1;
        ram_read <= 1'b0;
    end
end

always_ff@(posedge clk) begin
    if ((mbs == BS_MEM) && (maio[3:2] == 2'b00) && (!sctl_n)) begin
        if (maio == BYTE_WRITE) begin
            ram_byte <= 1'b1;
        end
        ram_write <= 1'b1;
        ram_wdata <= dal[15:0];
    end else begin
        ram_write <= 1'b0;
        ram_byte <= 1'b0;
    end
end

endmodule

`default_nettype wire

メモリ読み出し時の信号を確認します。
下図、左端の赤マーカーがクロック T0、白マーカーがクロック T4、オレンジマーカーが次の T0 です。8 クロックで読み出しが完了しているのが分かります。

メモリ読み出しクロックサイクル

ASCIIART の実行は、2 割弱改善し、11分38秒になりました。

参考文献

DCJ11 Microprocessor User's Guide, 3.5 BUS READ CYCLE, 1983


この記事が気に入ったらサポートをしてみませんか?