//
// Copyright (c) 2014-2019 by 1801BM1@gmail.com
//______________________________________________________________________________
//
// Version of 1801BM2 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 vm2_qbus
#(parameter
//______________________________________________________________________________
//
// If VM2_CORE_FIX_PREFETCH is nonzero the PC2 prefetch bugfix is applied.
//
// Original 1801BM2 processor contains microcode bug at the following conditions:
// - two operands PDP-11 instruction is being executed
// - source has addressing method @PC, -(PC) or @-(PC)
// - destination does not involve PC (dst register field !=7)
// - no extra instruction words are used by destination (no E(Rn), @E(Rn))
// - Q-bus is slow and opcode prefetch is not completed before microcode
// starts source field  processing and fetching the source data (slow RPLY/AR)
//
// The bug is related to inapropriate handling of buffer instruction register,
// if Q-bus slow and the prefetch is in not complete the CPU waits for completion
// and requests the another prefetch to BIR. The microcode fix is very complicated
// hence the approach to wait prefectch completion was chosen.
//
// If zero parameter is specified the model follows the original 1801BM2 behaviour
// (with prefetch bug).
//
   VM2_CORE_FIX_PREFETCH = 0
)
(
   input          pin_clk_p,     // positive edge clock
   input          pin_clk_n,     // negative edge clock
                                 //
   output         pin_init,      // peripheral reset output
   input          pin_dclo,      // processor reset
   input          pin_aclo,      // power fail notificaton
   input          pin_halt,      // halt mode interrupt
   input          pin_evnt,      // timer interrupt requests
   input          pin_virq,      // vectored interrupt request
                                 //
   input          pin_ar,        // address ready
   input          pin_dmr,       // bus grant request
   input          pin_sack,      // bus grant acknowlegement
   input          pin_rply,      // transaction acknowlegement
                                 //
   output         pin_clko,      // internal clock output
   output         pin_dmgo,      // bus grant
   output         pin_sel,       // halt mode access
   output         pin_iako,      // interrupt vector input
                                 //
   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
   output         pin_ctrl_ena,  //
                                 //
   output         pin_sync,      // address strobe
   output         pin_wtbt,      // write/byte status
   output         pin_dout,      // data output strobe
   output         pin_din        // data input strobe
);

//______________________________________________________________________________
//
reg            virq, halt, evnt;       // interrupt requests
reg            dclo, aclo;             // cold reset, power monitor
reg            aclo_stb, aclo_res;     //
                                       //
reg            ac0;                    // initial ACLO rising edge detected
reg            dble_cnt0;              // double QBUS timeout error counter
reg            dble_cnt1;              //
reg            evnt_fall;              // EVNT  rising edge detector
reg            aclo_fall;              // ACLO falling edge detector
reg            aclo_rise;              // ACLO rising edge detector
                                       //
wire           evnt_ack;               // clear system timer request
wire           aclo_ack;               // clear system ACLO requests
wire           tovf_ack;               // clear Q-bus timeout request
                                       //
reg            acok_rq;                // nACLO rise interrupt request
reg            aclo_rq;                // nACLO fall interrupt request
reg            tout_rq;                // bus timeout exception request
reg            dble_rq;                // double bus timeout request
reg            evnt_rq;                // system timer interrupt request
reg            vec_stb;                // vector interrupt acknowlegement
                                       //
wire  [15:0]   ad;                     // internal address/data bus
reg            ad_oe;                  // external AD pins output enable
reg            ct_oe;                  //
                                       //
wire           bus_free;               //
wire           bus_adr;                // address on ad bus strobe
reg            bus_dat;                // data on ad bus strobe
wire           bfree;                  //
                                       //
wire           sel, sel1;              //
reg            sel2;                   //
                                       //
wire           init;                   //
reg            init_out;               //
reg            dmgo_out;               //
wire           dmgo;                   //
reg            dmr;                    //
wire           ar;                     //
wire           sack;                   //
wire           iako;                   //
reg            iako_out;               //
wire           wtbt_out;               //
wire           rplys;                  //
reg            irply;                  // input pin strobe
wire           rply;                   //
reg            rply0, rply1;           //
reg            rply2, rply3;           //
reg            din;                    //
reg            dout, dout_s0;          //
reg            sync, sync_s0;          //
reg            ardy, ardy_s0;          //
reg            adr_req;                //
reg            drdy;                   //
reg            sk;                     //
wire           sync_clw;               //
wire           sync_set;               //
wire           ua_rply;                //
wire           rdat;                   //
                                       //
wire           io_start;               // start IO transaction
wire           io_rdy;                 //
wire           in_ua;                  //
wire           io_in;                  // prefetch cmd & read data
wire           io_wr;                  //
wire           io_rd;                  //
wire           io_sel;                 //
wire           io_wri;                 //
wire           io_iak;                 //
wire           io_alt;                 //
wire           io_x001;                //
wire           io_rcd;                 //
reg            io_rcd1;                //
wire           io_rcd1_xt;             //
wire           io_cmd;                 //
reg            io_cmdr;                //
reg            io_rcdr;                //
reg            io_pswr;                //
                                       //
reg            iop_wr;                 //
reg            iop_rd;                 //
reg            iop_in;                 // prefetch cmd & read data
reg            iop_rcd;                //
reg            iop_sel;                // halt mode access
reg            iop_iak;                //
reg            iop_una;                // unaddressed access
reg            iop_word;               //
wire           iop_stb;                // IO opcode strobe
                                       //
wire           reset;                  // system reset
wire           abort;                  // abort by bus timeout
wire           mc_res;                 // microcode reset
wire           mc_stb;                 // mc read phase strobe
wire           mw_stb;                 // mc write phase strobe
wire           pi_stb_rc;              // peripheral strobe
reg            pi_stb;                 //
wire           all_rdy;                //
reg            all_rdy_t0;             //
reg            all_rdy_t1;             //
reg            alu_nrdy;               // ALU not ready
reg            sta_nrdy;               // branch state not ready
reg            cmd_nrdy;               // instruction completion
wire           pli_nrdy;               // interrupt polling not ready
reg            tim_nrdy0;              // wait abort exception status
reg            tim_nrdy1;              // wait nINIT pulse generation
wire           mc_rdy, mc_rdy_rc;      //
reg            br_iocmd;               // instruction read IO in progress
reg            br_ready;               // breg contains valid read instruction
reg            ir_stb;                 //
wire           bir_stb;                //
wire           bra_req;                //
wire           mdfy;                   // write modifies prefetched location
wire           tena;                   // Q-bus timer count enable
wire           tovf;                   // Q-bus timeout interrupt
wire           thang;                  //
                                       //
reg            rta_fall;               //
wire           rta, creq;              //
reg            get_state;              //
wire           wt_state_rc;            //
wire           set_cend_rc;            //
reg            set_cend;               // set command end flag
reg            acmp_en;                // PC address comparator enable
                                       //
wire           din_set, dout_set;      //
reg            din_clr, dout_clr;      //
wire           dout_clr_fc;            //
wire           sync_clr;               //
wire           rcmd_set;               //
wire           din_clr_rc;             //
                                       //
reg   [15:0]   ireg;                   // primary instruction register
reg   [15:0]   breg;                   // prefetch instruction register
reg   [5:0]    ia;                     // microinstuction address register
reg   [2:0]    ri;                     // interrupt acknowlegement register
reg   [2:0]    ix;                     // auxiliary conditions register
                                       //
reg   [11:0]   br;                     // branch processing matrix input register
wire  [15:0]   qri;                    // interrupt processing matrix input aliases
wire  [9:0]    pli;                    // interrupt priority encode matrix output
wire  [11:0]   pld;                    // preliminary instruction decoder matrix output
wire           plb;                    // branch processing matrix output
                                       //
wire  [5:0]    na_rc;                  //
reg   [5:0]    na;                     // microcode next address field
reg   [30:0]   plm;                    // main matrix result register (first stage)
reg   [30:21]  plm_wt;                 //
wire  [30:21]  plr;                    //
wire  [36:0]   pla;                    //
                                       //
reg   [4:0]    plm_rn;                 //
wire  [6:0]    rn_wa;                  //
wire           pc2_wa;                 //
wire  [7:7]    wa;                     //
wire           wa_pc;                  // program counter selected
wire           wa_r1, wa_r2;           //
wire           ra_wa;                  // write address register from X*-bus
wire           ra_wx;                  // write address register from X-bus
reg            ra_fw;                  //
wire           ra_fwn;                 //
wire           ra_fr, ra_fr1;          //
wire           ra_fr_rc, ra_fwn_rc;    //
wire           pc1_wr, pc_wax;         //
wire           pc_wr;                  //
wire           rs_wa, acc_wa;          //
wire           cpsw_wa;                //
wire           cpsw_stb;               //
wire           ea1_wa, ea2_wa;         //
wire           ea_ctld;                //
wire           pswt_wa;                //
wire           psw_wa, psw8_wa;        //
wire           psw_stb, pswc_stb;      //
wire           wr_psw;                 //
wire           brd_rql, brd_rqh;       //
wire           qd_swap;                //
wire           qswp, rd2h;             //
reg            qa0;                    //
reg            wr7;                    // read command start cycle
                                       //
reg   [15:0]   cmux;                   // constant generator multiplexer
wire  [3:0]    csel;                   // constant generator selector
reg   [7:0]    vmux;                   // vector generator multiplexer
wire  [3:0]    vsel;                   // vector generator selector
                                       //
reg   [15:0]   ea22;                   // extended arithmetics register 2.2
reg   [15:0]   ear1;                   // extended arithmetics register 1
reg   [15:0]   ear2;                   // extended arithmetics register 2
reg   [15:0]   acc;                    // accumulator
reg   [15:0]   sreg;                   // source register
reg   [15:0]   r[6:0];                 // general purpose register files
reg   [15:0]   pc2;                    // prefetch PC pointer
reg   [15:0]   pc1;                    // actual PC pointer
reg   [15:0]   cpc;                    // copy of PC saved for halt mode
wire  [8:0]    psw_rc;                 //
reg   [8:0]    psw;                    // PSW
reg   [8:0]    cpsw;                   // PSW copy
reg   [15:0]   qreg;                   // ALU Q register (Q-bus data)
reg   [15:0]   areg;                   // ALU A register (Q-bus address)
                                       //
