// // Copyright (c) 2014-2019 by 1801BM1@gmail.com //______________________________________________________________________________ // // Optimizations done: // - plr18r is replaced by plr[18] // - plr33r is replaced by plr[33] // - ustb2 is equal to ~au_alsl // - 177702 register data removed // - dout_start uses rply_ack[2] instead of rply_ack[1] // - slave Qbus interface should be syncronized (or slow) with clk // //______________________________________________________________________________ // // Version of 1801VM1 processor with Q-bus external interface // All external signal transitions should be synchronzed with pin_clk // The core does not contain any extra metastability eliminators itself // module vm1_qbus #(parameter //______________________________________________________________________________ // // If VM1_CORE_REG_USES_RAM is nonzero the Register File is implemented // as library RAM module, the constant and vector generators also use // this initialized RAM to provide the data. This option is intended to // be used on FPGA with embedded RAM blocks // VM1_CORE_REG_USES_RAM = 1, //______________________________________________________________________________ // // VM1 version select - VM1A or VM1G. VM1G contains another version of // microcode, supports VE timer interrupt and MUL operation. // If VM1_CORE_MULG_VERSION is defined an nonzero the VM1G core being generated // VM1_CORE_MULG_VERSION = 0 ) ( input pin_clk_p, // processor clock input pin_clk_n, // processor clock 180 degree input pin_ena, // processor clock enable input [1:0] pin_pa, // processor number input pin_init_in, // peripheral reset input output pin_init_out, // peripheral reset output // input pin_dclo, // processor reset input pin_aclo, // power fail notificaton input [3:1] pin_irq, // radial interrupt requests input pin_virq, // vectored interrupt request // input [15:0] pin_ad_in, // data bus input output [15:0] pin_ad_out, // address/data bus output output pin_ad_ena, // address/data bus enable // input pin_dout_in, // data output strobe input output pin_dout_out, // data output strobe output input pin_din_in, // data input strobe input output pin_din_out, // data input strobe output output pin_wtbt, // write/byte status output pin_ctrl_ena, // enable control outputs // input pin_sync_in, // address strobe input output pin_sync_out, // address strobe output output pin_sync_ena, // address strobe enable // input pin_rply_in, // transaction reply input output pin_rply_out, // transaction reply output // input pin_dmr_in, // bus request shared line output pin_dmr_out, // // input pin_sack_in, // bus acknowlegement output pin_sack_out, // bus acknowlegement // input pin_dmgi, // bus granted input output pin_dmgo, // bus granted output output pin_iako, // interrupt vector input input pin_sp, // peripheral timer input output [2:1] pin_sel, // register select outputs output pin_bsy // bus busy flag ); //______________________________________________________________________________ // wire [15:0] wb_pio_dat_i; // wire [15:0] wb_cpu_dat_i; // // wire [33:0] plx, plx_a, plx_g; // main microcode matrix output reg [33:0] plr; // main matrix result register (last stage) reg [33:0] plm; // main matrix result register (first stage) reg [14:0] mj; // microcode stage and condition register reg [15:0] ir; // instruction register (last stage) reg [15:0] ira; // instruction register (first stage) // wire [10:0] pli, pli_a, pli_g; // interrupt priority encode matrix output reg [19:0] rq; // interrupt request register reg aclo; // ACLO falling edge detectors reg acok; // ACLO raising edge detectors reg irq2; // IRQ2 falling edge detectors reg irq3; // IRQ3 falling edge detectors reg uop; // undefined operation latch reg qbto; // I/O bus timeout & OAT latch reg ivto; // IAKO bus timeout latch reg start_irq; // raised by 1777x2 register write wire tve_irq; // VE-timer interrupt request (vm1a_pli ignores) wire tve_ack; // VE-timer interrupt acknowledgement // wire exc_uop; // Undefined opcode found wire exc_oat; // Odd address trap detector wire exc_err2; // wire exc_err3; // wire exc_err7; // reg [3:0] exc_dbl; // double error detector // reg [5:0] qbus_timer; // qbus timeout counter wire qbus_tena; // reg qbus_tovf; // Qbus timer overflow latch // // wire uop_ack; // undefined instruction wire aclo_ack; // ACLO timer acknowlegement wire irq2_ack; // IRQ2 timer acknowlegement wire irq3_ack; // IRQ3 timer acknowlegement reg [3:0] vsel; // vector selection register reg [3:0] plir; // pli[10:8:6:4] outputs latch // wire ir_stb1; // reg ir_stb2; // instruction register strobe wire ir_clr; // wire ir_set_fc; // reg ir_set; // reg ir_stop; // reg ir_seq; // wire ir_seq_rc; // // wire pli_req_rc; // interrupt encoder request reg pli_req; // source and latch wire pli_stb; // interrupt matrix strobe wire pli_nrdy; // interrupt matrix not ready // wire plm_stb_rc; // plm_register strobe source reg plm_stb; // plm_register strobe latch // wire plm1x_fc; // wire plm2x_fc; // main matrix result strobes reg plm1x, plm2x; // reg plm1x_hl; // reg plm_ena; // wire plm_ena_fc; // // reg [3:0] sop_out; // wire sop_up; // wire [7:0] plop; // wire uplr_stb; // reg mj_stb1, mj_stb2; // reg psw_stb, psw_stbc; // reg psw_mj; // // wire [3:0] plm23_fc; // reg plm23_wait; // reg plm23_ichk; // // wire [3:1] tplm_rc; // reg [3:1] tplm; // reg [3:1] tplmz; // reg [8:6] plrt; // reg [8:6] plrtz; // // reg reset; // global device hardware reset reg abort; // odd address. bus hang, invalid opcode reg mjres; // reset microcode state machine reg mjres_h; // // wire mjres_rc; // wire reset_rc; // wire abort_rc; // reg abort_tm; // // wire [15:0] d; // internal data bus wire [15:0] tve_d; // timer module data output wire ad_oe; // external AD pins output enable wire sel177x; // peripheral block access reg sel_00, sel_02, // peripheral block selectors sel_04, sel_06, // sel_10, sel_12, // sel_14, sel_16, // sel_xx; // wire sel_in, sel_out; // reg rply_s2, rply_s3; // disable rply generation if start_irq active wire rply_s1; // // reg dmr_req; // reg dmr_req_l; // wire dmr_req_rc; // wire dmr_out; // wire iako_out; // reg iako_out_lh; // reg iak_flag; // reg [2:0] init_out; // // wire qbus_done; // reg [3:1] rply_ack; // wire rply_ack_fc; // // reg iako_oe; // wire oe_set_fc; // reg oe_set; // wire oe_clr_fc; // reg oe_clr; // // wire qbus_nrdy; // reg [1:0] qbus_aseq; // address request sequencer reg dout_done; // wire dout_start; // reg dout_req; // wire dout_req_rc; // reg dout_out; // reg dout_out_l; // wire dout_ext; // // wire din_done; // wire din_start; // reg din_out; // reg din_out_l; // // wire dmgo_out; // wire qbus_yield; // reg dmgi_in_l; // reg qbus_adr; // reg qbus_req; // reg qbus_win; // reg qbus_win_h; // wire qbus_own; // reg qbus_own_fp; // reg qbus_own_rp; // reg qbus_flag; // wire qbus_flag_rc; // reg sack_out; // reg sync_out; // reg sync_out_h; // reg sync_ena; // wire sync_stb; // wire sync_fedge; // reg qbus_nosr_h; // wire qbus_nosr_rc; // wire qbus_gnt; // reg qbus_gnt_l; // wire qbus_free; // reg qbus_free_h; // // reg [2:0] reg_csr; // 177700: control register reg [7:0] reg_err; // 177704: error register // reg [3:0] freg; // reg [15:0] psw; // processor status word wire [15:0] x, xr, xr_ff, xr_rm; // X bus wire [15:0] y, yr, yr_ff, yr_rm; // Y bus wire [15:0] f; // ALU function inverted output wire [15:0] h; // half summ wire [15:0] c; // carry wire [15:0] cpred; // carry form preceding but reg cl; // inserted least bit carry // wire [1:0] fmux; // wire [3:0] flag; // wire fbit7, fbit15; // wire [7:1] fctl; // wire fbitc; // // reg alu_b, alu_c; // ALU function selector reg alu_d, alu_e; // registered for speed reg alu_s, alu_x; // // wire cl_fc; // wire alu_b_fc; // wire alu_c_fc; // wire alu_d_fc; // wire alu_e_fc; // wire alu_x_fc; // wire alu_s_fc; // // wire [15:0] alu; // ALU output to X/Y bus wire [15:0] axy; // AND product wire [15:0] oxy; // OR product // reg ustb, ustb_h; // reg ustb1, ustb1_h; // reg ustb1_hl; // // reg alu_busy_fp; // ALU busy (not ready phase shifted) reg alu_busy_rp; // reg alu_nrdy; // ALU not ready wire alu_qrdy; // Qbus data ready // reg au_alsl, au_alsh; // ALU result strobes wire au_qsx, au_qsy; // qbus temporary register wire au_pswx, au_pswy; // PSW read enable wire au_pstbx; // PSW write strobe wire au_astb; // wire au_qstbx; // wire au_qstbd; // wire au_is0, au_is1; // ALU X argument strobes wire au_qrdd; // reg au_ta0; // // reg au_astb_xa; // au_astb/au_qstb speed optimizers reg au_qstb_xa; // reg au_astb_xu; // reg au_qstb_xu; // // wire [15:0] qrd; // qbus byte swap data wire [15:0] nx; // reg [15:0] qreg; // ALU Q register (Q-bus data) reg [15:0] areg; // ALU A register (Q-bus address) reg [15:0] xreg; // ALU X parameter register reg [15:0] yreg; // ALU Y parameter register //______________________________________________________________________________ // // synopsys translate_off initial begin plm[33:0] = 34'o000000000000; psw[15:0] = 16'o000000; end // synopsys translate_on //______________________________________________________________________________ // // External connection assignments // assign wb_pio_dat_i = pin_ad_in; assign wb_cpu_dat_i = pin_ad_in; assign pin_init_out = init_out[0] | reset_rc; assign pin_ad_out = d; assign pin_ad_ena = ad_oe; assign pin_dout_out = dout_out & dout_out_l; assign pin_din_out = din_out; assign pin_wtbt = (sync_stb & ~plrt[8]) | (dout_ext & plrt[6]); assign pin_sync_out = sync_out; assign pin_sync_ena = sync_ena | sync_out; assign pin_ctrl_ena = qbus_win | iako_oe; assign pin_rply_out = (sel_in | sel_out) & (pin_rply_in | ~sel_02 | ~rply_s2); assign pin_iako = iako_out_lh; assign pin_bsy = sync_out | pin_ctrl_ena; assign pin_dmr_out = dmr_out; assign pin_sack_out = sack_out; assign pin_dmgo = dmgo_out; assign pin_sel[2] = sel_14; assign pin_sel[1] = sel_16; //______________________________________________________________________________ // // Control and glue logic // // assign ir_clr = ~tplm_rc[3] & ~ir_seq_rc & (tplm[3] | ir_seq); assign ir_clr = (~tplm_rc[3] & tplm[3]) | (~ir_seq_rc & ir_seq); // // tplm1 - instruction prefetch // tplm3 - instruction fetch // assign ir_seq_rc = ~mjres & ~mjres_rc & (~ir_seq | tplm[1] | tplm[3]) & (plm23_wait | ir_seq); always @(posedge pin_clk_p) ir_seq <= ir_seq_rc; assign plm_ena_fc = ~sop_out[0] & (mjres | ustb1_h | ~alu_busy_rp) & ~qbus_nrdy; always @(posedge pin_clk_n) begin plm_ena <= plm_ena_fc; end assign sop_up = sop_out[3] | (~sop_out[2] & ~sop_out[1]); always @(posedge pin_clk_p) begin sop_out[2] <= sop_out[1]; if (plm_stb_rc) sop_out[0] <= 1'b0; else if (mjres_rc | plm_ena) sop_out[0] <= 1'b1; end always @(posedge pin_clk_n) begin sop_out[1] <= sop_out[0]; sop_out[3] <= ir_stop | pli_nrdy | ir_stb2 | mjres_h | (alu_nrdy & (plop[0] | plop[4])); end assign plm_stb_rc = ~plm_stb & ~sop_up; always @(posedge pin_clk_p) plm_stb <= plm_stb_rc; always @(posedge pin_clk_n or posedge mjres) begin if (mjres) ustb <= 1'b0; else begin if (ustb_h) ustb <= 1'b0; else if ((alu_busy_rp | (alu_busy_fp & ~ustb1_h)) & alu_qrdy) ustb <= 1'b1; end end always @(posedge pin_clk_p or posedge mjres) begin if (mjres) ustb_h <= 1'b0; else ustb_h <= ustb; end always @(posedge pin_clk_n) ustb1 <= ustb_h; always @(posedge pin_clk_p) ustb1_h <= ustb1; always @(posedge pin_clk_n) ustb1_hl <= ustb1_h; always @(posedge pin_clk_n or posedge mjres) begin if (mjres) alu_busy_fp <= 1'b0; else alu_busy_fp <= alu_busy_rp; end always @(posedge pin_clk_p or posedge mjres) begin if (mjres) alu_busy_rp <= 1'b0; else if (plm2x) alu_busy_rp <= 1'b1; else if (ustb1) alu_busy_rp <= 1'b0; end always @(posedge pin_clk_p or posedge mjres) begin if (mjres) alu_nrdy <= 1'b0; else if (plm2x) alu_nrdy <= 1'b1; else if (ustb1_h) alu_nrdy <= 1'b0; end assign ir_stb1 = tplm[1] | tplm[3]; assign ir_set_fc = plm23_fc[0] | plm23_fc[1] | plm23_fc[3]; always @(posedge pin_clk_n) ir_set <= ir_set_fc; always @(posedge pin_clk_p or posedge mjres) begin if (mjres) ir_stb2 <= 1'b0; else begin if (ir_clr) ir_stb2 <= 1'b0; else if (ir_set) ir_stb2 <= 1'b1; end end always @(posedge pin_clk_p or posedge mjres) begin if (mjres) ir_stop <= 1'b0; else if (~reg_csr[0]) ir_stop <= 1'b0; else if (ir_clr) ir_stop <= 1'b1; end always @(posedge pin_clk_n or posedge mjres) begin if (mjres) tplmz <= 3'b000; else if (plm_ena_fc) begin tplmz[1] <= (plm[3:1] == 3'b100); tplmz[2] <= (plm[3:1] == 3'b010); tplmz[3] <= (plm[3:1] == 3'b011); end end assign tplm_rc[1] = ~(mjres | mjres_rc | din_done) & ((uplr_stb & tplmz[1]) | tplm[1]); // instruction early prefetch assign tplm_rc[2] = ~(mjres | mjres_rc | din_done) & ((uplr_stb & tplmz[2]) | tplm[2]); // data retrieving assign tplm_rc[3] = ~(mjres | mjres_rc | din_done) & ((uplr_stb & tplmz[3]) | tplm[3]); // instruction fetch always @(posedge pin_clk_p) tplm <= tplm_rc; always @(posedge pin_clk_p) begin // // plr[6] QBUS operation type: byte operation flag // plr[7] QBUS operation type: write flag // plr[8] QBUS operation type: read flag // 00x - nothing // 010 - write word // 011 - write byte // 100 - read word // 101 - read byte // 110 - read-modify-write word // 111 - read-modify-write byte // plrtz[6] <= plr[6]; plrtz[7] <= plr[7] & plr[8]; plrtz[8] <= plr[8]; // // Reset Read Flag after read completion within // read-modify-write operations // if (din_done) plrt[8] <= 1'b0; else if (uplr_stb) plrt[8] <= plrtz[8]; if (uplr_stb) plrt[7:6] <= plrtz[7:6]; end //______________________________________________________________________________ // // Qbus logic // assign qbus_done = (din_done & ~plrt[7]) | dout_done | mjres; always @(posedge pin_clk_p) iako_out_lh <= iako_out; assign iako_out = din_out & iak_flag; // // Master processor never asserts DMR_OUT // assign dmr_out = dmr_req & (pin_pa != 2'b00); // // Reply acknowlegement latches // (converted to flip-flops approach) // assign rply_ack_fc = (pin_rply_in & pin_bsy); always @(posedge pin_clk_p) rply_ack[1] <= rply_ack_fc; always @(posedge pin_clk_n) rply_ack[2] <= rply_ack[1]; always @(posedge pin_clk_p) rply_ack[3] <= rply_ack[2]; assign alu_qrdy = (~qbus_adr | plr[23] | (~plr[7] & ~plr[8])) // wait for areg free & (~dout_req | plr[23] | plr[7] | plr[8]) // wait for write complete & (plr[10] | (~tplm[2] & ~iak_flag)); // wait for data or vector fetch always @(posedge pin_clk_p) begin if (uplr_stb) qbus_adr <= 1'b1; else if (mjres | mjres_rc | sync_fedge) qbus_adr <= 1'b0; end assign dmr_req_rc = ~(~sync_out & qbus_win) & (au_astb | dmr_req); always @(posedge pin_clk_p or posedge mjres) begin if (mjres) dmr_req <= 1'b0; else dmr_req <= dmr_req_rc; end always @(posedge pin_clk_n) dmr_req_l <= dmr_req; assign dout_req_rc = (~plrt[8] & au_qstbx & (dmr_req_rc | qbus_own_rp)) | (~qbus_done & dout_req); always @(posedge pin_clk_p or posedge mjres) begin if (mjres) dout_req <= 1'b0; else dout_req <= dout_req_rc; end assign dout_ext = dout_out | dout_out_l; assign dout_start = dout_req_rc & qbus_flag_rc & ~rply_ack[2]; // originally ~rply_ack[1] always @(posedge pin_clk_p or posedge mjres) begin if (mjres) dout_out <= 1'b0; else if (dout_done) dout_out <= 1'b0; else if (dout_start) dout_out <= 1'b1; end always @(posedge pin_clk_n) begin dout_done <= rply_ack[1] & dout_out; dout_out_l <= dout_out; end assign din_start = oe_set | (plrt[8] & sync_fedge); assign din_done = din_out_l & (/* rply_ack[3] | */ rply_ack[2]); always @(posedge pin_clk_n) din_out_l <= din_out; always @(posedge pin_clk_p or posedge mjres) begin if (mjres) din_out <= 1'b0; else if (din_done) din_out <= 1'b0; else if (din_start) din_out <= 1'b1; end assign qbus_tena = dout_out | din_out; assign oe_clr_fc = mjres | (/* ~rply_ack_fc & */ rply_ack[1] & ~qbus_flag); assign oe_set_fc = qbus_gnt & iak_flag & ~dmr_req & ~qbus_own; always @(posedge pin_clk_n) begin if (oe_clr_fc) iako_oe <= 1'b0; else if (oe_set_fc) iako_oe <= 1'b1; oe_clr <= oe_clr_fc; oe_set <= oe_set_fc; end assign sync_stb = qbus_win & (~sync_out_h | ~qbus_win_h); assign sync_fedge = sync_out & ~sync_ena; always @(posedge pin_clk_n) begin if (oe_clr_fc) qbus_win <= 1'b0; else if (dmr_req & qbus_gnt) qbus_win <= 1'b1; end always @(posedge pin_clk_p) begin qbus_win_h <= qbus_win; sync_out_h <= sync_out; end always @(posedge pin_clk_n) begin sync_out <= qbus_win_h; sync_ena <= sync_out_h; end assign qbus_yield = ~iako_oe & ~qbus_own & (pin_pa[1:0] == 2'b00) & pin_dmr_in; assign qbus_free = ~(pin_dmr_in | pin_sack_in | (pin_pa[1:0] != 2'b00)); assign qbus_gnt = (qbus_nosr_h | (sync_out_h & ~qbus_win_h)) & (qbus_free_h | (dmr_out & sack_out)); assign qbus_nosr_rc = ~pin_rply_in & ~pin_sync_in; always @(posedge pin_clk_p) qbus_free_h <= qbus_free; always @(posedge pin_clk_p) qbus_nosr_h <= qbus_nosr_rc; always @(posedge pin_clk_n) qbus_gnt_l <= qbus_gnt; assign qbus_own = qbus_own_fp | qbus_own_rp; always @(posedge pin_clk_p) begin if (qbus_done) qbus_own_rp <= 1'b0; else if (dmr_req_l & qbus_gnt_l) qbus_own_rp <= 1'b1; end always @(posedge pin_clk_n) begin if (qbus_own_rp) qbus_own_fp <= 1'b0; else if (dmr_req & qbus_gnt) qbus_own_fp <= 1'b1; end assign qbus_flag_rc = ~qbus_done & (sync_fedge | qbus_flag); always @(posedge pin_clk_p) qbus_flag <= qbus_flag_rc; always @(posedge pin_clk_p or posedge mjres) begin if (mjres) sack_out <= 1'b0; else if (qbus_done) sack_out <= 1'b0; else if (pin_dmgi & (qbus_nosr_rc | (sync_out & ~qbus_win)) & qbus_req) sack_out <= 1'b1; end always @(posedge pin_clk_n) dmgi_in_l <= pin_dmgi; assign dmgo_out = qbus_yield | (~qbus_req & dmgi_in_l); always @(posedge pin_clk_p or posedge mjres) begin if (mjres) qbus_req <= 1'b0; else if (qbus_done) qbus_req <= 1'b0; else if (dmr_out & ~pin_dmgi) qbus_req <= 1'b1; end //______________________________________________________________________________ // // 1801BM1 can issue preliminary transaction address, so the plm->plr strobe // should be delayed till current transaction in progess completed // assign qbus_nrdy = (qbus_aseq[1] & ~oe_clr) | (au_astb & qbus_aseq[0] & ~oe_clr); assign uplr_stb = (au_astb & ~qbus_aseq[0]) | (au_astb & qbus_aseq[0] & oe_clr) | qbus_aseq[1] & oe_clr; always @(posedge pin_clk_n or posedge mjres) begin if (mjres) qbus_aseq <= 2'b00; else begin // // Reset the completed request if it is only one // if (au_astb) qbus_aseq[0] <= 1'b1; else if (oe_clr & ~qbus_aseq[1]) qbus_aseq[0] <= 1'b0; // // The third request is impossible - the state machine // is suspended by qbus_nrdy // if (oe_clr) qbus_aseq[1] <= 1'b0; else if (au_astb & qbus_aseq[0]) qbus_aseq[1] <= 1'b1; end end //______________________________________________________________________________ // assign d = ((sel_in & sel_00) ? {11'o3777, pin_pa, reg_csr} : 16'o000000) | ((sel_in & sel_02) ? 16'o177777 : 16'o000000) | ((sel_in & sel_04) ? {8'o377, reg_err} : 16'o000000) | ((sel_in & (sel_06 | sel_10 | sel_12)) ? tve_d : 16'o000000) | (sync_stb ? areg : 16'o000000) | (au_qrdd ? qrd : 16'o000000); assign qrd = au_ta0 ? {qreg[7:0], 8'o000} : (plrt[6] ? {8'o000, qreg[7:0]} : qreg); assign sel177x = (pin_ad_in[15:6] == 10'o1777) & (pin_ad_in[5:4] == pin_pa[1:0]); assign sel_in = sel_xx & pin_din_in; assign sel_out = sel_xx & pin_dout_in; assign ad_oe = sync_stb | dout_ext | ~(sel_16 | sel_14 | ~sel_in); vm1_timer timer ( .tve_clk(pin_clk_p), .tve_ena(pin_ena), .tve_reset(pin_init_out | pin_init_in), .tve_dclo(pin_dclo), .tve_sp(pin_sp), .tve_din(wb_pio_dat_i), .tve_dout(tve_d), .tve_csr_oe(sel_12 & sel_in), .tve_cnt_oe(sel_10 & sel_in), .tve_lim_oe(sel_06 & sel_in), .tve_csr_wr(sel_12 & sel_out), .tve_lim_wr(sel_06 & sel_out), .tve_irq(tve_irq), .tve_ack(tve_ack) ); // // Qbus timeout counter // // original 1801BM1 timer has 1/8 input prescaler which is no reset and // provides bus timeout in a range 56..63 processor clocks. This model // emulates the average value 60 clocks. // // Timeout exception request should be synchronized with raising clk's edge // always @(posedge pin_clk_p) begin qbus_tovf <= &qbus_timer[5:2]; end always @(posedge pin_clk_n or negedge qbus_tena) begin if (~qbus_tena) qbus_timer <= 6'o00; else if (~qbus_tovf) qbus_timer <= qbus_timer + 6'o01; end // // Control register at 177700 // always @(posedge pin_clk_p or posedge reset) begin if (reset) reg_csr <= 3'b000; else begin // // Bit 0 of control register // if ((plm1x_hl & ~plr[25]) | (ir_set & reg_csr[1])) reg_csr[0] <= 1'b1; else if (sel_out & sel_00) reg_csr[0] <= wb_pio_dat_i[0]; // // Bit 1 of control register (controls set of bit 0) // if (sel_out & sel_00) reg_csr[1] <= wb_pio_dat_i[1]; // // Bit 2 of control register (wait state) // if (plm1x_hl & ~plr[27]) reg_csr[2] <= 1'b0; else if (plm1x_hl & ~plr[7]) reg_csr[2] <= 1'b1; else if (sel_out & sel_00) reg_csr[2] <= wb_pio_dat_i[2]; end end // // Error register at 177704 // Bit 0 is Double Error // Bit 1 is Undefine Opcode // Bit 5 is not used (always read as one) // Bit 6 is Odd Address Trap (is not implmented) // always @(posedge pin_clk_p) begin if (reset_rc | ir_set) reg_err <= 8'b00100000; else begin // // Bit 0 - double error // if ( (exc_dbl[0] & exc_uop) | (exc_dbl[1] & qbus_tovf) | (exc_dbl[2] & exc_oat) | (exc_dbl[3] & exc_err7)) reg_err[0] <= 1'b1; else if (sel_out & sel_04) reg_err[0] <= wb_pio_dat_i[0]; // // Bit 1 - undefined opcode // if (exc_uop) reg_err[1] <= 1'b1; else if (sel_out & sel_04) reg_err[1] <= wb_pio_dat_i[1]; // // Bit 2 & 3 - unknown error, exceptions not implemented // if (exc_err2) reg_err[2] <= 1'b1; else if (sel_out & sel_04) reg_err[2] <= wb_pio_dat_i[2]; if (exc_err3) reg_err[3] <= 1'b1; else if (sel_out & sel_04) reg_err[3] <= wb_pio_dat_i[3]; // // Bit 4 - qbus timeout // if (qbus_tovf) reg_err[4] <= 1'b1; else if (sel_out & sel_04) reg_err[4] <= wb_pio_dat_i[4]; // // Bit 6 - odd address trap // if (exc_oat) reg_err[6] <= 1'b1; else if (sel_out & sel_04) reg_err[6] <= wb_pio_dat_i[6]; // // Bit 7 - unknown error, no exception // if (exc_err7) reg_err[7] <= 1'b1; else if (sel_out & sel_04) reg_err[7] <= wb_pio_dat_i[7]; end // // Double error detectors // if (~exc_uop) exc_dbl[0] <= reg_err[1]; if (~qbus_tovf) exc_dbl[1] <= reg_err[4]; if (~exc_oat) exc_dbl[2] <= reg_err[6]; if (~exc_err7) exc_dbl[3] <= reg_err[7]; end always @(posedge pin_clk_p) begin if (~pin_sync_in) begin sel_xx <= sel177x; sel_00 <= sel177x & (pin_ad_in[3:1] == 3'b000); sel_02 <= sel177x & (pin_ad_in[3:1] == 3'b001); sel_04 <= sel177x & (pin_ad_in[3:1] == 3'b010); sel_06 <= sel177x & (pin_ad_in[3:1] == 3'b011); sel_10 <= sel177x & (pin_ad_in[3:1] == 3'b100); sel_12 <= sel177x & (pin_ad_in[3:1] == 3'b101); sel_14 <= sel177x & (pin_ad_in[3:1] == 3'b110); sel_16 <= sel177x & (pin_ad_in[3:1] == 3'b111); end end assign rply_s1 = sel_02 & sel_out & rply_s3; always @(posedge pin_clk_n) rply_s3 <= ~rply_s2; always @(posedge pin_clk_n) rply_s2 <= start_irq; always @(posedge pin_clk_p) begin // // Original circuit contains error // The start_irq request is reset by interrupt ack and EMT execution (last one is wrong) // if (reset | ((vsel[2:0] == 3'b110) & (plr[28:25] == 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]))) start_irq <= 1'b0; else if (rply_s1) start_irq <= 1'b1; end //______________________________________________________________________________ // // Interrupt controller // assign pli = VM1_CORE_MULG_VERSION ? pli_g : pli_a; vm1g_pli pli_matrix_g(.rq(rq), .sp(pli_g)); vm1a_pli pli_matrix_a(.rq(rq), .sp(pli_a)); always @(posedge pin_clk_p) begin rq[0] <= psw[10]; rq[1] <= plir[0]; // pli4r rq[2] <= psw[11]; rq[3] <= uop; rq[4] <= psw[7]; rq[9] <= qbto; rq[10] <= reg_err[0]; rq[11] <= pin_aclo & aclo; rq[12] <= reg_csr[2]; rq[13] <= ~pin_aclo & acok; rq[14] <= pin_irq[1]; rq[15] <= psw[4]; rq[16] <= pin_irq[2] & irq2; rq[17] <= ivto; rq[18] <= pin_irq[3] & irq3; // // Only master CPU processes vectored interrupts // Matrix accepts low level as active (asserted request) // rq[8] <= ~(pin_virq & (pin_pa == 2'b00)); // // Not used matrix inputs // rq[5] <= 1'b0; rq[6] <= 1'b0; rq[7] <= 1'b0; // // VE timer interrupt // rq[19] <= tve_irq; end // // Odd address trap detector is blocked on 1801BM1 // assign exc_oat = 1'b0; assign exc_uop = plm_ena & plr[12]; assign exc_err2 = plm1x_hl & ~plr[26]; assign exc_err3 = plm1x_hl & ~plr[28]; assign exc_err7 = plm1x_hl & ~plr[30]; always @(posedge pin_clk_p or posedge reset) begin if (reset) plir[0] <= 1'b0; else if (pli_stb) plir[0] <= pli[4]; end always @(posedge pin_clk_p) begin if (pli_stb) begin plir[1] <= pli[6]; plir[2] <= pli[8]; plir[3] <= pli[10]; end end // // Detector's reset // assign aclo_ack = plm1x_hl & ~plr[27] & ~plir[3] & ~plir[2] & plir[1]; assign uop_ack = plm1x_hl & ~plr[27] & ~plir[3] & ~plir[2] & ~plir[1]; assign irq2_ack = plm1x_hl & ~plr[27] & plir[3] & plir[2] & ~plir[1]; assign irq3_ack = plm1x_hl & ~plr[27] & plir[3] & ~plir[2] & ~plir[1]; assign tve_ack = plm1x_hl & ~plr[27] & plir[3] & ~plir[2] & plir[1]; // // ACLO edge detectors // always @(posedge pin_clk_p) begin if (reset | aclo_ack) aclo <= 1'b0; else if (~pin_aclo) aclo <= 1'b1; if (pin_dclo | aclo_ack) acok <= 1'b0; else if (pin_aclo) acok <= 1'b1; end // // IRQ2 and IRQ3 falling edge detectors // Also resettable by internal INIT // always @(posedge pin_clk_p) begin if (pin_init_out | pin_init_in) begin irq2 <= 1'b0; irq3 <= 1'b0; end else begin if (irq2_ack) irq2 <= 1'b0; else if (~pin_irq[2]) irq2 <= 1'b1; if (irq3_ack) irq3 <= 1'b0; else if (~pin_irq[3]) irq3 <= 1'b1; end end // // Error exception latches // always @(posedge pin_clk_p) begin if (reset | uop_ack) begin uop <= 1'b0; qbto <= 1'b0; ivto <= 1'b0; end else begin if (exc_uop) uop <= 1'b1; if (qbus_tovf & iako_out) ivto <= 1'b1; if (qbus_tovf | exc_oat) qbto <= 1'b1; end end assign pli_req_rc = plm23_ichk | abort; assign pli_nrdy = pli_req; assign pli_stb = pli_req; always @(posedge pin_clk_p) begin pli_req <= pli_req_rc; if (pli_stb) vsel <= {pli[3], ~pli[2], pli[1], pli[0]}; else if (plm1x) vsel <= {plr[18], ~plr[20], ~plr[21], ~plr[22]}; end always @(posedge pin_clk_p or posedge mjres) begin if (mjres) iak_flag <= 1'b0; else if (din_done) iak_flag <= 1'b0; else if (plm_ena & (plr[28:25] == 4'b0010) & (plr[11] | (plr[13] & ~plr[14])) & (vsel == 4'b1111)) iak_flag <= 1'b1; end //______________________________________________________________________________ // // Reset circuits // assign mjres_rc = reset_rc | abort_rc; assign reset_rc = pin_dclo | (pin_aclo & ~init_out[0] & init_out[2]); assign abort_rc = (qbus_tovf | exc_oat | exc_uop | abort) & ~abort_tm & ~reset_rc; always @(posedge pin_clk_p) begin reset <= reset_rc; mjres <= mjres_rc; mjres_h <= mjres; abort <= abort_rc; abort_tm <= abort & ~reset_rc; end always @(posedge pin_clk_p) begin if (reset_rc) init_out[0] <= 1'b0; else if (plm1x_hl) begin if (~plr[23]) init_out[0] <= 1'b0; else if (~plr[10]) init_out[0] <= 1'b1; end init_out[1] <= init_out[0]; init_out[2] <= init_out[1]; end //______________________________________________________________________________ // // Microcode state machine // assign plx = VM1_CORE_MULG_VERSION ? plx_g : plx_a; vm1g_plm plm_matrix_g(.ir(ir), .mr(mj), .sp(plx_g)); vm1a_plm plm_matrix_a(.ir(ir), .mr(mj), .sp(plx_a)); assign plm1x_fc = plm_ena_fc & ~plm[12] & (plm[11] & plm[13]); assign plm2x_fc = plm_ena_fc & ~plm[12] & ~(plm[11] & plm[13]); // irq check wait IR start IR Note assign plm23_fc[0] = plm_ena_fc & (plm[3:1] == 3'b001); // no yes no RTT opcode, wait fetch completion assign plm23_fc[1] = plm_ena_fc & (plm[3:1] == 3'b011); // yes yes yes usual IR fetch assign plm23_fc[2] = plm_ena_fc & (plm[3:1] == 3'b101); // yes no no WAIT opcode, check irq only assign plm23_fc[3] = plm_ena_fc & (plm[3:1] == 3'b111); // yes yes no ~RTT opcode, wait fetch completion always @(posedge pin_clk_n) begin plm23_wait <= plm23_fc[0] | plm23_fc[3]; plm23_ichk <= plm23_fc[1] | plm23_fc[2] | plm23_fc[3]; end assign plop[0] = ~plr[22] & ~plr[21] & ~plr[4]; // 000 assign plop[1] = ~plr[22] & ~plr[21] & plr[4]; // 001 assign plop[2] = ~plr[22] & plr[21] & ~plr[4]; // 010 assign plop[3] = ~plr[22] & plr[21] & plr[4]; // 011 assign plop[4] = plr[22] & ~plr[21] & ~plr[4]; // 100 assign plop[5] = plr[22] & ~plr[21] & plr[4]; // 101 assign plop[6] = plr[22] & plr[21] & ~plr[4]; // 110 assign plop[7] = plr[22] & plr[21] & plr[4]; // 111 always @(posedge pin_clk_n) begin plm1x <= plm1x_fc; plm2x <= plm2x_fc; plm1x_hl <= plm1x; if (plm_ena) begin psw_stb <= ~plop[0] & ~plop[2] & ~plop[7]; psw_stbc <= ~plop[0] & ~plop[1] & ~plop[2] & ~plop[3] & ~plop[7]; mj_stb1 <= (plop[7] & ir_stb2) | (~plop[1] & ~plop[5] & ~plop[7]); mj_stb2 <= (plop[7] & ir_stb2) | (~plop[1] & ~plop[5] & ~plop[7] & ~plop[3]); psw_mj <= plop[7] & ir_stb2; end end // // Instruction register // always @(posedge pin_clk_p) begin if (ir_stb1) ira <= wb_cpu_dat_i; if (ir_stb2) if (ir_stb1) ir <= wb_cpu_dat_i; else ir <= ira; end //______________________________________________________________________________ // always @(posedge pin_clk_n) begin if (plm_ena_fc) plr <= plm; end always @(posedge pin_clk_p) begin // // Other bits have no reset facility // if (plm_stb_rc) begin // // Some of plm is not used here (microcode address directly uses plx instead) // plm <= plx; end end //______________________________________________________________________________ // // Microcode register // always @(posedge pin_clk_p or posedge abort) begin // // The least bit is reset by abort // and set by common reset // if (abort) mj[0] <= 1'b0; else if (reset) mj[0] <= 1'b1; else if (plm_stb_rc) mj[0] <= ~plx[29]; end always @(posedge pin_clk_p or posedge mjres) begin // // Least bits are produced directly from main matrix // and have the async reset feature (next microcode address) // if (mjres) mj[6:1] <= 6'b111111; else if (plm_stb_rc) begin mj[1] <= ~plx[24]; mj[2] <= ~plx[19]; mj[3] <= plx[15]; mj[4] <= plx[9]; mj[5] <= plx[5]; mj[6] <= ~plx[0]; end end always @(posedge pin_clk_p) begin if (ustb1_hl) begin if (mj_stb1) begin mj[11] <= psw[4]; mj[10:8] <= psw_mj ? psw[3:1] : freg[3:1]; end if (mj_stb2) mj[7] <= psw_mj ? psw[0] : freg[0]; end end always @(posedge pin_clk_p or posedge mjres) begin // // Bits 14:12 poll the interrupt controller state // if (mjres) mj[14:12] <= 3'b000; else if (pli_stb) mj[14:12] <= {~pli[5], ~pli[7], pli[9]}; else if (plm1x) mj[14:12] <= {~plr[14], plr[16], ~plr[17]}; end //______________________________________________________________________________ // // ALU result flags and PSW // always @(posedge pin_clk_n) begin if (au_alsl) freg <= flag; end always @(posedge pin_clk_n or posedge reset) begin // // Start microcode correctly sets the PSW // But simulator can not calculate ALU function // correctly if PSW in initially undefined // // The PSW is written by microcode with 340 value // while executing reset sequence // if (reset) psw[15:0] <= {6'o00, pin_pa[1:0], 8'o000}; else begin if (au_alsl & au_pstbx) psw[7:0] <= x[7:0]; else begin // // Latch the ALU flag results immediately after ALU completion // Rollback to the original PSW logic // if (psw_stbc & ustb1_hl) psw[0] <= freg[0]; if (psw_stb & ustb1_hl) psw[3:1] <= freg[3:1]; // // This does not work correctly for MUL instruction - result flags are wrong // due to G-version microcode urges to write flags from ALU bus directly // (au_pstbx active) // // if (psw_stbc & au_alsl) // psw[0] <= flag[0]; // if (psw_stb & au_alsl) // psw[3:1] <= flag[3:1]; // end if (au_alsh & au_pstbx) begin psw[9:8] <= pin_pa[1:0]; psw[15:10] <= x[15:10]; end end end // // ALU general purpose registers // assign xr = VM1_CORE_REG_USES_RAM ? xr_rm : xr_ff; assign yr = VM1_CORE_REG_USES_RAM ? yr_rm : yr_ff; // // Implement the Register File with library RAM module // vm1_reg_ram vreg_rm( .clk_p(pin_clk_p), .clk_n(pin_clk_n), .reset(reset), .plr(plr), .xbus_in(x), .xbus_out(xr_rm), .ybus_out(yr_rm), .wstbl(au_alsl), .wstbh(au_alsh), .ireg(ir), .vsel(vsel), .pa(pin_pa), .carry(psw[0])); // // Implement the Register File with Flip-Flops array // The constant generator can be built in the File // in some implementations // vm1_reg_ff vreg_ff( .clk_p(pin_clk_p), .clk_n(pin_clk_n), .reset(reset), .plr(plr), .xbus_in(x), .xbus_out(xr_ff), .ybus_out(yr_ff), .wstbl(au_alsl), .wstbh(au_alsh), .ireg(ir), .vsel(vsel), .pa(pin_pa), .carry(psw[0])); assign au_pswy = (plr[28:25] == 4'b1000) & ~plr[11] & ~plr[13]; assign au_qsy = (plr[28:25] == 4'b0000) & ~plr[11] & ~plr[13]; assign au_pswx = (plr[33:30] == 4'b1000); assign au_qsx = (plr[33:30] == 4'b0000); always @(posedge pin_clk_n) au_alsl <= alu_busy_rp & ustb_h; always @(posedge pin_clk_n) au_alsh <= alu_busy_rp & ustb_h & plr[18]; assign au_is0 = ~(plr[13] & plr[14] & plr[25] & plr[26] & ~plr[27]); assign au_is1 = (plr[13] & plr[14] & plr[25] & plr[26] & ~plr[27]); assign au_qrdd = dout_ext; assign au_qstbd = iako_out | tplm[2]; assign au_pstbx = (plr[33:30] == 4'b1000) & plr[20]; // // Original strobes: // // assign au_astb = (au_alsl & ~(~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8])) // | ( ustb & (~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8])); // assign au_qstbx = (au_alsl & ~(~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]) // | ( ustb & (~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]); // // Speed-optimized strobes: // assign au_astb = au_astb_xa | (ustb & au_astb_xu); assign au_qstbx = au_qstb_xa | (ustb & au_qstb_xu); always @(posedge pin_clk_n) begin au_astb_xa <= alu_busy_rp & ustb_h & ~(~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8]); au_qstb_xa <= alu_busy_rp & ustb_h & ~(~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]; au_astb_xu <= (~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8]); au_qstb_xu <= (~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]; end // // X bus (12 entries) // AU_RSX0 - general purpose regs // AU_RSX1 - general purpose regs // AU_QSX - qbus temporary reg // AU_PSWX - PSW // // AU_ALSx - ALU result strobe (writeonly) // AU_ASTB - A address register (readonly) // AU_ASTB - A address register (readonly) // AU_QSTBX - Qbus temporary reg (readonly) // AU_QSTBX - Qbus temporary reg (readonly) // AU_IS0 - ALU X argument (readonly) // AU_IS1 - ALU X argument (readonly) // // Y bus, inverted (9 entries) // AU_RSY0 - general purpose regs // AU_RSY1 - general purpose regs // AU_QSY - Qbus temporary reg // AU_PSWY - PSW // // AU_ALSx - ALU result strobe (writeonly)) // AU_VSELY - vector generator (Y-writeonly) // AU_CSELY - constant generator (Y-writeonly) // ALU_U - ALU Y argument (readonly) // assign x[15:0] = au_alsl ? (au_alsh ? alu[15:0] : {8'o000, alu[7:0]}) : ( xr | (au_qsx ? qreg : 16'o000000) | (au_pswx ? psw : 16'o000000)); assign y[15:0] = ~(yr | (au_qsy ? qreg : 16'o000000) | (au_pswy ? psw : 16'o000000)); // // ALU qbus register // // Note: pin_clk_n has been changed to pin_clk_p to provide // valid data before nDOUT falling edge, but it reduced the Fmax // always @(posedge pin_clk_p) begin if (au_qstbx) qreg[7:0] <= x[7:0]; else if (au_qstbd) qreg[7:0] <= (au_ta0 ? wb_cpu_dat_i[15:8] : wb_cpu_dat_i[7:0]); if (au_qstbx) qreg[15:8] <= x[15:8]; else if (au_qstbd) qreg[15:8] <= wb_cpu_dat_i[15:8]; end always @(posedge pin_clk_n) begin if (au_astb) areg <= x; end // // Transaction address low bit latch // always @(posedge pin_clk_p) begin if (sync_stb) au_ta0 <= areg[0] & plrt[6]; end //______________________________________________________________________________ // // ALU function unit // assign nx = alu_x ? ~xreg : xreg; // // ALU input parameters (from X and Y buses) registers // always @(posedge pin_clk_n) begin if (au_is0) xreg[15:0] <= x[15:0]; else if (au_is1) xreg[15:0] <= {x[7:0], x[15:8]}; yreg <= y; end // // ALU controls // // plr[17:13] cl alu_b alu_c alu_d alu_e alu_x oxy axy h alu // 00x00 1 0 1 0 0 0 ~x|~y ~x&~y ~(x^y) x+y // 00x01 1 0 1 0 0 0 - - - - // 00x11 1 0 1 0 0 0 - - - - // 00x10 1 0 0 0 1 0 ~x|~y ~x ~(x&~y) x&~y // 01x00 0 0 1 0 0 1 x|~y x&~y x^y y-x // 01x01 0 0 1 0 0 1 - - - - // 01x11 0 0 1 0 0 1 - - - - // 01x10 0 0 1 0 1 0 ~x|~y ~x&~y ~(x^y) x^y // 10x00 1 1 1 0 1 0 ~x|y ~x&~y ~y y // 10x01 1 0 0 0 1 0 1 ~x ~x x // 10x10 1 0 1 0 1 0 1 ~x&~y ~(x|y) x|y // 10x11 1 0 0 0 1 0 1 ~x ~x x // 11x00 0 1 0 1 0 0 ~x|y ~x&y x^y x-y // 11x01 0 1 0 1 0 0 - - - - // 11x11 0 1 0 1 0 0 - - - - // 11x10 1 1 0 0 1 0 ~x|y ~x ~(x&y) x&y // assign cl_fc = ~plr[16] | (plr[17] & alu_e_fc); assign alu_b_fc = plr[17] & (plr[16] | (~plr[13] & ~plr[14])); assign alu_c_fc = (~plr[13] & (plr[16] ^ plr[17])) | (~alu_e_fc & ~plr[17]); assign alu_d_fc = ~alu_e_fc & plr[16] & plr[17]; assign alu_e_fc = (~plr[13] & plr[14]) | (~plr[16] & plr[17]); assign alu_x_fc = plr[16] & ~plr[17] & ~alu_e_fc; assign alu_s_fc = ~plr[13] | ~plr[14] | (plr[25] & plr[26]); always @(posedge pin_clk_n) begin cl <= cl_fc; alu_b <= alu_b_fc; alu_c <= alu_c_fc; alu_d <= alu_d_fc; alu_e <= alu_e_fc; alu_x <= alu_x_fc; alu_s <= alu_s_fc; end // // ALU selectable function // assign cpred = {c[14:0], cl}; assign c = (cpred & oxy) | (~cpred & axy & oxy); assign h = (~oxy & ~axy) | (oxy & axy); assign f = alu_e ? h : ~(cpred ^ h); // // ALU result shifter // assign fbit7 = fctl[1] & f[7] | fctl[3] & f[8] | fctl[7] & c[7] | fctl[5] & fbitc; assign fbit15 = fctl[2] & f[15] | fctl[6] & c[15] | fctl[4] & fbitc; assign fctl[1] = ~plr[25] & ~plr[26] & plr[27] & ~plr[18]; assign fctl[2] = ~plr[25] & ~plr[26] & plr[27]; assign fctl[3] = plr[27] & plr[18]; assign fctl[4] = plr[13] & plr[14] & ~plr[25] & plr[26] & plr[27]; assign fctl[5] = plr[13] & plr[14] & ~plr[25] & plr[26] & plr[27] & ~plr[18]; assign fctl[6] = plr[13] & plr[14] & plr[25] & ~plr[26] & plr[27]; assign fctl[7] = plr[13] & plr[14] & plr[25] & ~plr[26] & plr[27] & ~plr[18]; // // assign alu_shr = ~alu_s & plr[27]; // assign alu_shl = ~alu_s & ~plr[27]; // assign alu = ~(alu_s ? f : (plr[27] ? {fbit15, f[15:9], fbit7, f[7:1]} : {f[14:0], fbitc})); // // ALU result condition flags // assign flag[0] = alu_s ? ~fmux[0] : ~fmux[1]; // C assign flag[2] = (~plr[18] | (alu[15:8] == 8'o000)) & (alu[7:0] == 8'o000); // Z assign flag[3] = plr[18] ? alu[15] : alu[7]; // N assign flag[1] = ~(alu_s & alu_e) // V & ~(((fmux[1] ^ flag[3]) | alu_s) & (plr[18] ? (c[14] ^ ~c[15]) : (c[6] ^ ~c[7]))); assign fmux[0] = cl ? (alu_e | (plr[18] ? c[15] : c[7])) : ~(alu_e | (plr[18] ? c[15] : c[7])); assign fmux[1] = (f[0] | ~plr[27]) & (plr[27] | (plr[18] ? f[15] : f[7])); assign fbitc = ~(psw[0] & ~plr[25] & plr[26]); // // ALU and/or products // assign oxy = ~nx | ~((~plr[17] ? ~yreg : 16'o000000) | (alu_b ? yreg : 16'o000000)); assign axy = ~nx & ~(alu_d ? yreg : 16'o000000) & ~(alu_c ? ~yreg : 16'o000000); endmodule //______________________________________________________________________________ // // Vector address and constant generator // module vm1_vgen ( input [15:0] ireg, // instruction register input [3:0] vsel, // vector output selection input [3:0] csel, // constant output selection input vena, // vector output enable input cena, // constant output enable input carry, // carry flag psw[0] input [1:0] pa, // processor number output [15:0] value // output vector value ); reg [15:0] vmux; // variable for vector multiplexer reg [15:0] cmux; // variable for constant multiplexer // // On schematics vsel is {pli[3], ~pli[2], pli[1], pli[0]} // always @(*) begin case(vsel) 4'b0000: vmux = 16'o160006; // double error 4'b0001: vmux = 16'o000020; // IOT instruction 4'b0010: vmux = 16'o000010; // reserved opcode 4'b0011: vmux = 16'o000014; // T-bit/BPT trap 4'b0100: vmux = 16'o000004; // invalid opcode 4'b0101: // or qbus timeout case (pa[1:0]) // initial start 2'b00: vmux = 16'o177716; // register base 2'b01: vmux = 16'o177736; // depends on 2'b10: vmux = 16'o177756; // processor number 2'b11: vmux = 16'o177776; // default:vmux = 16'o177716; // endcase // 4'b0110: vmux = 16'o000030; // EMT instruction 4'b0111: vmux = 16'o160012; // int ack timeout 4'b1000: vmux = 16'o000270; // IRQ3 falling edge 4'b1001: vmux = 16'o000024; // ACLO falling edge 4'b1010: vmux = 16'o000100; // IRQ2 falling edge 4'b1011: vmux = 16'o160002; // IRQ1 low level/HALT 4'b1100: vmux = 16'o000034; // TRAP instruction 4'b1101: vmux = ireg; // instruction register 4'b1110: vmux = 16'o000000; // start @177704 4'b1111: vmux = 16'o000000; // unused vector (iako) default: vmux = 16'o000000; // endcase end // // Constant generator and opcode fields shifter/truncator // // On schematics csel is plr[28:25] // // csel0 = 4b'00xx // csel1 = 4b'01xx // csel2 = 4b'10xx // csel3 = 4b'11xx // csel4 = 4b'xx00 // csel5 = 4b'xx01 // csel6 = 4b'xx10 // csel7 = 4b'xx11 // always @(*) begin case(csel) 4'b0000: cmux = {12'o0000, ireg[3:0]}; // csel0 & csel4 (CLx/SEx) 4'b0001: cmux = 16'o000340; // csel0 & csel5 (start PSW constant) 4'b0010: cmux = 16'o000000; // csel0 & csel6 (vector output) 4'b0011: cmux = 16'o000002; // csel0 & csel7 4'b0100: cmux = {9'o000, ireg[5:0], 1'b0}; // csel1 & csel4 (MARK/SOB) 4'b0101: cmux = 16'o177716; // csel1 & csel5 4'b0110: cmux = 16'o177777; // csel1 & csel6 4'b0111: cmux = 16'o000001; // csel1 & csel7 4'b1000: // begin // csel2 & csel4 if (ireg[7]) // cmux = {7'o177, ireg[7:0], 1'b0}; // low byte x2 (BR/Bxx) else // sign extension cmux = {7'o000, ireg[7:0], 1'b0}; // for branches end // 4'b1001: cmux = 16'o100000; // csel2 & csel5 4'b1010: cmux = 16'o177676; // csel2 & csel6 4'b1011: cmux = 16'o000020; // csel2 & csel7 (MUL) 4'b1100: cmux = {15'o00000, carry}; // csel3 & csel4 (ADC/SBC) 4'b1101: cmux = 16'o177400; // csel3 & csel5 (start address AND) 4'b1110: cmux = 16'o000010; // csel3 & csel6 4'b1111: cmux = 16'o000000; // csel3 & csel7 (vector read/vsel) default: cmux = 16'o000000; endcase end assign value = (vena ? vmux : 16'o000000) | (cena ? cmux : 16'o000000); endmodule //______________________________________________________________________________ // // Register file, flip-flops implementation // module vm1_reg_ff ( input clk_p, // input clk_n, // input reset, // input [33:0] plr, // control matrix input [15:0] xbus_in, // X bus input output [15:0] xbus_out, // X bus output output [15:0] ybus_out, // Y bus output input wstbl, // write strobe low byte input wstbh, // write strobe high byte // input [15:0] ireg, // instruction register input [3:0] vsel, // interrupt vector selector input [1:0] pa, // processor number input carry // carry flag ); wire vc_vsel, vc_csel; reg [3:0] vc_vreg; wire [15:0] vc_vcd; // vector/constant data wire [13:0] rs0, rs1, rsw; // register select reg [15:0] gpr[0:13]; // register array reg [3:0] xadr; reg [3:0] yadr; always @(posedge clk_n) begin xadr <= plr[33:30]; yadr <= plr[28:25]; end always @(posedge clk_n) begin vc_vreg <= vsel; end assign vc_vsel = (plr[28:25] == 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); assign vc_csel = (plr[28:25] != 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); vm1_vgen vgen( .ireg(ireg), // instruction register .vsel(vc_vreg), // vector output selection .csel(plr[28:25]), // constant output selection .vena(vc_vsel), // vector output enable .cena(vc_csel), // constant output enable .carry(carry), // carry flag psw[0] .pa(pa), // processor number .value(vc_vcd) // output vector value ); assign rs0[0] = (yadr == 4'b1111) & ~plr[11] & ~plr[13]; assign rs0[1] = (yadr == 4'b0111) & ~plr[11] & ~plr[13]; assign rs0[2] = (yadr == 4'b1011) & ~plr[11] & ~plr[13]; assign rs0[3] = (yadr == 4'b0011) & ~plr[11] & ~plr[13]; assign rs0[4] = (yadr == 4'b1101) & ~plr[11] & ~plr[13]; assign rs0[5] = (yadr == 4'b0101) & ~plr[11] & ~plr[13]; assign rs0[6] = (yadr == 4'b1001) & ~plr[11] & ~plr[13]; assign rs0[7] = (yadr == 4'b0001) & ~plr[11] & ~plr[13]; assign rs0[8] = (yadr == 4'b1110) & ~plr[11] & ~plr[13]; assign rs0[9] = (yadr == 4'b0110) & ~plr[11] & ~plr[13]; assign rs0[10] = (yadr == 4'b1010) & ~plr[11] & ~plr[13]; assign rs0[11] = (yadr == 4'b0010) & ~plr[11] & ~plr[13]; assign rs0[12] = (yadr == 4'b1100) & ~plr[11] & ~plr[13] | (plr[13] & plr[14]); assign rs0[13] = (yadr == 4'b0100) & ~plr[11] & ~plr[13]; assign rs1[0] = (xadr == 4'b1111); assign rs1[1] = (xadr == 4'b0111); assign rs1[2] = (xadr == 4'b1011); assign rs1[3] = (xadr == 4'b0011); assign rs1[4] = (xadr == 4'b1101); assign rs1[5] = (xadr == 4'b0101); assign rs1[6] = (xadr == 4'b1001); assign rs1[7] = (xadr == 4'b0001); assign rs1[8] = (xadr == 4'b1110); assign rs1[9] = (xadr == 4'b0110); assign rs1[10] = (xadr == 4'b1010); assign rs1[11] = (xadr == 4'b0010); assign rs1[12] = (xadr == 4'b1100); assign rs1[13] = (xadr == 4'b0100); assign rsw[0] = (xadr == 4'b1111) & plr[20]; assign rsw[1] = (xadr == 4'b0111) & plr[20]; assign rsw[2] = (xadr == 4'b1011) & plr[20]; assign rsw[3] = (xadr == 4'b0011) & plr[20]; assign rsw[4] = (xadr == 4'b1101) & plr[20]; assign rsw[5] = (xadr == 4'b0101) & plr[20]; assign rsw[6] = (xadr == 4'b1001) & plr[20]; assign rsw[7] = (xadr == 4'b0001) & plr[20]; assign rsw[8] = (xadr == 4'b1110) & plr[20]; assign rsw[9] = (xadr == 4'b0110) & plr[20]; assign rsw[10] = (xadr == 4'b1010) & plr[20]; assign rsw[11] = (xadr == 4'b0010) & plr[20]; assign rsw[12] = (xadr == 4'b1100) | ~plr[20]; assign rsw[13] = (xadr == 4'b0100) & plr[20]; assign xbus_out = (rs1[0] ? gpr[0] : 16'o000000) | (rs1[1] ? gpr[1] : 16'o000000) | (rs1[2] ? gpr[2] : 16'o000000) | (rs1[3] ? gpr[3] : 16'o000000) | (rs1[4] ? gpr[4] : 16'o000000) | (rs1[5] ? gpr[5] : 16'o000000) | (rs1[6] ? gpr[6] : 16'o000000) | (rs1[7] ? gpr[7] : 16'o000000) | (rs1[8] ? gpr[8] : 16'o000000) | (rs1[9] ? gpr[9] : 16'o000000) | (rs1[10] ? gpr[10] : 16'o000000) | (rs1[11] ? gpr[11] : 16'o000000) | (rs1[12] ? gpr[12] : 16'o000000) | (rs1[13] ? gpr[13] : 16'o000000); assign ybus_out = (rs0[0] ? gpr[0] : 16'o000000) | (rs0[1] ? gpr[1] : 16'o000000) | (rs0[2] ? gpr[2] : 16'o000000) | (rs0[3] ? gpr[3] : 16'o000000) | (rs0[4] ? gpr[4] : 16'o000000) | (rs0[5] ? gpr[5] : 16'o000000) | (rs0[6] ? gpr[6] : 16'o000000) | (rs0[7] ? gpr[7] : 16'o000000) | (rs0[8] ? gpr[8] : 16'o000000) | (rs0[9] ? gpr[9] : 16'o000000) | (rs0[10] ? gpr[10] : 16'o000000) | (rs0[11] ? gpr[11] : 16'o000000) | (rs0[12] ? gpr[12] : 16'o000000) | (rs0[13] ? gpr[13] : 16'o000000) | (vc_vsel ? vc_vcd : 16'o000000) | (vc_csel ? vc_vcd : 16'o000000); always @(posedge clk_n) begin if (wstbl) begin if (rsw[0]) gpr[0][7:0] <= xbus_in[7:0]; if (rsw[1]) gpr[1][7:0] <= xbus_in[7:0]; if (rsw[2]) gpr[2][7:0] <= xbus_in[7:0]; if (rsw[3]) gpr[3][7:0] <= xbus_in[7:0]; if (rsw[4]) gpr[4][7:0] <= xbus_in[7:0]; if (rsw[5]) gpr[5][7:0] <= xbus_in[7:0]; if (rsw[6]) gpr[6][7:0] <= xbus_in[7:0]; if (rsw[7]) gpr[7][7:0] <= xbus_in[7:0]; if (rsw[8]) gpr[8][7:0] <= xbus_in[7:0]; if (rsw[9]) gpr[9][7:0] <= xbus_in[7:0]; if (rsw[10]) gpr[10][7:0] <= xbus_in[7:0]; if (rsw[11]) gpr[11][7:0] <= xbus_in[7:0]; if (rsw[12]) gpr[12][7:0] <= xbus_in[7:0]; if (rsw[13]) gpr[13][7:0] <= xbus_in[7:0]; end if (wstbh) begin if (rsw[0]) gpr[0][15:8] <= xbus_in[15:8]; if (rsw[1]) gpr[1][15:8] <= xbus_in[15:8]; if (rsw[2]) gpr[2][15:8] <= xbus_in[15:8]; if (rsw[3]) gpr[3][15:8] <= xbus_in[15:8]; if (rsw[4]) gpr[4][15:8] <= xbus_in[15:8]; if (rsw[5]) gpr[5][15:8] <= xbus_in[15:8]; if (rsw[6]) gpr[6][15:8] <= xbus_in[15:8]; if (rsw[7]) gpr[7][15:8] <= xbus_in[15:8]; if (rsw[8]) gpr[8][15:8] <= xbus_in[15:8]; if (rsw[9]) gpr[9][15:8] <= xbus_in[15:8]; if (rsw[10]) gpr[10][15:8] <= xbus_in[15:8]; if (rsw[11]) gpr[11][15:8] <= xbus_in[15:8]; if (rsw[12]) gpr[12][15:8] <= xbus_in[15:8]; if (rsw[13]) gpr[13][15:8] <= xbus_in[15:8]; end end // synopsys translate_off initial begin gpr[0] = 16'o000000; gpr[1] = 16'o000000; gpr[2] = 16'o000000; gpr[3] = 16'o000000; gpr[4] = 16'o000000; gpr[5] = 16'o000000; gpr[6] = 16'o000000; gpr[7] = 16'o000000; gpr[8] = 16'o000000; gpr[9] = 16'o000000; gpr[10] = 16'o000000; gpr[11] = 16'o000000; gpr[12] = 16'o000000; gpr[13] = 16'o000000; gpr[0] = 16'o000000; end // synopsys translate_on endmodule //______________________________________________________________________________ // // Register file, RAM implementation // module vm1_reg_ram ( input clk_p, // input clk_n, // input reset, // input [33:0] plr, // control matrix input [15:0] xbus_in, // X bus input output [15:0] xbus_out, // X bus output output [15:0] ybus_out, // Y bus output input wstbl, // write strobe low byte input wstbh, // write strobe high byte // input [15:0] ireg, // instruction register input [3:0] vsel, // interrupt vector selector input [1:0] pa, // processor number input carry // carry flag ); wire vc_vsel, vc_csel; reg [3:0] vc_reg; wire [15:0] vc_mux; wire [5:0] xadr; wire [5:0] yadr; wire wren; always @(posedge clk_n) begin vc_reg <= vsel; end assign vc_vsel = (plr[28:25] == 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); assign vc_csel = (plr[28:25] != 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); assign wren = (wstbl & (plr[32:30] != 3'b000) & plr[20]) | (wstbl & ~plr[20]); assign xadr[5:0] = {2'b00, wstbl ? (plr[20] ? plr[33:30] : 4'b1100) : plr[33:30]}; assign yadr[3:0] = vc_vsel ? vsel : (vc_csel ? plr[28:25] : ((plr[13] & plr[14]) ? 4'b1100 : ((~plr[11] & ~plr[13]) ? plr[28:25] : 4'b0000))); assign yadr[4] = vc_vsel; assign yadr[5] = vc_csel; vm1_vcram vm1_vcram_reg( .clock(clk_n), .address_a(xadr), .data_a(xbus_in), .q_a(xbus_out), .byteena_a({wstbh | ~wstbl, 1'b1}), .wren_a(wren), .address_b(yadr), .data_b(16'o000000), .wren_b(1'b0), .q_b(vc_mux)); assign ybus_out = vc_mux | ((vc_vsel & (vc_reg == 4'b0101)) ? {10'o0000, pa, 4'o00} : 16'o000000) | ((vc_vsel & (vc_reg == 4'b1101)) ? ireg : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b0000)) ? {12'o0000, ireg[3:0]} : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b0100)) ? {9'o000, ireg[5:0], 1'b0} : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b1000)) ? {ireg[7] ? 7'o177 : 7'o000, ireg[7:0], 1'b0} : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b1100)) ? {15'o00000, carry} : 16'o000000); endmodule //______________________________________________________________________________ //