A2PDP11 (7) コンソール ODT の起動
コンソール ODT (Octal Debugging Technique) を起動し、出力を USB シリアルで読み取れるようにします。
コンソール ODT のインターフェースは、Users Guide 5.3 章に記載があります。
USB シリアルは Arduino nano を使いました。後で、この部分は、Apple II バスとの接続に置き換えます。
Tang Nano 9K および Arduino と下図のように接続します。
ODT の出力時に DAL<7:0> を 74LS374 でラッチし、Arduino で読み取ります。ハンドシェーク用に 4 本の信号 RRDY、RSTB、WRDY、WSTB を使います。
Arduino のスケッチを作成します。
D2-D9 は 74LS374 を介して DAL<7:0> につながっています。
RRDY (Read Ready) は、Arduino が DCJ11 からデータを受信可能なとき HIGH になります。RSTB (Read Strobe) は、DCJ11 からの出力があるとき HIGH になります。RENB は、74LS374 の出力イネーブルを制御します(負論理)。
RSTB が HIGH の時、RRDY をネゲート (LOW) にし、ODT の出力を抑制します。続いて、RENB をアサート(LOW) し、DAL を読み取り、RENB をネゲート (HIGH) します。読み取ったデータをシリアルポートに出力し、RRDY をアサート (HIGH) にして、次のデータを読み取れるようにします。
// ODT serial console interface
// TEST 5: 2024.08.10 Read ODT console out, nanja.info
#define d0_pin 2
#define d1_pin 3
#define d2_pin 4
#define d3_pin 5
#define d4_pin 6
#define d5_pin 7
#define d6_pin 8
#define d7_pin 9
#define rrdy_pin 10 // Ready to read from DCJ11's ODT data
#define rstb_pin 11 // Strobe for read from DCJ11's ODT data
#define wrdy_pin 12 // Ready to write to DCJ11's ODT data
#define wstb_pin 13 // Strobe for write to DCJ11's ODT data
#define renb_pin 14 // Enable read data
#define wenb_pin 15 // Enable write data
void setup() {
Serial.begin(9600);
pinMode(d0_pin, INPUT);
pinMode(d1_pin, INPUT);
pinMode(d2_pin, INPUT);
pinMode(d3_pin, INPUT);
pinMode(d4_pin, INPUT);
pinMode(d5_pin, INPUT);
pinMode(d6_pin, INPUT);
pinMode(d7_pin, INPUT);
pinMode(rrdy_pin, OUTPUT);
pinMode(rstb_pin, INPUT);
pinMode(wrdy_pin, OUTPUT);
pinMode(wstb_pin, INPUT);
pinMode(renb_pin, OUTPUT);
pinMode(wenb_pin, OUTPUT);
digitalWrite(rrdy_pin, HIGH);
digitalWrite(wrdy_pin, LOW);
digitalWrite(renb_pin, HIGH);
digitalWrite(wenb_pin, HIGH);
Serial.println("Serial Start");
}
void loop() {
byte rdata; // read from DCJ11's ODT data
byte wdata; // write to DCJ11's ODT data
if (digitalRead(rstb_pin)) {
digitalWrite(rrdy_pin, LOW);
digitalWrite(renb_pin, LOW);
bitWrite(rdata, 0, digitalRead(d0_pin));
bitWrite(rdata, 1, digitalRead(d1_pin));
bitWrite(rdata, 2, digitalRead(d2_pin));
bitWrite(rdata, 3, digitalRead(d3_pin));
bitWrite(rdata, 4, digitalRead(d4_pin));
bitWrite(rdata, 5, digitalRead(d5_pin));
bitWrite(rdata, 6, digitalRead(d6_pin));
bitWrite(rdata, 7, digitalRead(d7_pin));
digitalWrite(renb_pin, HIGH);
Serial.write(rdata);
digitalWrite(rrdy_pin, HIGH);
}
}
top.sv を修正します。
ALE の立ち下がりエッジで、DAL、ALO、BS、を、それぞれ mdal、malo、mbs にラッチします。
// 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
`default_nettype none
module top (
input wire [3:0] aio,
input wire [1:0] bs,
input wire [5:0] dal_hi, // DAL<21:16>
inout wire [15:0] dal_lo, // DAL<15:0>
input wire proc_n,
input wire bufctl_n,
input wire ale_n,
input wire strb_n,
input wire sctl_n,
input wire map_n,
input wire abort_n,
input wire clk,
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
output wire nxm_n
);
logic sclk;
Gowin_rPLL u_rpll(
.clkout(sclk), //output clkout 54MHz
.clkin(clk) //input clkin 18MHz
);
// 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
logic [7:0] gp_code;
always_ff@(negedge ale_n) begin
if ((aio == GP_READ) || (aio == GP_WRITE)) begin
gp_code <= dal_lo[7:0];
end else begin
gp_code <= 8'b11111111;
end
end
logic [21:0] mdal;
logic [3:0] maio;
logic [1:0] mbs;
always_ff@(negedge ale_n) begin
mdal <= {dal_hi, dal_lo};
maio <= aio;
mbs <= bs;
end
起動モードを 01 (Enter Console ODT) に設定します。
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
コンソール ODT インターフェースのアドレス 17777560 - 17777566 へのアクセス時に、NXM アボートを生成しないようにします。
logic nxm;
assign nxm_n = sctl_n ? 1'b1 : ~nxm;
always_ff@(negedge ale_n) begin
if ((aio[3:2] == 2'b10) || (aio[3:2] == 2'b00)) begin
// RMW_BUSLOCK, RMW_NOLOCK, DATA_READ, DEMAND_READ, WORD_WRITE, BYTE_WRITE
if (bs == BS_MEM) begin
if (dal_lo > 16'o157777) begin
nxm <= 1'b1;
end
end
if (bs == BS_EXT) begin
if ({dal_hi, dal_lo[15:3]} == DLART) begin
nxm <= 1'b0;
end else begin
nxm <= 1'b1;
end
end
end else begin
nxm <= 1'b0;
end
end
rrdy を clk に同期させ、メタステーブルを回避するため、二段のフリップフロップ rrdy0、rrdy1 で受けます。
logic rxrdy;
logic rrdy1;
logic rrdy0;
always_ff@(negedge clk) begin
rrdy0 <= rrdy;
rrdy1 <= rrdy0;
end
XBUF の読み取りを制御します。
送信バッファレジスタ XBUF (17777562) への書き込み時、RSTB を生成 (HIGH) し、DAL<7:0> を 74LS344 でラッチします。ODT の次の出力を抑制するため、rxrdy を 0 にします。
Arduino が DAL を読み取るのを待ち、rrdy1 (CLK に同期したRRDY) がネゲート (LOW) になったら、RSTB を LOW にします。
Arduino がシリアル出力するのを待ち、rrdy1 がアサート (HIGH) になったら、rxrdy を 1 にし、次の ODT 出力を受けられるようにします。
always_ff@(negedge clk) begin
if ((sctl_n == 0) && (mdal == XBUF)) begin
rstb <= 1'b1;
rxrdy <= 1'b0;
end else if (!rrdy1) begin
rstb <= 1'b0;
end else if (!rstb) begin
rxrdy <= 1'b1;
end
end
BUFCTL のアサート (LOW) 時に、ODT インターフェースに応答するようにします。
受信制御・状態レジスタ RCSR (17777560) の読み出しに対し、wrdy を返します。
送信制御・状態レジスタ XCSR (17777564) の読み出しに対し、rxrdy を返します。
それ以外の読み出し時は、odt_out をハイインピーダンスにし、dal_out を返します。
logic [15:0] dal_out;
logic [15:0] odt_out;
assign dal_lo = bufctl_n ? 16'bz : dal_out | odt_out;
always_ff@(negedge bufctl_n) begin
if ((maio == DATA_READ) && (mbs == BS_EXT)) begin
if (mdal == RCSR) begin
odt_out <= {8'b0, wrdy, 7'b0};
end
if (mdal == XCSR) begin
odt_out <= {8'b0, rxrdy, 7'b0};
end
end else begin
odt_out <= 16'bz;
wstb <= 1'b0;
end
end
endmodule
`default_nettype wire
コンソール ODT 起動時の動作を確認します。
下図の、黄色マーカー部に示す GP CODE 230 (マイクロ診断テスト 3 成功) の後、赤マーカー部で GP CODE 234 (コンソール ODT 開始信号) が生成されています。白マーカー部で、AIO が 0011 (バスバイト書き込み)、BS が 10 (外部 I/O)、DAL<7:0> が 015 (CR) となりキャリッジリターンが出力されているのがわかります。
下図の、オレンジマーカー部で、Arduino にデータが読み込まれ RRDY が LOW になっています。右側の赤マーカー部で、Arduino のシリアル出力が完了し、RRDY が HIGH になりまます。
シリアル出力を、screen で表示してみます。
最初の Serial Start は、Arduino のデバッグ用の出力です。
<CR><LF>の後、PC (プログラムカウンタ) が 6 桁の 8 進数で表示され、<CR><LF>の後、プロンプト @ が表示されました。
INIT ボタンを押すたびに、繰り返されます。
参考文献
DCJ11 Microprocessor User's Guide, 5.3 CONSOLE ODT, 1983