wire  [15:0]   alu_inx;                // ALU X operand selector
wire  [15:0]   alu_iny;                // ALU Y operand selector
wire  [15:0]   alu_an;                 // ALU operands 'and'
wire  [15:0]   alu_or;                 // ALU operands 'or'
wire  [15:0]   alu_cf;                 // ALU carry
wire  [15:0]   alu_cp;                 //
wire  [15:0]   alu_af;                 // ALU function
wire  [15:0]   alu_sh;                 //
reg   [15:0]   alu_fr;                 // ALU function register
reg   [15:0]   alu_cr;                 // ALU carry register
reg   [15:0]   xb;                     // ALU result register
wire  [15:0]   xbo;                    // byte xchanger output
wire  [15:0]   ax;                     // ALU X* output bus
reg   [15:0]   x;                      // ALU X input multiplexer
reg   [15:0]   y;                      // ALU Y input multiplexer
                                       //
wire           alu_cin;                //
wire           alu_a, alu_b;           // ALU function controls
wire           alu_c, alu_d;           //
wire           alu_e, alu_f;           //
wire           alu_g;                  //
wire           rshift, lshift, nshift; // ALU shifter controls
wire           sh_ci1, sh_ci2, sh_ci3; //
wire           alu_xb;                 //
                                       //
wire           sf_sum;                 //
reg            sf_inv, sf_dir;         //
reg            sf_lr, sf_rr;           //
reg            sf_sub;                 //
reg            sf_byte;                //
reg            sf_xchg;                //
reg            sxt_y;                  //
wire           sxt_rxy;                //
wire           axy_wh;                 //
wire           adr_eq;                 //
                                       //
wire           zl, zh, eq1;            //
wire           ea_22z;                 //
reg            ea_20r;                 //
                                       //
wire           cond_c0;                //
wire           cond_c1;                //
wire           cond_c2;                //
                                       //
wire           cond_c;                 //
wire           cond_v;                 //
wire           cond_z;                 //
wire           cond_n;                 //
                                       //
wire           plm1m;                  //
wire           plm13m;                 //
wire           plm14m;                 //
wire           plm18m;                 //
wire           plm19m;                 //
wire           plm20m;                 //
                                       //
wire           en_alu_rc;              //
wire           mc_drdy, mc_drdy_rc;    //
reg            mc_drdy0, mc_drdy1;     //
reg   [2:0]    alu_st;                 // ALU state machine
reg   [5:0]    iocmd_st;               //
reg   [1:0]    iopc_st;                //
reg   [5:1]    io_st;                  //
reg            buf_res;                //
reg            bir_fix;                // need prefetch fix needed decoded
wire           wr1;                    // ALU read args phase strobe
wire           wr2;                    // ALU write result phase strobe
wire           ad_rd;                  // external AD pins read enable
wire           alu_wr;                 // ALU write result
wire           brd_wq;                 // buffer data register write from Q-bus
wire           brd_wa;                 // buffer data register write from ALU
                                       //
reg            pli_arq;                // interrupt query after IO abort
reg            pli_ack;                // interrupt module ack
wire           pli_req;                // interrupt module query
wire           sd_word;                //
reg            word27;                 //
wire           rd_end;                 //
reg            pli6r;                  //
reg            pli8r;                  //
reg            wcpu;                   //
reg            tbit;                   //
                                       //
reg            dc_b7;                  //
wire           dc_f2;                  //
wire           dc_i7;                  //
wire           dc_j7;                  //
wire           dc_bi;                  //
wire           dc_fl;                  //
wire           dc_aux;                 //
reg            dc_fb;                  //
reg            dc_rtt;                 //
reg            dc_mop0;                //
reg            dc_mop1;                //
wire           alt_cnst;               //
                                       //
reg            ea_nrdy;                // EA unit internal operations
wire           ea_shr;                 //
wire           ea_vdiv;                //
wire           ea_mxin;                //
reg            ea_mxinr;               //
wire           ea_muls;                //
wire           sh_cin;                 //
wire  [15:0]   ea_mux;                 //
wire           ea_sh2;                 //
wire           ea_shl;                 //
wire           ea_shr2;                //
wire           ea_div;                 //
wire           ea_mul;                 //
wire           ea_mop0, ea_mop1;       //
wire           ea_rdy;                 //
reg            ea_trdy0, ea_trdy1;     //
wire           ea_trdy0_set;           //
wire           ea_trdy0_clr;           //
wire           ea_trdy1_clr;           //
reg            ea_trdy2_clr;           //
                                       //
reg            tlz;                    //
reg            wait_div;               //
reg            zero_div;               //
reg            div_vfr;                // sticky division overflow flag
wire           div_vf;                 // result division overflow flag
                                       //
reg   [4:0]    ea_ct;                  // internal EA phase counter
reg            ea_1t, ea_1tm, ea_1tc;  // first cycle after counter load
wire  [20:0]   ea_f;                   // counter phases
reg            ea_f0r, ea_f4r;         //
reg            ea_fn23r;               //
wire           ea_fn12;                //
wire           ea_f218;                //
wire           ea_ctse;                //
                                       //
wire           eas_dir;                //
wire           eas_left;               //
wire           eas_right;              //
                                       //
reg            bra;                    //
reg            bra_stb;                //
wire           ws_cend, ws_wait;       //
                                       //
reg   [8:0]    qtim;                   // Q-bus/nINIT timer counter
reg            tend;                   // Q-bus/nINIT timer counting end pulse
reg            tadone;                 // suppress repetitive timeout aborts
reg            tabort;                 // Q-bus false reply strobe
reg            tevent;                 // Q-bus timeout exception request
wire           tout;                   // Q-bus/nINIT timer 1/64 pulses
                                       //
reg            br_cmdrq;               // breg read cmd request
wire           to_block;               // block false reply on timeout
wire           wra;                    //
wire           wtbt;                   //
reg            to_rply;                //
                                       //
//______________________________________________________________________________
//
// Strobe shift descriptions.
//
// Original strobes were extended and shifted in various way to convert the
// design to synchronous one and improve speed characteristics. Here the strobe
// mofifications are documented. R/F means rising/falling edge of primary clock
// R2/F2 means rising/falling edge of secondary clock (90 degree shifted)
//
//             Original    Synch
// wr1         F2-R2       R-R
// wr2         F-R         R-R
// wra         F-R         R-R
// iop_stb     F-R         R-R
// iop_start   F-R         R-R
// alu_wr      F-R         R-R
// mc_stb      F-R         R-R
// mw_stb      R-F         R-R
// pi_stb      R-F         R-R
// sync_clr    R-F         R-R
//______________________________________________________________________________
//
// Saved original strobe assignments for reference purposes
//
// assign iop_stb    = (io_st[2] & ~io_st[4] & io_st[5]) | (~io_st[1] & io_start);
// assign io_start   = wra | (wr2 & iop_una);
// assign wr2        = alu_st[2] & ~alu_st[1];
// assign wra        = (ra_wx | ra_wa) & ~to_block
//                   & (plr[21] | plr[22] | plr[23])
//                   & (~dc_mop0 | ~dc_mop1 | ~io_x001);
// assign mc_stb     = all_rdy_t0 & all_rdy_t1;
// assign mw_stb     = alu_st[0] & ~alu_st[1];
// assign alu_wr     = alu_st[1] & ~alu_st[2] & ea_rdy;
// assign pi_stb     = ~plm[0] & ~all_rdy_t0 & all_rdy_t1;
// assign sync_clr    = mc_res | (~iop_wr & ~rply3 & rply2);
// assign mc_rdy     = alu_nrdy & plm[0];
// assign mc_drdy    = ~plm[27] | mc_drdy1;
//______________________________________________________________________________
//
// Extrenal pin assignments
//
assign pin_ad_out    = ad;
assign pin_ad_ena    = ad_oe & ~sack;
assign pin_init      = init;
assign pin_dmgo      = dmgo_out;
assign pin_sel       = sel;
assign pin_iako      = iako;

assign pin_ctrl_ena  = ct_oe;
assign pin_sync      = sync;
assign pin_wtbt      = wtbt_out;
assign pin_dout      = dout;
assign pin_din       = din;

//______________________________________________________________________________
//
// Reset and phase clock generator
//
assign pin_clko = ~pin_clk_p;

always @(posedge pin_clk_p)
begin
   dclo <= pin_dclo;
   aclo <= pin_aclo;
end

always @(posedge pin_clk_p) aclo_stb <= aclo;
always @(posedge pin_clk_n) aclo_res <= aclo;

assign init = init_out | dclo;
always @(posedge pin_clk_p)
begin
   if (reset | tout)
      init_out <= 1'b0;
   else
      if (pi_stb & plm[13])
         init_out <= 1'b1;
end

always @(posedge pin_clk_p)
begin
   //
   // ac0 flag is introduced to wait nACLO raise
   // reset will not be deasserted till the nACLO rise
   //
   if (reset)
      ac0 <= 1'b0;
   else
      if (pli_ack)
         ac0 <= pli[3];
end

assign reset = dclo | (~ac0 & aclo_res);
assign mc_res = abort | reset;
//______________________________________________________________________________
//
// Interrupt inputs latches
//
always @(posedge pin_clk_p)
begin
   evnt <= pin_evnt & ~init;
   halt <= pin_halt;
   virq <= pin_virq;
end

//______________________________________________________________________________
//
always @(posedge pin_clk_n) dmr <= pin_dmr;
always @(posedge pin_clk_p) dmgo_out <= dmgo;

assign sel  = (sel2 & bus_adr) | sel1;
assign sel1 = (iop_sel | iop_stb & io_sel) & din;
always @(posedge pin_clk_n)
begin
   if (wra)
      sel2 <= psw[8] ^ io_alt;
   else
      if (mc_res)
         sel2 <= 1'b1;
end

