![見出し画像](https://assets.st-note.com/production/uploads/images/163091362/rectangle_large_type_2_b22afade821d1f0bd4595d18197c73f1.jpeg?width=1200)
A2PDP11 (16) コンソール ODT
Apple II をコンソールとして使い、ODT で DCJ11 を制御できるようにします。
Apple II 側ソフトウェア
Apple II 側のソフトウェアは、cc65 で書きました。Apple2BuildPipeline を使うと Xcode 上で、Apple II のソフトウェアを開発することができます。
/*
* main.c
* a2odt
*
* Created by ushicow on 2024/11/24.
* Copyright (c) 2024 nanja.info All rights reserved.
*
*/
// TEST18
#include <stdio.h>
#include <conio.h>
#include <peekpoke.h>
#include <stdint.h>
#define SLOT 7
#define RCSR (0xc080 + SLOT * 16)
#define RBUF (0xc081 + SLOT * 16)
#define XCSR (0xc082 + SLOT * 16)
#define XBUF (0xc083 + SLOT * 16)
int main(void)
{
uint8_t rdata;
uint8_t wdata = 0;
printf("Serial Start\n");
POKE(XCSR, 0);
while (1) {
if (PEEK(XCSR) >= 128) { // xstb == 1
POKE(XCSR, 0); // xrdy <= 0
rdata = PEEK(XBUF);
putchar(rdata);
} else if (PEEK(RCSR) >= 128) { // rstb == 1
POKE(RBUF, wdata);
POKE(RCSR, 0); // rrdy <= 0
} else if (kbhit()) {
wdata = cgetc();
if (wdata == 24) { // control-X
return(0);
}
POKE(RCSR, 128); // rrdy <= 1
} else {
POKE(XCSR, 128); // xrdy <= 1
}
}
return 0;
}
XCSR のビット7 (xstb) が 1 なら、XBUF を読み、ディスプレイに表示します。
RCSR のビット7 (rstb) が 1 なら、RBUF にキー入力を書き込みます。
キー入力があれば、RCSR のビット7 (rrdy) に 1 を書き込みます。
Control-X で終了できるようにしました。
表示データもキー入力もなければ、XCSRのビット 7 (xrdy) に 1 を書き込みます。
PDP-11/HACK の Test #1 プログラムを実行してみます。
![](https://assets.st-note.com/img/1732444553-JoinEG8LkbIZXjfHpyPalqms.jpg?width=1200)
Tang Nano 9K コードの修正
最初非常に不安定でしたが、試行錯誤の結果、以下のように修正することで、完全ではありませんが、ある程度安定するようになりました。
RAM のアクセス用クロック memory_clk を、DCJ11 のクロックの 9 倍 (162 MHz) に変更し、3 分周した 54 MHz のクロック clk_x3 で、各種信号の処理を行うようにしました。
top.sv
`default_nettype none
// DCJ11 TangNano interface by nanja.info
// TEST18 2024.11.24 Use Extarnal clock
module top (
inout wire [15:0] dal, // DAL<21:0>, BS<1:0>
input wire [3:0] aio, // AIO<3:0>
inout wire [7:0] d, // Apple II Data D<7:0>
input wire devsel_n, // Apple II /DEVSEL
input wire rw, // Apple II R/W
input wire bufctl_n,
input wire ale_n,
output wire nxm_n,
input wire sctl_n,
input wire clk,
output reg cont_n,
output reg miss_n,
output reg dallo_oe_n,
output reg event_n,
output reg irq0,
output reg irq1,
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
// Apple II Register
parameter A2RCSR = 8'h00; // Console out status; Read = rstb, Write = rrdy
parameter A2RBUF = 8'h01; // Cousole out data
parameter A2XCSR = 8'h02; // Console in status; Read = xstb, Write = xrdy
parameter A2XBUF = 8'h03; // Console in data
logic clk_x3; // clk x 3 = 54 MHz
//Gowin_rPLL rpll(
// .clkout(clk_x3), //output clkout
// .clkin(clk) //input clkin
//);
assign event_n = 1'b1;
assign irq0 = 1'b0;
assign irq1 = 1'b0;
logic [4:0] count;
logic [15:0] mdallo;
logic [21:0] mdal;
logic [3:0] maio;
logic [1:0] mbs;
logic [7:0] gp_code;
logic [7:0] a; // Apple II Address
always_ff@(posedge clk_x3) begin
if (ale_n) begin
count <= 0;
end else begin
if (count == 0) begin
dallo_oe_n <= 1'b1;
mdallo <= dal;
end else if (count == 2) begin
if ((aio == GP_READ) || (aio == GP_WRITE)) begin
gp_code <= mdallo[7:0];
end else begin
gp_code <= 8'b11111111;
end
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;
a[0] <= dal[5];
a[1] <= dal[4];
a[2] <= dal[3];
a[3] <= dal[2];
a[4] <= dal[1];
a[5] <= dal[15];
a[6] <= dal[14];
a[7] <= dal[13];
dallo_oe_n <= 1'b0;
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 [7:0] xbuf;
logic [7:0] rbuf;
logic xrdy;
logic rrdy;
logic [7:0] d0;
assign d = rw ? d0 : 8'bz;
logic devsel0;
logic devsel1;
//always_ff@(posedge clk) begin
always_ff@(posedge clk_x3) begin
devsel0 <= !devsel_n;
devsel1 <= devsel0;
end
logic dev_done;
logic error;
//always_ff@(posedge clk) begin
always_ff@(posedge clk_x3) begin
if (devsel1) begin
if (dev_done) begin;
if (rw) begin
case (a[3:0])
A2RCSR : d0 <= {rstb, 7'b0};
A2XCSR : d0 <= {xstb, 7'b0};
A2XBUF : d0 <= xbuf;
endcase
end else begin
case (a[3:0])
A2RCSR : rrdy <= d[7];
A2RBUF : rbuf <= d;
A2XCSR : xrdy <= d[7];
8'h0f : error <= 1'b1;
endcase
end
dev_done <= 1'b0;
end
end else begin
dev_done <= 1'b1;
error <= 1'b0;
end
end
logic xdone;
logic xstb;
//always_ff@(posedge clk) begin
always_ff@(posedge clk_x3) begin
if (gp_code == 8'o014) begin
xdone <= 1'b1;
xstb <= 1'b0;
end else if ((sctl_n == 0) && (mdal == XBUF)) begin
xstb <= 1'b1;
xdone <= 1'b0;
xbuf <= dal[7:0];
end else if (xstb & !xrdy) begin
xstb <= 1'b0;
end else if (!xstb & xrdy) begin
xdone <= 1'b1;
end
end
logic rdone;
logic rstb;
//always_ff@(posedge clk) begin
always_ff@(posedge clk_x3) begin
if (gp_code == 8'o014) begin
rdone <= 1'b0;
rstb <= 1'b0;
end else if (rrdy) begin
rstb <= 1'b1;
end else if (rstb) begin
rstb <= 1'b0;
rdone <= 1'b1;
end else if (mdal == RBUF) begin
rdone <= 1'b0;
end
end
assign dal = bufctl_n ? 16'bz :
(mdal == RCSR) ? {8'b0, rdone, 7'b0} :
(mdal == XCSR) ? {8'b0, xdone, 7'b0} :
(mdal == RBUF) ? {8'b0, rbuf} :
(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 cont_n = 1'b0;
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 == 3)) 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
always_ff@(posedge clk_x3) 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
ram.sv
`default_nettype none
// DCJ11 TangNano interface by nanja.info
// PSRAM interface module
// TEST18 2024.11.24 Use external clock
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 clk,
output reg clk_x3,
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
.clkoutd3(clk_x3), //output clkoutd3
.clkin(clk) //input clkin
);
logic clk_d;
logic memory_clk/* synthesis syn_keep=1 */;
logic memory_clk_p;
logic pll_lock;
logic init_calib0;
logic init_calib1;
logic clk_out/* synthesis syn_keep=1 */;
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;
logic clk2;
assign clk_out = clk2;
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(clk2), //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
参考文献
DCJ11 Microprocessor User's Guide, 5.3 CONSOLE ODT, 1983
Apple II Reference Manual, Signal description for peripheral I/O, 1978
Apple2BuildPipeline