// // Copyright (c) 2020 by 1801BM1@gmail.com // // Testbench for the M4 replica, native QBUS version //______________________________________________________________________________ // `include "../../tbe/config.v" //______________________________________________________________________________ // module memory ( input [15:0] a, input [15:0] din, output reg [15:0] dout, input wtbt, input read, input write ); reg [15:0] mem [0:8191]; integer i; always @ (posedge read) begin dout = mem[a[13:1]]; end always @ (negedge write) begin if (wtbt) begin if (a[0]) mem[a[13:1]][15:8] = din[15:8]; else mem[a[13:1]][7:0] = din[7:0]; end else mem[a[13:1]] = din; end initial begin for (i=0; i<8191; i = i + 1) begin mem[i] = 16'h0000; end $readmemh("../../../../tst/out/test.mem", mem); end endmodule //______________________________________________________________________________ // // Primary testbench top module // module tb4(); integer i, i0; reg clk; // processor clock reg dclo; // processor reset reg aclo; // power fail notificaton reg evnt; // timer interrupt requests reg halt; // radial interrupt requests reg virq; // vectored interrupt request reg rfrq; // dynamic RAM refresh request // tri1 init; // peripheral reset wire [1:0] bsel; // // reg [15:0] rad; // latched data wire [15:0] ad_mux; // tri1 [15:0] ad; // inverted address/data bus reg [15:0] ad_reg; // reg ad_oe; // // tri1 din; // data input strobe tri1 dout; // data output strobe tri1 wtbt; // write/byte status tri1 sync; // address strobe // reg rply; // transaction reply reg dmr; // bus request shared line reg sack; // bus acknowlegement wire dmgo; // bus grant output wire iako; // interrupt vector strobe wire dref; // reg din_iako; // reg din_sync; // reg in_iako; // // reg [15:0] addr; // reg wflg; // reg sel_all; // reg sel_ram; // // reg tty_tx_rdy; // terminal transmitter ready reg tty_tx_ie; // terminal transmitter interrupt enable reg tty_rx_ie; // terminal receiver interrupt enable // wire ram_read, ram_write; //_____________________________________________________________________________ // assign bsel = `SIM_CONFIG_BOOT_MODE; assign ad = ad_oe ? (sel_ram ? ~ad_mux : ~ad_reg) : 16'hZZZZ; assign ram_read = sel_ram & ~din & ~sync; assign ram_write = sel_ram & ~dout & ~sync; memory ram( .a(addr), .din(~ad), .dout(ad_mux), .wtbt(~wtbt), .read(ram_read), .write(ram_write)); always @(negedge sync) begin rply = 1'b1; addr <= ~ad; wflg <= ~wtbt; if (~ad < 16'o040000) begin sel_all = 1'b1; sel_ram = 1'b1; end if (~ad == 16'o177714) // 7-segment outhex sel_all = 1'b1; if (~ad == 16'o177715) sel_all = 1'b1; if ((~ad >= 16'o177560) & (~ad <= 16'o177567)) sel_all = 1'b1; end always @(posedge sync) begin sel_all = 1'b0; sel_ram = 1'b0; end always @ (posedge clk) rad <= ad; always @(negedge din) begin din_iako = iako; din_sync = sync; `ifdef SIM_CONFIG_DEBUG_IO @(posedge din) if (~din_sync) $display("Read @ %06O (%06O)", addr, ~ad); else if (~din_iako | in_iako) $display("Read @ Vector"); else $display("Read @ Invalid"); in_iako = 0; `endif end always @(posedge dout) begin `ifdef SIM_CONFIG_DEBUG_IO $display("Write @ %06O (%06O)", addr, ~ad); `endif end always @(posedge din or posedge dout) begin @ (negedge clk); @ (posedge clk); #2 ad_oe = 1'b0; rply = 1'b1; end always @(negedge din) begin if (~sync) begin if (addr == 16'o177560) begin ad_oe = 1'b1; ad_reg = 16'o000000 | (tty_rx_ie << 6); end if (addr == 16'o177562) begin ad_oe = 1'b1; ad_reg = 16'o000000; end if (addr == 16'o177564) begin ad_oe = 1'b1; ad_reg = (tty_tx_rdy << 7) | (tty_tx_ie << 6); end if (addr == 16'o177566) begin ad_oe = 1'b1; ad_reg = 16'o000000; end if (sel_all) begin #2 rply = 1'b0; ad_oe = 1'b1; end end end always @(negedge iako) begin in_iako = 1; if (~din) begin if (~virq) begin ad_oe = 1'b1; ad_reg = 16'o000064; @ (negedge clk); //@ (posedge clk); #2 virq = 1; rply = 1'b0; end end end always @(negedge dout) begin if (sel_all) begin //@ (negedge clk); //@ (posedge clk); #2 rply = 1'b0; end if (addr == 16'o177560) begin tty_rx_ie = ~ad[6]; end if (addr == 16'o177564) begin tty_tx_ie = ~ad[6]; if (tty_tx_rdy & tty_tx_ie) virq = 0; else virq = 1; end if (addr == 16'o177566) begin tty_tx_rdy = 0; virq = 1; `ifdef SIM_CONFIG_DEBUG_TTY $display("tty: %06O (%c)", ~ad & 8'o377, ((~ad & 8'o377) > 16'o000037) ? (~ad & 8'o377) : 8'o52); if ((~ad & 8'o377) == 16'o000100) begin $display("ODT invoked, stop"); $finish; end `endif end end //_____________________________________________________________________________ // // Terminal registers simulation // always @(negedge init) begin tty_tx_ie = 0; tty_rx_ie = 0; tty_tx_rdy = 1; virq = 1; end always @(negedge tty_tx_rdy) begin for (i=0; i<4000; i = i + 1) begin @ (negedge clk); @ (posedge clk); end tty_tx_rdy = 1; if (tty_tx_ie) virq = 0; end //_____________________________________________________________________________ // // Clock generator // initial begin forever begin clk = 1; #(`SIM_CONFIG_CLOCK_HPERIOD); clk = 0; #(`SIM_CONFIG_CLOCK_HPERIOD); end end //_____________________________________________________________________________ // // Simulation time limit (first breakpoint) // initial begin #`SIM_CONFIG_TIME_LIMIT $finish; end //_____________________________________________________________________________ // initial begin tty_tx_ie = 0; tty_rx_ie = 0; tty_tx_rdy = 1; in_iako = 0; rfrq = 1; dclo = 0; aclo = 0; evnt = 1; virq = 1; halt = 1; ad_reg = ~16'h0000; ad_oe = 0; rply = 1; sack = 1; dmr = 1; // // CPU start // for (i=0; i<24; i = i + 1) begin @ (posedge clk); end dclo = 1; for (i=0; i<90; i = i + 1) begin @ (posedge clk); end #1 aclo = 1; $display("Processor ACLO and DCLO deasserted"); end //_____________________________________________________________________________ // am4 cpu ( .pin_clk(clk), // processor clock .pin_init_n(init), // peripheral reset .pin_dclo_n(dclo), // processor reset .pin_aclo_n(aclo), // power fail notificaton .pin_halt_n(halt), // halt mode request .pin_evnt_n(evnt), // timer interrupt requests .pin_virq_n(virq), // vectored interrupt request .pin_rfrq_n(rfrq), // refresh DRAM request // .pin_dmr_n(dmr), // bus request line .pin_sack_n(sack), // bus acknowlegement .pin_rply_n(rply), // transaction reply .pin_dmgo_n(dmgo), // bus granted output // .pin_ad_n(ad), // inverted address/data bus .pin_dref_n(dref), // dynamic RAM refresh .pin_sync_n(sync), // address strobe .pin_wtbt_n(wtbt), // write/byte status .pin_dout_n(dout), // data output strobe .pin_din_n(din), // data input strobe .pin_iako_n(iako), // interrupt vector input // .pin_bsel_n(bsel) // boot mode 3 - reserved micROM // boot mode 0 - 24/26 vector ); //_____________________________________________________________________________ // endmodule