//______________________________________________________________________________
//
// Internal multiplexed address/data bus
//
assign ad   = (bus_adr ? areg : 16'o000000)
            | (brd_rql ? {8'o000, qreg[7:0]} : 16'o000000)
            | (brd_rqh ? {qreg[15:8], 8'o000} : 16'o000000);

always @(posedge din or posedge pin_clk_n)
begin
   if (din)
      ad_oe <= 1'b0;
   else
      if (sack)
         ad_oe <= 1'b0;
      else
         ad_oe <= 1'b1;
end

always @(posedge pin_clk_n)
begin
   if (sack)
      ct_oe <= 1'b0;
   else
      if (bfree)
         ct_oe <= 1'b1;
end

//______________________________________________________________________________
//
// QBus state machine
//
assign ar   = pin_ar;
assign sack = pin_sack;

assign wtbt_out =  (bus_adr & wtbt) | (bus_dat & ~iop_word);
assign iako = iop_iak & din & iako_out;

always @(posedge pin_clk_n) iako_out <= iop_iak & din;
//
// Hold interrupt ackonwledge cycle flag on bus timeout
// to allow interrupt matrix recognize vector timeout
// and provide the correct vector SEL 274
//
always @(posedge pin_clk_p)
begin
   if (tovf_ack | tovf | ~tout_rq)
      vec_stb <= iako_out;
end

always @(posedge din_set or posedge pin_clk_p)
begin
   if (din_set)
      din <= 1'b1;
   else
      if (din_clr_rc | mc_res | ~ct_oe)
         din <= 1'b0;
end

always @(posedge mc_res or posedge pin_clk_n)
begin
   if (mc_res)
      dout_s0 <= 1'b0;
   else
      if (dout_clr_fc)
         dout_s0 <= 1'b0;
      else
         if (dout_set)
            dout_s0 <= 1'b1;
end

always @(negedge dout_s0 or posedge pin_clk_p)
begin
   if (~dout_s0)
      dout <= 1'b0;
   else
      if (~mc_res)
         dout <= 1'b1;
end

assign rta        = sync & ~ardy;
assign creq       = sync_s0 | adr_req;
assign dmgo       = dmr & ~ct_oe & ~sync_s0 & ~in_ua;
assign bfree      = ~sync & ~ar & (ardy | ~(irply | to_rply | ua_rply));
assign bus_free   = bfree & ~dmr & ct_oe;
assign bus_adr    = (~sync | ~ardy_s0) & (sync_s0 | sync_set);

assign brd_rqh    = bus_dat & (iop_word |  qa0);
assign brd_rql    = bus_dat & (iop_word | ~qa0);
assign qd_swap    = qa0;

always @(posedge pin_clk_n)
begin
   if (sync_s0 & ~ardy_s0 | mc_res)
      rta_fall <= 1'b0;
   else
      if (wra)
         rta_fall <= 1'b1;
end

always @(posedge pin_clk_p)
begin
   if (sync_clr)
      qa0 <= 1'b0;
   else
      if (bus_adr)
         qa0 <= areg[0] & ~iop_word;
end

always @(posedge mc_res or posedge pin_clk_p)
begin
   if (mc_res)
      bus_dat <= 1'b0;
   else
      if (dout_clr)
         bus_dat <= 1'b0;
      else
         if (~rply & ardy & (drdy | brd_wa) & (wtbt | dout_clr))
            bus_dat <= 1'b1;
end

assign sync_set = bus_free & adr_req;
assign sync_clw = (wtbt | dout_clr) & sync_clr;
assign sync_clr = mc_res | (~iop_wr & ~rply3 & rply1);

always @(posedge pin_clk_n) sync <= sync_s0;
always @(posedge mc_res or posedge pin_clk_p)
begin
   if (mc_res)
      sync_s0 <= 1'b0;
   else
      if (~ct_oe | sync_clr)
         sync_s0 <= 1'b0;
      else
         if (sync_set)
            sync_s0 <= 1'b1;
end

always @(posedge pin_clk_p) ardy_s0 <= sync & (ar | ardy_s0);
always @(posedge pin_clk_n) ardy <= ardy_s0;
always @(posedge pin_clk_n)
begin
   if (mc_res | to_block | (sync_s0 & ~ardy_s0))
      adr_req <= 1'b0;
   else
      if (wra)
         adr_req <= 1'b1;
end

assign ua_rply = (din | dout) & sel1;
assign rply    = (irply | to_rply | ua_rply) & ~rply3;

always @(posedge pin_clk_n) to_rply <= iop_rcd & ~word27 & tabort & ~to_rply;
always @(posedge pin_clk_n) irply <= pin_rply;

assign rdat       = iop_rd & rply0 & ~rply2;
assign rplys      = ~in_ua & (~sync_s0 | ~ardy_s0);
assign in_ua      = (iop_sel | iop_stb & io_sel | iop_iak) & (din | (~adr_req & bus_free));

assign io_iak     = (plr[24:21] == 4'b1111);    // Interrupt acknowlegement
assign io_sel     = (plr[24:21] == 4'b1011)     // Unaddressed read
                  | (plr[24:21] == 4'b1101);    //
assign io_rcd     = (plr[24:21] == 4'b0111);    // Read command ahead
assign io_cmd     = (plr[24:21] == 4'b0010)     // Read command
                  | (plr[24:21] == 4'b0110);    //
assign io_wri     = (plr[24:21] == 4'b0100)     // Write data
                  | (plr[24:21] == 4'b0101);    // Write alt data
assign io_alt     = (plr[24:21] == 4'b0011)     // Read alternating space
                  | (plr[24:21] == 4'b0101);    // Write alternating space
assign io_x001    = (plr[24:21] == 4'b0001)     // Operation is defined
                  | (plr[24:21] == 4'b1001);    // by dc_mop field

assign io_wr      = (io_x001 & ~dc_mop1) | io_wri;
assign io_rd      = (io_x001 & ~dc_mop0) | plr[22];
assign io_in      = io_rcd | (io_rd & ~io_cmd);

assign dout_set   = ~dout_clr & bus_dat;
assign din_set    = ~din_clr_rc & (iop_rd | io_rd & iop_stb) & ~rplys & ~rply3;
assign wtbt       = ~din_clr_rc & ~iop_rd & iop_wr;

assign io_rcd1_xt = ra_fr1 & na[1];
always @(posedge pin_clk_n)
begin
   if (wr2) io_rcd1 <= io_rcd1_xt;
   if (mw_stb) iop_una = io_iak | io_sel;
end

always @(posedge pin_clk_p)
begin
   if (sync_clr)
      iop_in <= 1'b0;
   else
      if (iop_stb & io_in)
         iop_in <= 1'b1;

   if (sync_clr | to_rply)
      iop_rcd <= 1'b0;
   else
      if (iop_stb & io_rcd)
         iop_rcd <= 1'b1;

   if (iop_stb)
      iop_word <= ~dc_fb | ~plr[30];

   if (sync_clr)
      iop_sel <= 1'b0;
   else
      if (iop_stb)
         iop_sel <= io_sel;

   if (sync_clr)
      iop_iak <= 1'b0;
   else
      if (iop_stb)
         iop_iak <= io_iak;

   if (din_clr_rc)
      iop_rd <= 1'b0;
   else
      if (iop_stb)
         iop_rd <= io_rd;
end

always @(posedge dout_clr or posedge pin_clk_p)
begin
   if (dout_clr)
      iop_wr <= 1'b0;
   else
      if (iop_stb)
         iop_wr <= io_wr;
end

assign dout_clr_fc = ~(rply2 | ~rply0) & (wtbt | dout_clr);
always @(posedge pin_clk_n) dout_clr = dout_clr_fc;

always @(posedge rply3 or posedge pin_clk_p)
begin
   if (rply3)
      din_clr <= 1'b0;
   else
      if (reset)
         din_clr <= 1'b0;
      else
         if (din_clr_rc)
            din_clr <= 1'b1;
end
assign din_clr_rc = ~(rply3 | ~rply1);

always @(posedge pin_clk_n) rply1 <= rply0 & rply & ~rplys;
always @(posedge pin_clk_p) rply2 <= rply1 | (rply | rply1) & rply2;
always @(posedge pin_clk_n) rply3 <= rply2;

always @(posedge rply3 or posedge pin_clk_p)
begin
   if (rply3)
      rply0 <= 1'b0;
   else
      rply0 <= rply & ~rplys;
end

always @(posedge pin_clk_p)
begin
   if (sync_clr)
      drdy <= 1'b0;
   else
      if (brd_wa)
         drdy <= 1'b1;
end

//______________________________________________________________________________
//
// Q-bus timer, also involved in INIT command pulse timing
//
assign tout  = qtim[0] & qtim[2] & qtim[4] & qtim[5];

always @(posedge pin_clk_n)
begin
   if (!tena)
      qtim <= 9'o000;
   else
      qtim <= qtim + 9'o001;
   //
   // Single shot pulse at the timer counting ends
   //
   if (!tena | tend)
      tend <= 1'b0;
   else
      tend <= (qtim == 9'o776);
   //
   // Q-bus false reply strobe
   //
   if (!tena | tabort | tend | tadone)
      tabort <= 1'b0;
   else
      tabort <= ~tim_nrdy1 & qtim[0] & qtim[2] & qtim[4] & qtim[5];

   //
   // Suppress multiple timeout abort requests
   //
   if (!tena)
      tadone <= 1'b0;
   else
      if (tabort)
         tadone <= 1'b1;

   tevent <= tabort & (~iop_rcd | word27);
end

//______________________________________________________________________________
//
// QBus and INIT timer counter
//
assign tena     = ~reset & (pli_nrdy | din | dout);
assign tovf     = tevent | thang;
assign pli_nrdy = tend | tim_nrdy0 | tim_nrdy1;

always @(posedge pin_clk_p)
begin
   //
   // tim_nrdy0 is used to stop mcu for waiting
   // Q-bus abort exception status from interrupt unit
   //
   if (reset | pli_arq & ~abort)
      tim_nrdy0 <= 1'b0;
   else
      if (abort)
         tim_nrdy0 <= 1'b1;
end

always @(posedge pin_clk_n)
begin
   //
   // tim_nrdy1 is used to stop mcu for waiting
   // nINIT pusle generating completion
   //
   if (reset | tend)
      tim_nrdy1 <= 1'b0;
   else
      if (pi_stb & plm[13])
         tim_nrdy1 <= 1'b1;
end

//______________________________________________________________________________
//
assign adr_eq  = ~acmp_en | (pc1 == areg);
assign mdfy = acmp_en & adr_eq;
always @(posedge pin_clk_p) acmp_en <= wra & io_wr;

always @(posedge pin_clk_n) if (alu_wr) io_rcdr <= io_rcd;
always @(posedge pin_clk_n) if (alu_wr) io_cmdr <= io_cmd;
always @(posedge pin_clk_n)
begin
   if (reset | sync_clw)
      io_pswr <= 1'b0;
   else
      if (wra & io_wr & ~na[0])
         io_pswr <= 1'b1;
end

//______________________________________________________________________________
//
// Instruction registers - primary and preliminary decoder
//
always @(posedge pin_clk_p)
begin
   if (bir_stb) breg <= pin_ad_in;
   if (ir_stb)
   begin
      ireg <= breg;
      dc_mop0 <= ~pld[4];
      dc_mop1 <= ~pld[3];
      dc_rtt  <= ~pld[2];
   end
end

vm2_pld pld_matrix(.rq(breg), .sp(pld));

assign dc_f2 = (breg[11:9] != 3'b000)
             & ((breg[8:6] == 3'b111) | (breg[11:10] == 2'b11));

assign dc_j7 = ir_stb
             & (breg[8:6] == 3'b111)
             & (breg[14:12] != 3'b000);

assign dc_i7  = (breg[2:0] == 3'b111);
assign dc_bi  = pld[5];
assign dc_fl  = (ir_stb ? pld[10] : ~dc_fb) & ((ir_stb & dc_bi) | (~dc_mop0 & dc_mop1));
assign dc_aux = dc_j7 | br_cmdrq;
assign alt_cnst = (~dc_fb & plm[30]) | (dc_fb & plm[30] & plm[5] & plm[6]);


always @(posedge pin_clk_p)
begin
   if (ir_stb) dc_fb <= ~pld[10];
   if (wr2) dc_b7 <= (ax[15:13] == 3'b111);
end

always @(posedge pin_clk_n)
begin
   if (io_cmdr | (alu_wr & io_cmd))
      br_cmdrq <= 1'b0;
   else
      if (rcmd_set)
         br_cmdrq <= 1'b1;
end

//______________________________________________________________________________
//
// Main microcode state machine
//
assign mc_stb     = all_rdy_t0;
assign pi_stb_rc  = ~pla[0] & mc_stb;
always @(posedge pin_clk_p) pi_stb <= pi_stb_rc;
assign all_rdy    = ~mc_res & ~alu_nrdy & (~sta_nrdy | bra_stb)
                  & ~pli_nrdy & ~cmd_nrdy & ~all_rdy_t1;

always @(posedge pin_clk_p) all_rdy_t0 <= all_rdy;
always @(posedge pin_clk_n) all_rdy_t1 <= all_rdy_t0;

always @(posedge pin_clk_n)
begin
   if (mc_res | pi_stb | alu_wr)
      alu_nrdy <= 1'b0;
   else
      if (mc_stb)
         alu_nrdy <= 1'b1;
end

assign mc_rdy     = alu_nrdy & plm[0];
assign mc_rdy_rc  = alu_nrdy & (mc_stb ? pla[0] : plm[0]);
always @(posedge pin_clk_p) set_cend <= set_cend_rc;
always @(posedge pin_clk_n) cmd_nrdy <= ~mc_res & ~ir_stb & (set_cend | cmd_nrdy);
always @(posedge pin_clk_p) sta_nrdy <= ~mc_res & ~bra_stb & (sta_nrdy | wt_state_rc);

//______________________________________________________________________________
//
always @(posedge pin_clk_n)
begin
   if (io_cmd & wra)
      br_iocmd <= 1'b0;
   else
      if (sk)
         br_iocmd <= 1'b1;
end

always @(posedge pin_clk_n)
begin
   if (   reset
        | ~br_iocmd
        | buf_res
        | word27
        | ir_stb)
      br_ready <= 1'b0;
   else
      if (br_iocmd & bir_stb)
         br_ready <= 1'b1;
end

assign bra_req = br_ready & (cmd_nrdy | set_cend_rc & ~ir_stb & ~mc_res);
always @(posedge pin_clk_p)
begin
   if (reset)
      ir_stb <= 1'b0;
   else
      begin
         if (mc_stb & ir_stb)
            ir_stb <= 1'b0;
         else
            if (bra_req)
               ir_stb <= 1'b1;
      end
end

//______________________________________________________________________________
//
// Instructions with two operands and sources address mode is @PC
// For this instruction we force prefetch completion wait
//
always @(posedge pin_clk_p)
begin
   if (mc_res)
      bir_fix <= 1'b0;
   else
      if (ir_stb)
         bir_fix = (breg[14:12] != 3'o0)    // two ops instructions
                 & (breg[14:12] != 3'o7)    //
                 & (breg[8:6] == 3'o7)      // source is PC related
                 & (breg[10:9] == 2'o1)     // source @PC or @-(PC) mode
                 & (breg[2:0] != 3'o7)      // not PC related destination
                 & (breg[5:3] != 3'o6)      // not E(Rn) destination
                 & (breg[5:3] != 3'o7)      // not @E(Rn) destination
                 & (VM2_CORE_FIX_PREFETCH != 0);
end

//______________________________________________________________________________
//
// Main microcode matrix
//
vm2_plm plm_matrix(.ir(ireg), .ix(ix), .ri(ri), .ia(ia), .sp(pla));

assign na_rc[0] = reset  | ~pla[31] & ~abort;
assign na_rc[1] = mc_res | ~pla[32];
assign na_rc[2] = mc_res | ~pla[33];
assign na_rc[3] = mc_res |  pla[34];
assign na_rc[4] = mc_res |  pla[35];
assign na_rc[5] = mc_res |  pla[36];

always @(posedge pin_clk_p)
begin
   if (reset)
      na[0] <= 1'b1;
   else
      if (abort)
         na[0] <= 1'b0;
      else
         if (mc_stb)
            na[0] <= ~pla[31];

   if (mc_res)
      na[5:1] <= 5'b11111;
   else
      if (mc_stb)
      begin
         na[1] <= ~pla[32];
         na[2] <= ~pla[33];
         na[3] <=  pla[34];
         na[4] <=  pla[35];
         na[5] <=  pla[36];
      end
end

always @(posedge pin_clk_n)
if (mw_stb)
      get_state <= ~na[0] & plm[25] & ~plm[26];

always @(posedge pin_clk_p)
if (mw_stb)
      plm_wt[30:21] <= plm[30:21];

always @(posedge pin_clk_p)
if (mc_stb)
   begin
      plm[0]   <=  pla[0];
      plm[1]   <= ~pla[1];
      plm[2]   <= ~pla[2];
      plm[3]   <= ~pla[3];
      plm[4]   <= ~pla[4];
      plm[5]   <= ~pla[5];
      plm[6]   <= ~pla[6];
      plm[7]   <= ~pla[7];
      plm[8]   <= ~pla[8];
      plm[9]   <= ~pla[9];
      plm[10]  <= ~pla[10];
      plm[11]  <= ~pla[11];
      plm[12]  <= ~pla[12];
      plm[13]  <= ~pla[13];
      plm[14]  <= ~pla[14];
      plm[15]  <= ~pla[15];
      plm[16]  <= ~pla[16];
      plm[17]  <= ~pla[17];
      plm[18]  <= ~pla[18];
      plm[19]  <=  pla[19];
      plm[20]  <=  pla[20];
      plm[21]  <=  pla[21];
      plm[22]  <=  pla[22];
      plm[23]  <=  pla[23];
      plm[24]  <=  pla[24];
      plm[25]  <=  pla[25];
      plm[26]  <=  pla[26];
      plm[27]  <= ~pla[27];
      plm[28]  <=  pla[28];
      plm[29]  <=  pla[29];
      plm[30]  <= ~pla[30];
   end

assign plr[21] = mw_stb ? ~plm[21] : ~plm_wt[21];
assign plr[22] = mw_stb ? ~plm[22] : ~plm_wt[22];
assign plr[23] = mw_stb ? ~plm[23] : ~plm_wt[23];
assign plr[24] = mw_stb ? ~plm[24] : ~plm_wt[24];
assign plr[30] = mw_stb ?  plm[30] :  plm_wt[30];

assign set_cend_rc = mc_stb &  na_rc[0] & pla[25] & ~pla[26];
assign wt_state_rc = mc_stb & ~na_rc[0] & pla[25] & ~pla[26];
//
// ALU operation is modifiable from extended arithmetics unit
//
assign plm1m   = plm[1] | (~plm[25] & ~dc_fb);
assign plm18m  = plm[18] | (~ea_1tc & ea_sh2 & ea_shl);
assign plm19m  = plm[19] & ( ea_1tc | ~ea_shl);
assign plm20m  = plm[20] & ~ea_shr;
assign plm13m  = plm[13] & ~ea_mop0 & ~ea_mop1 & (~ea_div | ~ea_f[1] | (tlz ^ ear1[15]));
assign plm14m  = plm[14]
               & (~acc[15] | ~ea_mul | ~ea_f[0])
               & ((tlz ^ acc[15]) | ~ea_div | ~ea_f[19])
               & (~(tlz ^ ear1[15]) | ~ea_f[1] | ~ea_div | ea_mop0 | (acc[15] ^ ear1[15]))
               & (~ea_div | ea_mop0 | ~ea_f218 | ~ear2[0]);


always @(posedge pin_clk_p)
begin
   //
   // Current microinstruction address latch
   //    - direct branch from preliminary decoder
   //    - next address field
   //
   if (~mc_stb)
      if (ir_stb)
         ia <= {pld[0], pld[8], pld[7], ~pld[6], ~pld[9], ~pld[11]};
      else
         ia <= na;
   //
   // Auxiliary conditions register
   //
   if (~mc_stb) ix[0] <= dc_fl;
   if (~mc_stb) ix[1] <= dc_aux | (bra_stb ? ~plb : bra);
   if (ir_stb) ix[2] <= dc_bi;
   //
   // Interrupt query register
   //
   if (ir_stb & ~dc_i7)
      ri[0] <= 1'b0;
   else
      if (pi_stb)
         ri[0] <= plm[3];
      else
         if (pli_ack)
            ri[0] <= ~pli[1];

   if (ir_stb & psw[8])
      ri[1] <= 1'b1;
   else
      if (pi_stb)
         ri[1] <= plm[2];
      else
         if (pli_ack)
            ri[1] <= ~pli[5];

   if (ir_stb & dc_f2)
      ri[2] <= 1'b1;
   else
      if (pi_stb)
         ri[2] <= plm[1];
      else
         if (pli_ack)
            ri[2] <= pli[4];
end

assign pli_req = mc_stb &  na_rc[1] & pla[28];
assign sd_word = mc_stb & ~na_rc[1] & pla[28];

always @(posedge pin_clk_p)
begin
   if (sd_word)
      word27 <= 1'b1;
   else
      if (mc_res | (rd_end & plm[27]))
         word27 <= 1'b0;
end

//______________________________________________________________________________
//
// Interrupt processing unit
//
vm2_pli pli_matrix(.rq(qri), .sp(pli));

assign qri[0]  = acok_rq;           // nACLO rise interrupt request
assign qri[1]  = psw[7] & psw[8];   // halt mode interrupt disable
assign qri[2]  = 1'b0;              // reserved entry
assign qri[3]  = halt;              // external halt mode interrupt
assign qri[4]  = tout_rq;           // bus timeout exception request
assign qri[5]  = virq;              // external vectored interrupt
assign qri[6]  = aclo_rq;           // nACLO fall interrupt request
assign qri[7]  = vec_stb;           // vectored interrupt ack
assign qri[8]  = dble_rq;           // double bus timeout exception
assign qri[9]  = wcpu;              // WAIT instruction execution
assign qri[10] = evnt_rq;           // system timer interrupt request
assign qri[11] = tbit | psw[4];     // T-bit step trap request
assign qri[12] = dc_rtt & (tbit | psw[4]);
assign qri[13] = psw[8];            // halp mode flag
assign qri[14] = psw[7];            // interrupt disable flag
assign qri[15] = ac0;               // wait initial nACLO rise

always @(posedge pin_clk_p)
begin
   pli_arq <= abort;
   pli_ack <= ~reset & (pli_arq & ~abort | pli_req);
end

always @(posedge pin_clk_p)
begin
   //
   // Interrupt requests acknowlegement and reset
   //
   if (reset)
   begin
      acok_rq <= 1'b0;
      tout_rq <= 1'b0;
      aclo_rq <= 1'b0;
      dble_rq <= 1'b0;
   end
   else
      begin
         if (aclo_ack)
            acok_rq <= 1'b0;
         else
            if (~aclo_stb & aclo_rise)
               acok_rq <= 1'b1;

         if (aclo_ack)
            aclo_rq <= 1'b0;
         else
            if (aclo_stb & aclo_fall)
               aclo_rq <= 1'b1;

         if (tovf_ack)
            tout_rq <= 1'b0;
         else
            if (tovf)
               tout_rq <= 1'b1;

         if (ir_stb)
            dble_rq <= 1'b0;
         else
            if (tovf & dble_cnt1)
               dble_rq <= 1'b1;
      end

   if (init | evnt_ack)
      evnt_rq  <= 1'b0;
   else
      if (evnt & evnt_fall)
         evnt_rq  <= 1'b1;
end

always @(posedge pin_clk_p)
begin
   //
   // nEVNT falling edge detector
   //
   if (~evnt)
      evnt_fall <= 1'b1;
   else
      if (init | evnt_ack)
         evnt_fall <= 1'b0;
   //
   // nACLO falling edge detector
   //
   if (~aclo_stb)
      aclo_fall <= 1'b1;
   else
      if (reset | aclo_ack)
         aclo_fall <= 1'b0;
   //
   // nACLO rising edge detector
   //
   if (aclo_stb)
      aclo_rise <= 1'b1;
   else
      if (dclo | aclo_ack)
         aclo_rise <= 1'b0;
   //
   // Double QBUS timeout error counter
   //
   if (tovf)
      dble_cnt0 <= 1'b1;
   else
      if (reset | ir_stb)
         dble_cnt0 <= 1'b0;

   if (~tovf)
      dble_cnt1 <= dble_cnt0;
   else
      if (reset)
         dble_cnt1 <= 1'b0;
end

assign tovf_ack = pi_stb & plm[15] & ~pli6r & ~pli8r;
assign aclo_ack = pi_stb & plm[15] & ~pli6r &  pli8r;
assign evnt_ack = pi_stb & plm[15] &  pli6r & ~pli8r;
assign vsel[3:0]  = pli_ack ?
                  {pli[0], ~pli[2], ~pli[7], pli[9]} :
                  {plm[17], plm[18], plm[19], plm[20]};

always @(posedge pin_clk_p)
begin
   if (pli_ack | pi_stb)
      case(vsel)
         4'b0000: vmux <= 8'o030;
         4'b0001: vmux <= 8'o020;
         4'b0010: vmux <= 8'o010;
         4'b0011: vmux <= 8'o014;
         4'b0100: vmux <= 8'o004;
         4'b0101: vmux <= 8'o174;
         4'b0110: vmux <= 8'o000;
         4'b0111: vmux <= 8'o000;
         4'b1000: vmux <= 8'o250;
         4'b1001: vmux <= 8'o024;
         4'b1010: vmux <= 8'o100;
         4'b1011: vmux <= 8'o170;
         4'b1100: vmux <= 8'o034;
         4'b1101: vmux <= 8'o274;
         4'b1110: vmux <= 8'o000;
         4'b1111: vmux <= 8'o000;
         default: vmux <= 8'o000;
      endcase

   if (pli_ack)
      begin
         pli6r <= pli[6];
         pli8r <= pli[8];
      end
end

always @(posedge pin_clk_p)
begin
   if (reset | (plm[15] & pi_stb))
      tbit <= 1'b0;
   else
      if (ir_stb)
         tbit <= psw[4];
end

always @(posedge pin_clk_p)
begin
   if (plm[14] & pi_stb)
      wcpu <= 1'b1;
   else
      if (reset | (plm[15] & pi_stb))
         wcpu <= 1'b0;
end

//______________________________________________________________________________
//
// Branch processing unit
//
vm2_plb  plb_matrix(.rq({na[5], na[4], br}), .sp(plb));

always @(posedge pin_clk_p)
begin
   br[0] <= bir_stb ? pin_ad_in[8]  : breg[8];
   br[1] <= bir_stb ? pin_ad_in[9]  : breg[9];
   br[2] <= bir_stb ? pin_ad_in[10] : breg[10];
   br[3] <= bir_stb ? pin_ad_in[12] : breg[12];
   br[4] <= bir_stb ? pin_ad_in[13] : breg[13];
   br[5] <= bir_stb ? pin_ad_in[14] : breg[14];
   br[6] <= bir_stb ? pin_ad_in[15] : breg[15];
   br[7] <= ~(wr2 ? (ax[15:13] == 3'b111) : dc_b7);
   if (ws_cend)
   begin
      br[8]  <= psw_rc[0];
      br[9]  <= psw_rc[1];
      br[10] <= psw_rc[2];
      br[11] <= psw_rc[3];
   end
   else
   if (ws_wait)
      begin
         br[8]  <= cond_c;
         br[9]  <= cond_v;
         br[10] <= cond_z;
         br[11] <= cond_n;
      end
end

assign ws_cend  = ~sta_nrdy;
assign ws_wait  =  sta_nrdy & wr2;

always @(posedge pin_clk_p) bra_stb <= bra_req | (wr2 & get_state);
always @(posedge pin_clk_p)
begin
   if (mc_res | mc_stb)
      bra <= 1'b0;
   else
      if (bra_stb & ~plb)
         bra <= 1'b1;
end

//______________________________________________________________________________
//
// Y bus constant and vector generator
//
assign csel[0] = plm[12];
assign csel[1] = plm[11];
assign csel[2] = plm[10];
assign csel[3] = plm[9];

always @(*)
case(csel)
   4'b0000: cmux = {12'o0000, ireg[3:0]};
   4'b0001: cmux = {9'o000, ireg[5:0], 1'b0};
   4'b0010: cmux = alt_cnst ? 16'o000002 : 16'o000001;
   4'b0011: cmux = 16'o000002;
   4'b0100: cmux = 16'o000000;
   4'b0101: cmux = 16'o000004;
   4'b0110: cmux = {7'o000, cpsw};     // PSW copy access
   4'b0111: cmux = breg;               // buffered data access
   4'b1000: cmux = {ireg[7] ? 8'o377 : 8'o000, ireg[6:0], 1'b0};
   4'b1001: cmux = psw[3] ? 16'o177777 : 16'o000000;
   4'b1010: cmux = {15'o00000, psw[0]};
   4'b1011: cmux = 16'o000020;
   4'b1100: cmux = {8'o000, vmux};
   4'b1101: cmux = 16'o000024;
   4'b1110: cmux = cpc;                // PC copy access instead const
   4'b1111: cmux = cpc;                // PC copy access instead const
   default: cmux = 16'o000000;
endcase

//______________________________________________________________________________
//
// Input X and Y ALU bus muxes
//
always @(*)
case({plm[4], plm[5], plm[6], plm[7]})
   4'b0000: x = r[0];               // register index 0
   4'b0001: x = r[1];               // register index 1
   4'b0010: x = r[2];               // register index 2
   4'b0011: x = r[3];               // register index 3
   4'b0100: x = r[4];               // register index 4
   4'b0101: x = r[5];               // register index 5
   4'b0110: x = r[6];               // register index 6
   4'b0111: x = (ra_fr1 | word27 & wr1) ? pc2 : pc1;
   4'b1000: x = ear1;               // register index 8
   4'b1001: x = ear2;               // register index 9
   4'b1010: x = 16'o000000;         // eq_cnt, not muxed
   4'b1011: x = sreg;               // register index 11
   4'b1100: x = {7'o000, psw};      // register index 12
   4'b1101: x = acc;                // register index 13
   4'b1110: x = 16'o000000;         // areg, not muxed
   4'b1111: x = qreg;               // register index 15
   default: x = 16'o000000;
endcase

always @(*)
if (plm[8])
   y = cmux;
else
   case({plm[9],plm[10],plm[11],plm[12]})
      4'b0000: y = r[0];            // register index 0
      4'b0001: y = r[1];            // register index 1
      4'b0010: y = r[2];            // register index 2
      4'b0011: y = r[3];            // register index 3
      4'b0100: y = r[4];            // register index 4
      4'b0101: y = r[5];            // register index 5
      4'b0110: y = r[6];            // register index 6
      4'b0111: y = pc1;             // register index 7
      4'b1000: y = ear1;            // register index 8
      4'b1001: y = ear2;            // register index 9
      4'b1010: y = 16'o000000;      // eq_cnt, not muxed
      4'b1011: y = sreg;            // register index 11
      4'b1100: y = {7'o000, psw};   // register index 12
      4'b1101: y = acc;             // register index 13
      4'b1110: y = areg;            // register index 14
      4'b1111: y = qreg;            // register index 15
      default: y = 16'o000000;
   endcase

//______________________________________________________________________________
//
assign xbo[7:0]   = alu_xb ? xb[15:8] : xb[7:0];
assign xbo[14:8]  = alu_xb ? xb[6:0] : xb[14:8];
assign xbo[15]    = (alu_xb ? xb[7] : (xb[15] & ~sf_sum)) | (sf_sum & alu_cr[15]);

assign ax[7:0]    = xbo[7:0];
assign ax[15:8]   = ((sxt_rxy & (~ax[7] | sxt_y)) ? 8'o000 : 8'o377)
                  & (rd2h ? xbo[15:8] : 8'o377);

//______________________________________________________________________________
//
// ALU
//
assign alu_inx = (alu_a ?  x : 16'o000000) | (alu_b ? ~x : 16'o000000);
assign alu_iny = (alu_c ?  y : 16'o000000) | (alu_d ? ~y : 16'o000000);

assign alu_or  = alu_e ? 16'o000000 : (alu_inx | alu_iny);
assign alu_an  = alu_f ? 16'o000000 : (alu_inx & alu_iny);
assign alu_cp  = {alu_cf[14:0], alu_cin};
assign alu_cf  = alu_g ? (alu_cp & alu_or) | alu_an : 16'o000000;
assign alu_af  = alu_cp ^ (alu_an ^ alu_or);

assign alu_sh[6:0]   = (nshift ? alu_af[6:0] : 7'o000)
                     | (rshift ? alu_af[7:1] : 7'o000)
                     | (lshift ? {alu_af[5:0], sh_cin & sh_ci3} : 7'o000);

assign alu_sh[7]     = sh_ci1 & alu_af[7]
                     | rshift & (plm1m ? alu_af[8] : (~sh_ci2 & sh_cin))
                     | lshift & alu_af[6];

assign alu_sh[14:8]  = (nshift ? alu_af[14:8] : 7'o000)
                     | (rshift ? alu_af[15:9] : 7'o000)
                     | (lshift ? alu_af[13:7] : 7'o000);

assign alu_sh[15]    = sh_ci2 & alu_af[15]
                     | rshift & sh_cin & ~sh_ci2
                     | lshift & alu_af[14];

assign ea_mux        = (eas_dir   ? ear2[15:0]              : 16'o000000)
                     | (eas_left  ? {ear2[14:0], ea_mxin}   : 16'o000000)
                     | (eas_right ? {alu_af[0], ear2[15:1]} : 16'o000000);

assign alu_a   = (plm13m  |  plm14m) & ~alu_b;
assign alu_b   = ~plm[17] &  plm14m;
assign alu_c   = (plm13m  | ~plm14m) & ~alu_d;
assign alu_d   =  plm[17] & ~plm14m;
assign alu_e   =  plm[15];
assign alu_f   =  plm[16];
assign alu_g   = ~plm[15] & plm13m & (plm[17] | plm14m);
assign alu_xb  =  sf_xchg | qswp;

assign alu_cin =  alu_g & (~plm[17] | ~plm14m);
assign sh_ci1  =  nshift | (~plm1m & sh_ci2);
assign sh_ci2  =  nshift | (~plm18m & rshift);
assign sh_ci3  =  plm18m | ~lshift;

assign nshift  =  plm19m &  plm20m;
assign lshift  = ~plm19m &  plm20m;
assign rshift  =  plm19m & ~plm20m;

always @(posedge pin_clk_p)
if (wr1)
   begin
      ea22   <= ea_mux;
      alu_fr <= alu_af;
      alu_cr <= alu_cf;
      xb     <= alu_sh;
   end

assign eq1     = (xb[15:0] == 16'o177777);
assign zl      = (xb[7:0]  == 8'o000);
assign zh      = (xb[15:8] == 8'o000);

assign sf_sum  = (alu_cr[14] ^ alu_cr[15]) & ea_mul & ~ea_f0r;
assign axy_wh  = ~(sxt_rxy & sxt_y);
assign qswp    = (plm_rn[4:0] == 5'b01111) & qa0;
assign rd2h    = qswp | ~sf_byte;
assign sxt_rxy = ~qswp & sf_byte;

always @(posedge pin_clk_p)
if (wr1)
   begin
      sf_dir  <= nshift;
      sf_lr   <= lshift;
      sf_rr   <= rshift;
      sf_inv  <= ~plm[17] & plm14m & ~plm13m;
      sf_sub  <= ~alu_cin;
      sf_byte <= ~plm1m;
      sf_xchg <= plm18m & plm19m & plm20m;
      sxt_y   <= plm13m | plm14m | plm[17];
   end

assign cond_n  = sf_byte ? xb[7] : xb[15];

assign cond_z  = zl & sf_byte
               | zh & sf_xchg
               | zl & zh & ~ea_sh2 & ~ea_mul & ~sf_xchg & ~sf_byte
               | zl & zh & ea_22z & (ea_sh2 | ea_mul);

assign cond_v  = ~ea_shr
               & ~ea_mul
               & (ea_vdiv | ~ea_div)
               & (div_vf | ~ea_shl)
               & (ea_div | ea_shl |
                 ( ((alu_cr[6]  ^ alu_cr[7] ) | ~sf_dir | ~sf_byte)
                 & ((alu_cr[14] ^ alu_cr[15]) | ~sf_dir |  sf_byte)
                 & (sf_dir | (cond_n ^ cond_c0))));

assign cond_c  = (zero_div | ~ea_div)
               & ((~sf_sub ^ cond_c0) | sf_inv | ea_mul)
               & cond_c1
               & cond_c2;

assign cond_c0 = (~sf_lr  |  sf_byte | alu_fr[15])
               & (~sf_lr  | ~sf_byte | alu_fr[7])
               & (~sf_rr  |  ea_shr2 | alu_fr[0])
               & (~sf_dir | ~sf_byte | alu_cr[7])
               & (~sf_dir |  sf_byte | alu_cr[15] | ea_mul | ea_div);

assign cond_c1 = ~ea_mul | ((~eq1 | ~ea22[15]) & (~zh | ~zl | ea22[15]));
assign cond_c2 = ~ea_shr2 | ea_20r;

//______________________________________________________________________________
//
// Register unit
//
always @(posedge pin_clk_p)
begin
   if (axy_wh)
   begin
      if (rn_wa[0]) r[0][15:8] <= ax[15:8];
      if (rn_wa[1]) r[1][15:8] <= ax[15:8];
      if (rn_wa[2]) r[2][15:8] <= ax[15:8];
      if (rn_wa[3]) r[3][15:8] <= ax[15:8];
      if (rn_wa[4]) r[4][15:8] <= ax[15:8];
      if (rn_wa[5]) r[5][15:8] <= ax[15:8];
      if (rn_wa[6]) r[6][15:8] <= ax[15:8];
   end

   if (rn_wa[0]) r[0][7:0] <= ax[7:0];
   if (rn_wa[1]) r[1][7:0] <= ax[7:0];
   if (rn_wa[2]) r[2][7:0] <= ax[7:0];
   if (rn_wa[3]) r[3][7:0] <= ax[7:0];
   if (rn_wa[4]) r[4][7:0] <= ax[7:0];
   if (rn_wa[5]) r[5][7:0] <= ax[7:0];
   if (rn_wa[6]) r[6][7:0] <= ax[7:0];
end

always @(posedge pin_clk_p)
begin
   //
   // Write can happen in the same clock for all pc2->pc1->cpc
   // So we should implement the correct register write chain
   //
   if (pc2_wa)
   begin
      pc2[7:0] <= ax[7:0];
      if (axy_wh) pc2[15:8] <= ax[15:8];
   end
   if (pc1_wr)
   begin
      pc1[7:0] <= pc2_wa ? ax[7:0] : pc2[7:0];
      pc1[15:8] <= pc2_wa ? (axy_wh ? ax[15:8] : pc2[15:8]) : pc2[15:8];
   end
   if (pc_wax)
      cpc <= ax;
   else
      if (pc_wr)
      begin
         cpc[7:0] <= pc1_wr ? (pc2_wa ? ax[7:0] : pc2[7:0]) : pc1[7:0];
         cpc[15:8] <= pc1_wr ?
            (pc2_wa ? (axy_wh ? ax[15:8] : pc2[15:8]) : pc2[15:8]) : pc1[15:8];
      end

   if (axy_wh)
   begin
      if (acc_wa) acc[15:8] <= ax[15:8];
      if (ea1_wa) ear1[15:8] <= ax[15:8];
      if (rs_wa) sreg[15:8] <= ax[15:8];
   end

   if (acc_wa) acc[7:0] <= ax[7:0];
   if (ea1_wa) ear1[7:0] <= ax[7:0];
   if (rs_wa) sreg[7:0] <= ax[7:0];

   if (ea1_wa)
      ear2 <= ea22;
   else
   begin
      if (ea2_wa) ear2[7:0] <= ax[7:0];
      if (ea2_wa & axy_wh)
         ear2[15:8] <= ax[15:8];
   end
end

always @(posedge pin_clk_p)
begin
   if (ra_wa)
   begin
      areg[7:0] <= ax[7:0];
      if (axy_wh)
         areg[15:8] <= ax[15:8];
   end
   else
      if (ra_wx)
         areg <= x;
end

always @(posedge pin_clk_p)
begin
   if (brd_wa)
   begin
      qreg[7:0] <= ax[7:0];
      if (axy_wh)
         qreg[15:8] <= ax[15:8];
   end
   else
      if (brd_wq)
         qreg  <= qd_swap ? {8'o000, pin_ad_in[15:8]} : pin_ad_in;
end

//______________________________________________________________________________
//
// PSW and PSW copy
//
assign psw_rc[0] = psw_wa  & ax[0] | ~psw_wa  & pswc_stb & cond_c | ~psw_wa & ~pswc_stb & psw[0];
assign psw_rc[1] = psw_wa  & ax[1] | ~psw_wa  & psw_stb  & cond_v | ~psw_wa & ~psw_stb  & psw[1];
assign psw_rc[2] = psw_wa  & ax[2] | ~psw_wa  & psw_stb  & cond_z | ~psw_wa & ~psw_stb  & psw[2];
assign psw_rc[3] = psw_wa  & ax[3] | ~psw_wa  & psw_stb  & cond_n | ~psw_wa & ~psw_stb  & psw[3];
assign psw_rc[4] = pswt_wa & ax[4] | ~pswt_wa & psw[4];
assign psw_rc[5] = psw_wa  & ax[5] | ~psw_wa  & psw[5];
assign psw_rc[6] = psw_wa  & ax[6] | ~psw_wa  & psw[6];
assign psw_rc[7] = psw_wa  & ax[7] | ~psw_wa  & psw[7];
assign psw_rc[8] = psw8_wa & ax[8] | ~psw8_wa & psw[8];

always @(posedge pin_clk_p)
begin
   if (cpsw_wa)
   begin
      cpsw[7:0] <= ax[7:0];
      if (axy_wh)
         cpsw[8] <= ax[8];
   end
   else
      if (cpsw_stb)
         cpsw[8:0] <= psw_rc[8:0];
end

always @(posedge pin_clk_p)
begin
   if (pswt_wa) psw[4] <= ax[4];
   if (psw_wa) psw[7:5] <= ax[7:5];
   if (psw8_wa) psw[8] <= ax[8];
end

always @(posedge pin_clk_p)
begin
   if (psw_wa)
      psw[3:0] <= ax[3:0];
   else
   begin
      if (pswc_stb) psw[0] <= cond_c;
      if (psw_stb)  psw[1] <= cond_v;
      if (psw_stb)  psw[2] <= cond_z;
      if (psw_stb)  psw[3] <= cond_n;
   end
end

//______________________________________________________________________________
//
always @(posedge pin_clk_p)
if (mw_stb)
begin
   //
   // Register (breg, cpsw, cpc) is accessed on Y bus, not constant
   //
   plm_rn[4] <= plm[8]  & plm[10] &  plm[11]
             & ~plm[29] & ~plm[2] & ~plm[3];

   if (~plm[29] & plm[3])        // store in to accumulator
      plm_rn[3:0] <= 4'b1101;    // at write result phase
   else
      begin
         plm_rn[0] <= plm[29] ? plm[7] : ~plm[2] & plm[12];
         plm_rn[1] <= plm[29] ? plm[6] : ~plm[2] & plm[11];
         plm_rn[2] <= plm[29] ? plm[5] : ~plm[2] & plm[10];
         plm_rn[3] <= plm[29] ? plm[4] : ~plm[2] & plm[9];
      end
   ra_fw <= ra_fwn;
end

assign ra_fwn     = plm[2] & plm[3];
assign ra_fwn_rc  = mc_stb ? (~pla[2] & ~pla[3]) : ra_fwn;
assign ra_fr      = ra_fr1 | (plm[2] & ~plm[3]);
assign ra_fr_rc   = mc_stb ? (pla[2] & ~pla[3] & pla[29]) | (~pla[2] & pla[3]) : ra_fr;
assign ra_fr1     = ~plm[2] & plm[3] & plm[29];
always @(posedge pin_clk_p) if (wr2) wr7 <= wa_pc & ~ra_fr1;

assign wa_r1      = plm_rn[4] &  plm_rn[3];
assign wa_r2      = plm_rn[4] & ~plm_rn[3] & ~plm_rn[0];
assign wa_pc      = (plm_rn[3:0] == 4'b0111);

assign cpsw_wa    = wr2 & wa_r2;
assign ea1_wa     = wr2 & (plm_rn[4:0] == 5'b01000);
assign ea2_wa     = wr2 & (plm_rn[4:0] == 5'b01001);
assign ea_ctld    = wr2 & (plm_rn[4:0] == 5'b01010);
assign rs_wa      = wr2 & (plm_rn[4:0] == 5'b01011);
assign psw_wa     = wr2 & (plm_rn[4:0] == 5'b01100);
assign psw8_wa    = wr2 & (plm_rn[4:0] == 5'b01100) &  ~sf_byte;
assign pswt_wa    = wr2 & (plm_rn[4:0] == 5'b01100) & (~sf_byte | (sf_byte & ~na[0]));
assign acc_wa     = wr2 & (plm_rn[4:0] == 5'b01101);
assign brd_wa     = wr2 & (plm_rn[4:0] == 5'b01111);

assign psw_stb    = wr2 & ~plm[25];
assign pswc_stb   = wr2 & ~plm[25] & ~plm[26];
assign wr_psw     = psw_stb | (psw_wa & ~plm[8]);
assign cpsw_stb   = (~psw_rc[7] | ~psw_rc[8]) & ((wr_psw & ~io_pswr) | (dout_clr & io_pswr));
assign pc_wr      = cpsw_stb | (pc1_wr & (~psw[7] | ~psw[8]) & (io_wr | (~sync_clw & ~io_pswr)));
assign pc1_wr     = (wr2 & wa_pc & ~io_rcdr) | word27 | (wr1 & io_rcdr & ~iopc_st[1]);

assign pc_wax     = wr2 & wa_r1;
assign pc2_wa     = wr2 & wa_pc;

assign ra_wa      = wr2 & ra_fw;
assign ra_wx      = alu_wr & ra_fr;
assign wra        = (ra_wx | ra_wa) & ~to_block
                  & (plr[21] | plr[22] | plr[23])
                  & (~dc_mop0 | ~dc_mop1 | ~io_x001);

assign rn_wa[0]   = wr2 & (plm_rn[4:0] == 5'b00000);
assign rn_wa[1]   = wr2 & (plm_rn[4:0] == 5'b00001);
assign rn_wa[2]   = wr2 & (plm_rn[4:0] == 5'b00010);
assign rn_wa[3]   = wr2 & (plm_rn[4:0] == 5'b00011);
assign rn_wa[4]   = wr2 & (plm_rn[4:0] == 5'b00100);
assign rn_wa[5]   = wr2 & (plm_rn[4:0] == 5'b00101);
assign rn_wa[6]   = wr2 & (plm_rn[4:0] == 5'b00110);

//______________________________________________________________________________
//
// Extended arithmetics processing unit
//
assign ea_ctse    = ~acc[5] | ~ireg[10];
assign ea_22z     = (ea22 == 16'o000000);
assign ea_shr2    = ea_sh2 & acc[5];
assign ea_shr     = ea_nrdy &  acc[5] & ireg[10];
assign ea_shl     = ea_nrdy & ~acc[5] & ireg[10];
assign ea_sh2     = ea_nrdy &  ireg[9] &  ireg[10];
assign ea_div     = ea_nrdy &  ireg[9] & ~ireg[10];
assign ea_mul     = ea_nrdy & ~ireg[9] & ~ireg[10];
assign sh_cin     = (ea_shl | ea_div) ? ear2[15] : psw[0];
assign ea_vdiv    = zero_div
                  | (ea_mxinr ^ alu_fr[15] ^ alu_cr[15])
                  | (ea_mxinr ^ tlz ^ acc[15]);

assign eas_dir    = nshift & ~(ea_div & ea_f[3]);
assign eas_left   = lshift |  (ea_div & ea_f[3]);
assign eas_right  = rshift;

assign ea_mop0    = ea_div & ((ea_f[0] & (tlz ? ~(acc[15] ^ wait_div) : ~acc[15])) | (ea_fn12 & ~wait_div));
assign ea_mop1    = ea_mul & ((ea_f[0] & ~acc[15]) | (~ea_f[0] & ~ear2[0]));
//
// Extended aritmetics internal phase counter,
// decremented every wr2 write cycle
//
always @(posedge pin_clk_p)
begin
   if (ea_ctld)
      ea_ct[4:0] <= ea_ctse ? ax[4:0] : ~ax[4:0];
   else
      if (wr2 & ea_nrdy)
         ea_ct <= ea_ct - 5'b00001;
end
//
// The first cycle after EA counter load (ea_ctld)
//
always @(posedge pin_clk_n) if (wr2) ea_1t <= ea_ctld;
always @(posedge pin_clk_p) if (wr2) ea_1tc <= ea_1t;
always @(posedge pin_clk_p) if (wr1) ea_1tm <= ea_1tc;

assign ea_f[0]    = (ea_ct == 5'b00000);
assign ea_f[1]    = (ea_ct == 5'b00001);
assign ea_f[2]    = (ea_ct == 5'b00010);
assign ea_f[3]    = (ea_ct == 5'b00011);
assign ea_f[4]    = (ea_ct == 5'b00100);
assign ea_f[19]   = (ea_ct == 5'b10011);
assign ea_f[20]   = (ea_ct == 5'b10100);

assign ea_fn12    = ea_f[2] | ea_f[1];                               // phases 2:1
assign ea_f218    = ~ea_f[19] & ~ea_f[20] & ~ea_f[0] & ~ea_f[1];     // phases 21,18:2

always @(posedge pin_clk_p)
begin
   if (wr1)
   begin
      ea_20r   <= ear2[0];
      ea_fn23r <= ea_f[3] | ea_f[2];
      ea_f0r   <= ea_f[0];
   end
   if (ea_ctld)
      ea_f4r <= 1'b0;
   else
      if (wr1) ea_f4r <= ea_f[4];
end

always @(posedge pin_clk_p)
begin
   if (wr2 & ea_fn23r) wait_div <= ~cond_z;
   if (wr2 & ea_1tm)  zero_div <= cond_z;
   if (wr1 & ea_1tc) tlz <= ear1[15];
end

//
// Sticky DIV overflow (V) flag
// Check and store V on every division cycle
//
always @(posedge pin_clk_p)
begin
   if (~ea_1t & (tlz ^ xb[15]))
      div_vfr <= 1'b1;
   else
      if (ea_1t)
         div_vfr <= 1'b0;
end
assign div_vf = div_vfr | (tlz ^ xb[15]);

assign ea_mxin = ~ea_shl & ~(alu_af[15] ^ acc[15]);
always @(posedge pin_clk_p) if (wr1 & ea_f[19]) ea_mxinr <= ea_mxin;

assign ea_muls       = ea_ctld & ~ireg[9] & ~ireg[10];
assign ea_rdy        = (ea_trdy0 | ea_trdy0_set) & (~ea_trdy1 | ea_f[0] | ~ireg[10]);
assign ea_trdy0_set  = mc_res | (~wr2 & ((ea_div & ea_f[4]) | (ea_f[1] & (ea_div | ea_mul))));
assign ea_trdy0_clr  = wr2 & (ea_muls | (ea_div & (ea_1tm | ea_f4r)));
assign ea_trdy1_clr  = wr2 & ~ea_ctld & ea_trdy1 & ea_f0r;
always @(posedge pin_clk_n) ea_trdy2_clr <= ea_trdy1_clr;

always @(posedge pin_clk_n)
begin
   if (ea_trdy0_set)
      ea_trdy0 = 1'b1;
   else
      if (ea_trdy0_clr)
         ea_trdy0 = 1'b0;
end

always @(posedge pin_clk_n)
begin
   if (mc_res | ea_trdy1_clr)
      ea_trdy1 <= 1'b0;
   else
      if (ea_ctld)
         ea_trdy1 <= 1'b1;
end

always @(posedge pin_clk_p)
begin
   if (mc_res | ea_trdy2_clr)
      ea_nrdy <= 1'b0;
   else
      if (ea_ctld)
         ea_nrdy <= 1'b1;
end

//______________________________________________________________________________
//
// ALU state machine
//
assign en_alu_rc  = ~alu_st[0]
                  & ((mc_drdy_rc & mc_rdy_rc & io_rdy) | ~ea_rdy)
                  & ((~ra_fr_rc & ~ra_fwn_rc) | (~rta & ~rta_fall))
                  | (~ac0 & ~alu_st[0] & mc_stb);

assign rd_end     = alu_st[1];
assign alu_wr     = alu_st[0] & ~alu_st[2] & ea_rdy;
assign wr2        = alu_st[2];
assign mw_stb     = alu_st[0];
assign wr1        = alu_st[0];
assign ad_rd      = bir_stb | rdat;

//
// Internal to_reply is asserted only for prefetch transactions
//
assign bir_stb    = rdat & (~iop_in | iop_rcd);
assign brd_wq     = rdat & ( iop_in | iop_rcd);
assign io_start   = wra | (wr2 & iop_una);

always @(posedge pin_clk_p) alu_st[0] <= en_alu_rc & ~mc_res;
always @(posedge pin_clk_n) alu_st[1] <= alu_st[0];
always @(posedge pin_clk_p) alu_st[2] <= alu_st[1] & ~mc_res;

always @(posedge pin_clk_n)
begin
   if (alu_wr)
   begin
      if (word27 | io_cmd)
         iopc_st[0] <= 1'b1;
      else
         if (io_rcd & ~word27)
            iopc_st[0] <= 1'b0;
   end
   else
   begin
      if (word27 | io_cmdr)
         iopc_st[0] <= 1'b1;
      else
         if (io_rcdr & ~word27)
            iopc_st[0] <= 1'b0;
   end

   if (alu_wr)
   begin
      if (io_cmd)
         iopc_st[1] <= 1'b1;
      else
         if (~io_rcd)
            iopc_st[1] <= iopc_st[0] | word27 | io_cmd;
   end
   else
   begin
      if (io_cmdr)
         iopc_st[1] <= 1'b1;
      else
         if (~io_rcdr)
            iopc_st[1] <= iopc_st[0]  | word27 | io_cmdr;
   end
end

assign mc_drdy    = ~plm[27] | mc_drdy1;
assign mc_drdy_rc = (mc_stb ? pla[27] : ~plm[27]) & ~bir_fix | mc_drdy1;
always @(posedge pin_clk_n)
begin
   if (sk)
      mc_drdy0 <= 1'b0;
   else
      if (io_start & io_in)
         mc_drdy0 <= 1'b1;

   if (mc_res | ((mc_drdy0 | (io_start & io_in)) & ~sk))
      mc_drdy1 <= 1'b0;
   else
      if (brd_wq)
         mc_drdy1 <= 1'b1;
end

assign io_rdy  = ~io_st[2] | ~io_st[4];
assign iop_stb = (io_st[2] & ~io_st[3] & io_st[5]) | (~io_st[1] & io_start);

always @(posedge pin_clk_p)
begin
   sk <= iop_stb;

   if (mc_res | (sync_clr & ~io_st[2]))
      io_st[1] <= 1'b0;
   else
      if (io_start)
         io_st[1] <= 1'b1;

   if (sync_clr)
      io_st[3] <= 1'b0;
   else
      if (~io_st[4])
         io_st[3] <= 1'b1;

   io_st[5] <= io_st[4];
end

always @(posedge pin_clk_n)
begin
   if (mc_res | (~io_st[4] & ~io_st[5]))
      io_st[2] <= 1'b0;
   else
      if (io_start & io_st[1])
         io_st[2] <= 1'b1;

   io_st[4] <= io_st[3];
end

assign thang      = ~iocmd_st[2] & iocmd_st[5];
assign abort      = iocmd_st[1] | tevent;
assign to_block   = thang | (io_rcd1 & iocmd_st[5]);
assign rcmd_set   = thang | (buf_res & iocmd_st[4]);

always @(posedge pin_clk_p)
begin
   if (reset)
      iocmd_st[0] <= 1'b0;
   else
      begin
         if (iocmd_st[2] & ~iocmd_st[4])
            iocmd_st[0] <= 1'b0;
         else
            if (rcmd_set)
               iocmd_st[0] <= 1'b1;
      end
end

always @(posedge pin_clk_n)
begin
   iocmd_st[1] <= iocmd_st[0];

   if (wr2 | iocmd_st[0])
      iocmd_st[2] <= 1'b1;
   else
      if (word27 & alu_wr)
         iocmd_st[2] <= 1'b0;

   if (wr2 & io_rcd1_xt)
      iocmd_st[3] <= 1'b1;
   else
      if (~io_rcd1_xt | iocmd_st[0])
         iocmd_st[3] <= 1'b0;
end

always @(negedge iocmd_st[3] or posedge pin_clk_n)
begin
   if (!iocmd_st[3])
      iocmd_st[4] <= 1'b0;
   else
      if (~creq)
         iocmd_st[4] <= 1'b1;
end

always @(posedge pin_clk_p)
begin
   if (wr7 | reset)
      iocmd_st[5] <= 1'b0;
   else
      if (to_rply)
         iocmd_st[5] <= 1'b1;
   //
   // Instruction buffer ready reset
   // We are writing to the prefetched location
   // and should drop prefetched instruction
   //
   if (wr7 | reset)
      buf_res <= 1'b0;
   else
      if (mdfy | to_rply)
         buf_res <= 1'b1;
end

//______________________________________________________________________________
//
// Input bus X register indices for phase read 1
// For debug purposes only, for diagram synchronizing
//
// Index 10 is for ea_cnt, no read to bus X implemented in original core
// Index 14 is for areg, no read to bus X implemented in original core
//
wire [6:0]  rn_rx, rn_ry;
wire        pc1_rx, pc1_ry;
wire        pc2_rx, ra_ry;
wire        ea1_rx, ea1_ry;
wire        ea2_rx, ea2_ry;
wire        rs_rx, rs_ry;
wire        psw_rx, psw_ry;
wire        acc_rx, acc_ry;
wire        brd_rx, brd_ry;
wire        cpsw_ry;
wire        bir_ry;
wire        pc_ry;

assign rn_rx[0]   = (plm[7:4] == 4'b0000);            // register index 0
assign rn_rx[1]   = (plm[7:4] == 4'b1000);            // register index 1
assign rn_rx[2]   = (plm[7:4] == 4'b0100);            // register index 2
assign rn_rx[3]   = (plm[7:4] == 4'b1100);            // register index 3
assign rn_rx[4]   = (plm[7:4] == 4'b0010);            // register index 4
assign rn_rx[5]   = (plm[7:4] == 4'b1010);            // register index 5
assign rn_rx[6]   = (plm[7:4] == 4'b0110);            // register index 6
                                                      //
assign pc1_rx     = (plm[7:4] == 4'b1110) & ~ra_fr1;  // register index 7
assign pc2_rx     = (plm[7:4] == 4'b1110) &  ra_fr1;  // register index 7
assign ea1_rx     = (plm[7:4] == 4'b0001);            // register index 8
assign ea2_rx     = (plm[7:4] == 4'b1001);            // register index 9
assign rs_rx      = (plm[7:4] == 4'b1101);            // register index 11
assign psw_rx     = (plm[7:4] == 4'b0011);            // register index 12
assign acc_rx     = (plm[7:4] == 4'b1011);            // register index 13
assign brd_rx     = (plm[7:4] == 4'b1111);            // register index 15

//______________________________________________________________________________
//
// Input bus Y register indices for phase read 1
// For debug purposes only, for diagram synchronizing
//
// Index 10 is for ea_cnt, no read to bus X implemented in original core
// plm[8] == 0 indicates operations with two operands
// plm[8] == 1 indicates operations with constant
//
assign rn_ry[0]   = (plm[12:8] == 5'b00000);          // register index 0
assign rn_ry[1]   = (plm[12:8] == 5'b10000);          // register index 1
assign rn_ry[2]   = (plm[12:8] == 5'b01000);          // register index 2
assign rn_ry[3]   = (plm[12:8] == 5'b11000);          // register index 3
assign rn_ry[4]   = (plm[12:8] == 5'b00100);          // register index 4
assign rn_ry[5]   = (plm[12:8] == 5'b10100);          // register index 5
assign rn_ry[6]   = (plm[12:8] == 5'b01100);          // register index 6
                                                      //
assign pc1_ry     = (plm[12:8] == 5'b11100);          // register index 7
assign ea1_ry     = (plm[12:8] == 5'b00010);          // register index 8
assign ea2_ry     = (plm[12:8] == 5'b10010);          // register index 9
assign rs_ry      = (plm[12:8] == 5'b11010);          // register index 11
assign psw_ry     = (plm[12:8] == 5'b00110);          // register index 12
assign acc_ry     = (plm[12:8] == 5'b10110);          // register index 13
assign ra_ry      = (plm[12:8] == 5'b01110);          // register index 14
assign brd_ry     = (plm[12:8] == 5'b11110);          // register index 15
                                                      //
assign cpsw_ry    = (plm[12:8] == 5'b01101);          // constant index 6
assign bir_ry     = (plm[12:8] == 5'b11101);          // constant index 7
assign pc_ry      = (plm[12:8] == 5'b01111)           // constant index 14
                  | (plm[12:8] == 5'b11111);          // constant index 15

//______________________________________________________________________________
//
endmodule
