//
// 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 (field value 17 octal)
// - 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)
//
// At the source operand processing the source address is taken from PC and
// written back to the PC and Q-bus address register unchanged. This writing back
// also rewrites the PC2 register containing the modified prefetch address (PC+2/4).
// Then at the command completion microcode does not restart the prefetch with
// io_cmd code and prefetch continues with wrong address in PC2. The next
// instruction behaviour may become undefined.
//
// Fix just blocks the PC2 write in the affected instructions and prefetch
// address is no corrupted. If zero parameter is specified the model follows
// the original 1801BM2 behaviour (with prefetch bug).
//
   VM2_CORE_FIX_PREFETCH = 0
)
(
   input          pin_clk,       // processor 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
                                 //
   input          pin_waki,      // window grant request
   output         pin_wrq,       // window grant 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            f1, f2;                 // phase clock generator
reg            virq, halt, evnt;       // interrupt requests
reg            dclo, aclo;             // cold reset, power monitor
reg            aclo_stb;               //
                                       //
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  [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
reg            bfree;                  //
                                       //
wire           sel, sel1, sel_alt;     //
reg            sel2;                   //
                                       //
wire           init;                   //
reg            init_out;               //
reg            dmgo_out;               //
wire           dmgo;                   //
reg            dmr;                    //
reg            waki;                   //
wire           ar;                     //
wire           sack;                   //
wire           win_req;                //
reg            wrq;                    //
wire           iako;                   //
reg            iako_out;               //
reg            vec_stb;                //
wire           wtbt_out;               //
wire           rplys;                  //
reg            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, skp;                //
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;                  //
wire           io_wr;                  //
wire           io_rd;                  //
wire           io_sel;                 //
wire           io_iak;                 //
wire           io_alt;                 //
wire           io_x001;                //
wire           io_rcd;                 //
wire           io_rcd1;                //
wire           io_cmd;                 //
reg            io_cmdr;                //
reg            io_rcdr;                //
reg            io_pswr;                //
reg            io_qto;                 // Q-bus timeout timer mode
                                       //
reg            iop_wr;                 //
reg            iop_rd;                 //
reg            iop_in;                 //
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;                  //
wire           abort;                  //
wire           mc_res;                 //
wire           mc_stb;                 // mc read phase strobe
wire           mw_stb;                 // mc write phase strobe
wire           pi_stb;                 // peri
wire           all_rdy;                //
reg            all_rdy_t0;             //
reg            all_rdy_t1;             //
reg            alu_nrdy;               // ALU not ready
reg            sta_nrdy;               // state not ready
reg            cmd_nrdy;               // instruction completion
wire           pli_nrdy;               // interrupt polling not ready
reg            tim_nrdy0;              //
reg            tim_nrdy1;              //
wire           mc_rdy;                 //
reg            sa1, sa2;               //
reg            br_iocmd;               // instruction reading to breag in progress
reg            br_ready;               // breg contains valid read instruction
reg            ir_stb;                 //
wire           bir_stb;                //
wire           bra_req;                //
wire           tevent;                 //
wire           mdfy;                   //
wire           tena;                   //
wire           tovf;                   //
wire           thang;                  //
                                       //
reg            rta_fall;               //
wire           rta, creq;              //
wire           set_cend;               //
reg            clr_cend;               //
wire           wt_state;               //
reg            get_state, get_sta0;    //
reg            acmp_te, acmp_en;       //
                                       //
wire           din_set, dout_set;      //
reg            din_clr, dout_clr;      //
wire           sync_clr;               //
wire           rcmd_set;               // set command re-fetch request
                                       //
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
reg   [15:0]   qr;                     // interrupt processing matrix input register
wire  [9:0]    pli;                    // interrupt priority encode matrix output
wire  [11:0]   pld;                    // preliminary instruction decoder matrix output
wire           plb;                    // branch processing matrix output
                                       //
reg            na0r, na1w;             //
reg   [5:0]    na;                     // microcode next address field
reg   [30:0]   plm;                    // main matrix result register (first stage)
reg   [30:8]   plm_wt;                 //
wire  [30:8]   plr;                    //
wire  [36:0]   pla;                    //
                                       //
reg   [4:0]    plm_rn;                 //
wire  [6:0]    rn_wa;                  //
wire           pc2_wa;                 //
wire           pc2_was;                //
wire  [6:0]    rn_ry;                  //
wire  [6:0]    rn_rx;                  //
wire  [7:0]    wa;                     //
wire  [5:0]    cn_rd;                  //
wire           cn_ry0, cn_ry1;         //
wire           wa_gpr;                 //
wire           wa_reg;                 //
wire           wa_r1, wa_r2;           //
wire           rd_reg;                 //
wire           ra_wa;                  // write address register from ax-bus
wire           ra_wx;                  // write address register from x-bus
reg            ra_fw;                  //
wire           ra_fwn;                 //
wire           ra_fr, ra_fr1;          //
reg            ra_fr2;                 //
wire           rx_gpr, ry_gpr;         //
wire           rx_reg, ry_reg;         //
wire           pc1_rx, pc1_ry;         //
wire           pc2_rx, pc_ry;          //
wire           pc1_wr, pc_wax;         //
wire           pc_wr;                  //
wire           brd_rx, brd_ry;         //
wire           acc_rx, acc_ry;         //
wire           rs_wa, acc_wa;          //
wire           rs_rx, rs_ry;           //
wire           ra_ry;                  //
wire           bir_ry;                 //
wire           cpsw_wa, cpsw_ry;       //
wire           cpsw_stb;               //
wire           ea1_wa, ea2_wa;         //
wire           ea1_rx, ea1_ry;         //
wire           ea2_rx, ea2_ry;         //
wire           ea_ctld;                //
wire           pswt_wa;                //
wire           psw_wa, psw8_wa;        //
wire           psw_rx, psw_ry;         //
wire           psw_stb, pswc_stb;      //
wire           wr_psw;                 //
wire           brd_rql, brd_rqh;       //
wire           qd_swap;                //
wire           qswp, rd2h;             //
reg            qa0;                    //
reg            wr7;                    //
                                       //
wire  [15:0]   const0[5:0];            //
wire  [15:0]   const1[5:0];            //
                                       //
reg   [15:0]   ea22;                   // extended arithmetics register
reg   [15:0]   ear1;                   // extended arithmetics register
reg   [15:0]   ear2;                   // extended arithmetics register
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;                    //
reg   [15:0]   pc1;                    //
reg   [15:0]   pc;                     //
reg   [8:0]    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;                    //
wire  [15:0]   x, ax;                  // ALU X (input) and X* (output) bus
wire  [15:0]   y, ay;                  // ALU Y (input) and Y* (output) bus
                                       //
wire           alu_cin;                //
wire           alu_a, alu_b;           // ALU function controls
wire           alu_c, alu_d;           //
wire           alu_e, alu_f;           //
wire           alu_g, alu_h;           //
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;                 //
wire           en_rd;                  //
wire           mc_drdy;                //
reg            mc_drdy0, mc_drdy1;     //
reg   [5:0]    alu_st;                 // ALU state machine
reg   [5:0]    iocmd_st;               //
reg   [1:0]    iopc_st;                //
reg   [5:0]    io_st;                  //
reg            buf_res;                //
reg            pc2_res;                // ignore pc2 write
wire           wr1, wr2;               //
wire           rd1, rd2;               //
wire           salu;                   //
wire           rd_end;                 //
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
wire           to_clr;                 // not assert internal to_rply
                                       //
wire           pli_req;                // interrupt module query
wire           pli_ack;                // interrupt module ack
wire           pli_rclr;               //
wire           sd_word;                //
reg            word27;                 //
reg            sm0, sm1, sm2, sm3;     // interrupt module strobes
reg            pli6r;                  //
reg            pli8r;                  //
wire           evnt_ack;               //
wire           aclo_ack;               //
wire           tovf_ack;               //
wire  [5:0]    vsel;                   //
reg   [3:0]    vec;                    //
reg            wcpu;                   //
reg            tbit;                   //
wire           tbit_req;               //
wire           rt_req;                 //
                                       //
reg            dc_b7;                  //
wire           dc_f2;                  //
wire           dc_f8;                  //
wire           dc_i7;                  //
wire           dc_j7;                  //
wire           dc_bi;                  //
wire           dc_fl;                  //
wire           dc_aux;                 //
reg            dc_i9;                  //
reg            dc_i10;                 //
reg            dc_fb;                  //
reg            dc_rtt;                 //
reg            dc_mop0;                //
reg            dc_mop1;                //
wire           alt_cnst;               //
                                       //
wire           ea_nrdy;                //
wire           ea_shr;                 //
wire           ea_vdiv;                //
wire           ea_mxin;                //
reg            ea_mxinr;               //
wire           ea_muls;                //
wire           sh_cin;                 //
wire  [15:0]   ea_mux;                 //
wire  [4:1]    ea_px;                  //
reg   [4:0]    ea_ct;                  //
reg   [4:0]    ea_cb;                  //
wire  [4:0]    ea_cts;                 //
reg            ea_1t;                  //
reg            ea_1tm;                 //
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            tlz;                    //
reg            wait_vdiv;              //
reg            wait_div;               //
reg            zero_div;               //
                                       //
wire  [20:0]   ea_f;                   //
reg            ea_f0r, ea_f4r;         //
reg            ea_fn23r;               //
wire           ea_fn12;                //
wire           ea_f218;                //
wire           ea_enact, ea_ctse;      //
                                       //
wire           eas_dir;                //
wire           eas_left;               //
wire           eas_right;              //
                                       //
wire  [7:0]    rx;                     //
wire  [7:0]    ry;                     //
                                       //
reg            bra;                    //
reg            sb0, sb1;               //
wire           clr_wsta;               //
wire           ws_cend, ws_wait;       //
                                       //
reg   [8:0]    qct_ta;                 //
reg   [8:0]    qct_tb;                 //
wire  [8:0]    qct_ck;                 //
wire           tinit;                  //
wire           tout;                   //
                                       //
//______________________________________________________________________________
//
reg            br_cmdrq;               // breg read cmd request
wire           to_block;               // block timeout false reply
wire           wra;
wire           wtbt, to_rply;

//______________________________________________________________________________
//
// Removed aliases (inherited from schematics)
//
// reg            sd1;
// wire           nrs;
// wire           ea_nin;
// wire           ea_cin;
//
// assign         nrs      = acc[15];
// assign         ea_cin   = alu_cr[15];
// assign         ea_nin   = alu_fr[15];
//
// always @(*)
// begin
//    if (~bra_req & ~ir_stb)
//       sd1 <= 1'b0;
//    else
//       if (~f2 & bra_req)
//          sd1 <= 1'b1;
// end
//
//______________________________________________________________________________
//
assign pin_ad_out    = ad;
assign pin_ad_ena    = ad_oe;
assign pin_init      = init;
assign pin_dmgo      = dmgo_out;
assign pin_wrq       = wrq;
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 = ~f1;
always @(negedge pin_clk)
begin
   dclo <= pin_dclo;
   f1 <= ~f2;
end

always @(posedge pin_clk)
begin
   if (dclo)            // this code provides
      f2 <= 1'b0;       // correct phase relation
   else                 // f2 starts after f1
      f2 <= f1;
end

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

always @(*)
begin
   if (f1) aclo <= pin_aclo;

   if (reset)
      ac0 <= 1'b0;
   else
      if (sm2)
         ac0 <= pli[3];
end

assign reset = dclo | (~ac0 & aclo_stb);
assign mc_res = abort | reset;
//______________________________________________________________________________
//
// Interrupt inputs
//
always @(*)
begin
   //
   // This is strange behaviour:
   // INIT does not reset EVNT if latch is active
   //
   if (~pli_req)
      evnt <= pin_evnt;
   else
      if (init) evnt <= 1'b0;

   if (~pli_req) halt <= pin_halt;
   if (~pli_req) virq <= pin_virq;
   if (~((ac0 & pli_req) | (~ac0 & f1))) aclo_stb <= aclo;
end

//______________________________________________________________________________
//
always @(negedge f1) dmr <= pin_dmr;
always @(*) if (f1) waki <= pin_waki;
always @(*) if (f1) dmgo_out <= dmgo;

assign sel_alt = psw[8] ^ io_alt;
assign sel  = (sel2 & bus_adr) | sel1;
assign sel1 = iop_sel & din;
always @(*)
begin
   if (wra)
      sel2 <= sel_alt;
   else
      if (mc_res)
         sel2 <= 1'b1;
end
//
// Window access request 160000..163777
//
assign win_req = wra & (~ax[11] | (~rd2 & ~x[11]))
                     & (~ax[12] | (~rd2 & ~x[12]))
                     & ( ay[13] | (~rd2 &  x[13]))
                     & ( ay[14] | (~rd2 &  x[14]))
                     & ( ay[15] | (~rd2 &  x[15]));
always @(*)
begin
   if (mc_res)
      wrq <= 1'b0;
   else
      if (~f1 & waki)
         wrq <= 1'b0;
      else
         if (win_req & ~waki)
            wrq <= 1'b1;
end

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

always @(*)
begin
   if (din | sack)
      ad_oe <= 1'b0;
   else
      if (~din & ~sack & ~f1)
         ad_oe <= 1'b1;
end

always @(*)
begin
   if (sack)
      ct_oe <= 1'b0;
   else
      if (~f1 & ~sack & bfree)
         ct_oe <= 1'b1;
end

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

assign iako = iop_iak & din & iako_out;
always @(negedge f1) iako_out <= iop_iak & din;
always @(*)
begin
   if (iako_out)
      vec_stb <= 1'b1;
   else
      if (f1 & ~iako_out)
         vec_stb <= 1'b0;
end

assign wtbt_out =  (bus_adr & wtbt) | (bus_dat & ~iop_word);

always @(*)
begin
   if (mc_res | din_clr | ~ct_oe)
      din <= 1'b0;
   else
      if (din_set)
         din <= 1'b1;
end

always @(*)
begin
   if (mc_res)
      dout_s0 <= 1'b0;
   else
      if (~f1 & dout_clr)
         dout_s0 <= 1'b0;
      else
         if (~f1 & dout_set)
            dout_s0 <= 1'b1;

   if (~dout_s0)
      dout <= 1'b0;
   else
      if (f1 & ~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 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 @(*)
begin
   if (rta | mc_res)
      rta_fall <= 1'b0;
   else
      if (wra)
         rta_fall <= 1'b1;
end

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

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

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

always @(*)
begin
   if (~ct_oe | sync_clr)
      sync_s0 <= 1'b0;
   else
      if (f1 & sync_set)
         sync_s0 <= 1'b1;

   if (~f1)
      sync <= sync_s0;
end

always @(*)
begin
   if (f1 & ~sync)
      ardy_s0 <= 1'b0;
   else
      if (f1 & sync & ar)
         ardy_s0 <= 1'b1;

   if (~f1)
      ardy <= ardy_s0;
end

always @(*)
begin
   if (mc_res | to_block | (sync & ~ardy_s0))
      adr_req <= 1'b0;
   else
      if (wra)
         adr_req <= 1'b1;
end

assign to_rply = ~to_clr & ~word27 & tevent & io_qto;
assign ua_rply = (din | dout) & sel1;
always @(*)
begin
   if (~f1)
      rply <= pin_rply | to_rply | ua_rply;

   if (~f1)
      bfree <= ~sync & ~ar & (ardy | ~rply);

end

assign rdat       = iop_rd & rply0 & ~rply2;
assign rplys      = ~in_ua & (~sync_s0 | ~ardy_s0);
assign in_ua      = (iop_sel | iop_iak) & (din | (~adr_req & bus_free));
assign io_iak     =  plr[24] & plr[23] & plr[22] & plr[21];
assign io_sel     =  plr[24] & ~io_iak & ~io_x001 & plr[21];
assign io_alt     = ~plr[24] & ~io_rcd & ~io_x001 & plr[21];
assign io_wr      = (io_x001 & ~dc_mop1) | (~io_rcd & ~io_iak & plr[23]);
assign io_rd      = (io_x001 & ~dc_mop0) | plr[22];
assign io_in      = io_rcd | (io_rd & ~io_cmd);
assign io_cmd     = ~plr[24] &         & plr[22] & ~plr[21];
assign io_rcd     = ~plr[24] & plr[23] & plr[22] &  plr[21];
assign io_rcd1    = ra_fr2 & na1w;
assign io_x001    = ~plr[23] & ~plr[22] & plr[21];

assign dout_set   = ~dout_clr & bus_dat;
assign din_set    = ~din_clr &  iop_rd & ~rplys & ~rply3;
assign wtbt       = ~din_clr & ~iop_rd & iop_wr;

always @(*)
begin
   if (dout_clr)
      iop_wr <= 1'b0;
   else
      if (iop_stb)
         iop_wr <= io_wr;

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

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

   if (mw_stb)
      iop_una = io_iak | io_sel;

   if (sync_clr)
   begin
      iop_iak <= 1'b0;
      iop_sel <= 1'b0;
   end
   else
      if (iop_stb)
      begin
         iop_iak <= io_iak;
         iop_sel <= io_sel;
      end

end

always @(*)
begin
   if (rply3 | ~rply1)
      dout_clr <= 1'b0;
   else
      if (wtbt)
         dout_clr <= 1'b1;

   if (rply3 | ~rply2 | rdat)
      din_clr <= 1'b0;
   else
      if (iop_rd)
         din_clr <= 1'b1;
end

always @(*)
begin
   if (rply3)
      rply0 <= 1'b0;
   else
      if (f1)
         rply0 <= rply & ~rplys;

   if (~f1) rply1 <= rply0;
   if (~f1) rply3 <= rply2;

   if (f1)
      if (rply1)
         rply2 <= 1'b1;
      else
         if (~rply & ~rply1)
            rply2 <= 1'b0;
end

always @(*)
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 qct_ck[0]  = tena & ~f1;
assign qct_ck[1]  = tena & qct_ta[0];
assign qct_ck[2]  = qct_ck[1] & qct_tb[1];
assign qct_ck[3]  = qct_ck[2] & qct_tb[2];
assign qct_ck[4]  = qct_ck[3] & qct_tb[3];
assign qct_ck[5]  = qct_ck[4] & qct_tb[4];
assign qct_ck[6]  = qct_ck[5] & qct_tb[5];
assign qct_ck[7]  = qct_ck[6] & qct_tb[6];
assign qct_ck[8]  = qct_ck[7] & qct_tb[7];
assign tout  = qct_ta[0] & qct_tb[2] & qct_tb[4] & qct_tb[5];
assign tinit = qct_tb[8] & qct_ck[8];

always @(*)
begin
   if (!tena)
      begin
         qct_ta <= 9'o000;
         qct_tb <= 9'o000;
      end
   else
   begin
      if (qct_ck[0]) qct_ta[0] <= ~qct_tb[0];
      if (qct_ck[1]) qct_ta[1] <= ~qct_tb[1];
      if (qct_ck[2]) qct_ta[2] <= ~qct_tb[2];
      if (qct_ck[3]) qct_ta[3] <= ~qct_tb[3];
      if (qct_ck[4]) qct_ta[4] <= ~qct_tb[4];
      if (qct_ck[5]) qct_ta[5] <= ~qct_tb[5];
      if (qct_ck[6]) qct_ta[6] <= ~qct_tb[6];
      if (qct_ck[7]) qct_ta[7] <= ~qct_tb[7];
      if (qct_ck[8]) qct_ta[8] <= ~qct_tb[8];

      if (~qct_ck[0]) qct_tb[0] <= qct_ta[0];
      if (~qct_ck[1]) qct_tb[1] <= qct_ta[1];
      if (~qct_ck[2]) qct_tb[2] <= qct_ta[2];
      if (~qct_ck[3]) qct_tb[3] <= qct_ta[3];
      if (~qct_ck[4]) qct_tb[4] <= qct_ta[4];
      if (~qct_ck[5]) qct_tb[5] <= qct_ta[5];
      if (~qct_ck[6]) qct_tb[6] <= qct_ta[6];
      if (~qct_ck[7]) qct_tb[7] <= qct_ta[7];
      if (~qct_ck[8]) qct_tb[8] <= qct_ta[8];
   end
end

//______________________________________________________________________________
//
assign adr_eq  = ~acmp_en | (pc1 == areg);
assign mdfy = acmp_en & ~acmp_te & adr_eq;
always @(*)
begin
   if (alu_wr) io_rcdr <= io_rcd;
   if (alu_wr) io_cmdr <= io_cmd;

   if (reset)
      acmp_te <= 1'b0;
   else
      if (~f1 & acmp_en)
         acmp_te <= 1'b0;
      else
         if (~f1 & wra & io_wr)
            acmp_te <= 1'b1;
      if (f1) acmp_en <= acmp_te;

   if (reset | sync_clw)
      io_pswr <= 1'b0;
   else
      if (wra & io_wr & ~na0r)
         io_pswr <= 1'b1;
end

//______________________________________________________________________________
//
// Instruction registers - primary and preliminary decoder
//
always @(*)
begin
   if (bir_stb) breg <= ad;
   if ( ir_stb) ireg <= breg;
end

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

assign dc_f2 = ir_stb
             & (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  = ~ir_stb | (breg[2:0] == 3'b111);
assign dc_bi  = pld[5];
assign dc_f8  = ir_stb & psw[8];
assign dc_fl  = ~dc_fb & ((ir_stb & dc_bi) | (~dc_mop0 & dc_mop1));
assign dc_aux = dc_j7 | bra | br_cmdrq;
assign alt_cnst = (~dc_fb & plm[30]) | (dc_fb & plm[30] & plm[5] & plm[6]);

always @(*)
begin
   if (ir_stb)
   begin
      dc_fb   <= ~pld[10];
      dc_mop0 <= ~pld[4];
      dc_mop1 <= ~pld[3];
      dc_rtt  <= ~pld[2];
      dc_i9   <= br[1];
      dc_i10  <= br[2];
   end
   if (wr2) dc_b7  <= (ay[15:13] == 3'b111);
end

always @(*)
begin
   if (io_cmdr)
      br_cmdrq <= 1'b0;
   else
      if (rcmd_set)
         br_cmdrq <= 1'b1;
end
//______________________________________________________________________________
//
// Main microcode state machine
//
assign mc_stb = all_rdy_t0 & all_rdy_t1;
assign pi_stb = ~plm[0] & ~all_rdy_t0 & all_rdy_t1;
assign all_rdy = ~mc_res & ~alu_nrdy & ~sta_nrdy & ~pli_nrdy & ~cmd_nrdy & ~all_rdy_t1;
always @(*)
begin
   if (mc_res)
      all_rdy_t0 <= 1'b0;
   else
      if (f1)
      begin
         if (all_rdy)
            all_rdy_t0 <=  1'b1;
         else
            if (all_rdy_t1)
               all_rdy_t0 <= 1'b0;
      end

   if (~f1)
      all_rdy_t1 <= all_rdy_t0;
end

always @(*)
begin
   if (mc_res | clr_wsta)
      sta_nrdy <= 1'b0;
   else
      if (wt_state)
         sta_nrdy <= 1'b1;
end

always @(*)
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];

always @(*) if (~f1) clr_cend <= ir_stb;
always @(*)
begin
   if (mc_res | clr_cend)
      cmd_nrdy <= 1'b0;
   else
      if (set_cend)
         cmd_nrdy <= 1'b1;
end

//
// Instructions with two operands and sorces address mode is @PC
// For this instruction we suppress the pc2 write in source read phase
//
always @(*)
begin
   if (mc_res)
      pc2_res <= 1'b0;
   else
      if (ir_stb)
         pc2_res =  (breg[14:12] != 3'o0)    // two ops instructions
                  & (breg[14:12] != 3'o7)    //
                  & (breg[11:6] == 6'o17)    // source is @PC
                  & (breg[5:3] != 3'o6)      // not E(Rn) destination
                  & (breg[5:3] != 3'o7)      // not @E(Rn) destination
                  & (breg[2:0] != 3'o7)      // not PC related destination
                  & (VM2_CORE_FIX_PREFETCH != 0);
end

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

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

assign bra_req = cmd_nrdy & br_ready;
always @(*)
begin
   if (reset)
      ir_stb <= 1'b0;
   else
      if (f1)
      begin
         if (sa1 & clr_cend)
            ir_stb <= 1'b0;
         else
            if (bra_req)
               ir_stb <= 1'b1;
      end
end

always @(*)
begin
   if (all_rdy & ~f2)
      sa1 <= 1'b1;
   else
      if (~mc_stb & ~all_rdy & ~all_rdy_t0)
         sa1 <= 1'b0;

   if (~mc_stb & ~all_rdy & ~all_rdy_t0)
      sa2 <= 1'b0;
   else
      if (f2 & sa1)
         sa2 <= 1'b1;
end

//______________________________________________________________________________
//
// Main microcode matrix
//
vm2_plm plm_matrix(.ir(ireg), .ix(ix), .ri(ri), .ia(ia), .sp(pla));
always @(*)
begin
   if (reset)
      na[0] <= 1'b1;
   else
      if (abort)
         na[0] <= 1'b0;
      else
         if (sa2)
            na[0] <= ~pla[31];

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

   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];

      get_sta0 <= ~na[0] & pla[25] & ~pla[26];
   end

   if (mw_stb)
   begin
      na0r <= na[0];
      na1w <= na[1];
      get_state <= get_sta0;
      plm_wt[30:8] <= plm[30:8];
   end
end

assign plr[8]  = plm_wt[8];
assign plr[25] = plm_wt[25];
assign plr[26] = plm_wt[26];
assign plr[30] = plm_wt[30];

assign plr[21] = (ra_fr & en_alu) ? ~plm[21] : ~plm_wt[21];
assign plr[22] = (ra_fr & en_alu) ? ~plm[22] : ~plm_wt[22];
assign plr[23] = (ra_fr & en_alu) ? ~plm[23] : ~plm_wt[23];
assign plr[24] = (ra_fr & en_alu) ? ~plm[24] : ~plm_wt[24];

assign set_cend =  na[0] & mc_stb & pla[25] & ~pla[26];
assign wt_state = ~na[0] & mc_stb & 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_1t & ea_sh2 & ea_shl);
assign plm19m  = plm[19] & ( ea_1t | ~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_muls | ~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 @(*)
begin
   //
   // Current microinstruction address latch
   //    - direct branch from preliminary decoder
   //    - next address field
   //
   if (~sa1)
      if (ir_stb)
         ia <= {pld[0], pld[8], pld[7], ~pld[6], ~pld[9], ~pld[11]};
      else
         ia <= na;
   //
   // Auxiliary conditions register
   //
   if (~sa1) ix[0] <= dc_fl;
   if (~sa1) ix[1] <= dc_aux;
   if (ir_stb) ix[2] <= dc_bi;
   //
   // Interrupt acknowlegement register
   //
   if (~dc_i7)
      ri[0] <= 1'b0;
   else
      if (pi_stb)
         ri[0] <= plm[3];
      else
         if (pli_ack)
            ri[0] <= ~pli[1];

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

   if (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_ack = sm2;
assign pli_req = mc_stb &  na[1] & pla[28];
assign sd_word = mc_stb & ~na[1] & pla[28];
assign pli_rclr = sm2 & sm3;

always @(*)
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(qr), .sp(pli));

always @(*)
begin
   if (pli_req | abort)
      sm0 <= 1'b1;
   else
      if (sm3 | reset)
         sm0 <= 1'b0;

   if (~f2 & sm0 & ~abort)
      sm1 <= 1'b1;
   else
      if (~sm2 & (abort | ~sm0))
         sm1 <= 1'b0;

   if (reset | (f1 & sm3))
      sm2 <= 1'b0;
   else
      if (f1 & sm1 & ~abort & sm0)
         sm2 <= 1'b1;

   if (~f1) sm3 <= sm2;
end

always @(*)
begin
   if (init)
      qr[10]  <= 1'b0;
   else
      if (~sm1)
         if (evnt_ack)
            qr[10]  <= 1'b0;
         else
            if (evnt & evnt_fall)
               qr[10]  <= 1'b1;

   if (reset)
   begin
      qr[0]  <= 1'b0;
      qr[4]  <= 1'b0;
      qr[6]  <= 1'b0;
      qr[8]  <= 1'b0;
      qr[12] <= 1'b0;
      qr[15] <= 1'b0;
   end
   else
      if (~sm1)
      begin
         if (aclo_ack)
            qr[0]  <= 1'b0;
         else
            if (~aclo_stb & aclo_rise)
               qr[0] <= 1'b1;

         if (aclo_ack)
            qr[6]  <= 1'b0;
         else
            if (aclo_stb & aclo_fall)
               qr[6] <= 1'b1;

         if (tovf_ack)
            qr[4]  <= 1'b0;
         else
            if (tovf)
               qr[4] <= 1'b1;

         if (clr_cend)
            qr[8] <= 1'b0;
         else
            if (tovf & dble_cnt1)
               qr[8] <= 1'b1;

         qr[12] <= rt_req;
         qr[15] <= ac0;
      end

   if (~sm1)
   begin
      qr[1]  <= psw[7] & psw[8];
      qr[2]  <= 1'b0;
      qr[3]  <= halt;
      qr[5]  <= virq;
      qr[7]  <= vec_stb;
      qr[9]  <= wcpu;
      qr[11] <= tbit_req;
      qr[13] <= psw[8];
      qr[14] <= psw[7];
   end
end

always @(*)
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 | clr_cend)
         dble_cnt0 <= 1'b0;

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

assign tovf_ack = plm[15] & pi_stb & ~pli6r & ~pli8r;
assign aclo_ack = plm[15] & pi_stb & ~pli6r &  pli8r;
assign evnt_ack = plm[15] & pi_stb &  pli6r & ~pli8r;

assign vsel[0] = plm[8] & (vec[2:0] == 3'b000);
assign vsel[1] = plm[8] & (vec[2:0] == 3'b001);
assign vsel[2] = plm[8] & (vec[2:0] == 3'b010);
assign vsel[3] = plm[8] & (vec[2:0] == 3'b011);
assign vsel[4] = plm[8] & (vec[2:0] == 3'b100);
assign vsel[5] = plm[8] & (vec[2:0] == 3'b101);

always @(*)
begin
   if (pli_ack) pli6r <= pli[6];
   if (pli_ack) pli8r <= pli[8];

   if (pli_ack)
   begin
      vec[0] <=  pli[9];
      vec[1] <= ~pli[7];
      vec[2] <= ~pli[2];
      vec[3] <=  pli[0];
   end
   else
      if (pi_stb)
      begin
         vec[0] <= plm[20];
         vec[1] <= plm[19];
         vec[2] <= plm[18];
         vec[3] <= plm[17];
      end
end

assign tbit_req = tbit | psw[4];
assign rt_req = dc_rtt & (tbit | psw[4]);

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

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

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

always @(*)
begin
   if (reset | pli_rclr)
      tim_nrdy0 <= 1'b0;
   else
      if (abort)
         tim_nrdy0 <= 1'b1;

   if (reset | (tinit & ~f1))
      tim_nrdy1 <= 1'b0;
   else
      if (pi_stb & plm[13])
         tim_nrdy1 <= 1'b1;
end

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

always @(*)
begin
   if (~sb1)
   begin
      br[0] <= breg[8];
      br[1] <= breg[9];
      br[2] <= breg[10];
      br[3] <= breg[12];
      br[4] <= breg[13];
      br[5] <= breg[14];
      br[6] <= breg[15];
      br[7] <= ~dc_b7;
   end
   if (ws_cend)
   begin
      br[8]  <= psw[0];
      br[9]  <= psw[1];
      br[10] <= psw[2];
      br[11] <= psw[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  = ~sb1 & ~sta_nrdy;
assign ws_wait  = wr2 & ~sb1 & ~ws_cend;
assign clr_wsta = ~sb0 & sb1;
always @(*)
begin
   if (mc_res)
      sb0 <= 1'b0;
   else
      if (~f1 & sb1)
         sb0 <= 1'b0;
      else
         if (bra_req | (wr2 & get_state))
            sb0 <= 1'b1;

   if (f1) sb1 <= sb0;

   if (mc_res | mc_stb)
      bra <= 1'b0;
   else
      if (clr_wsta & ~plb)
         bra <= 1'b1;
end

//______________________________________________________________________________
//
// ALU mux and constant generator
//
assign const0[0]  = {ireg[7] ? 8'o377 : 8'o000, ireg[6:0], 1'b0};
assign const0[1]  = psw[3] ? 16'o177777 : 16'o000000;
assign const0[2]  = {15'o00000, psw[0]};
assign const0[3]  = 16'o000020;
assign const0[5]  = 16'o000024;
assign const0[4]  = (vsel[0] ? 16'o000030 : 16'o000000)
                  | (vsel[1] ? 16'o000020 : 16'o000000)
                  | (vsel[2] ? 16'o000010 : 16'o000000)
                  | (vsel[3] ? 16'o000014 : 16'o000000)
                  | (vsel[4] ? 16'o000004 : 16'o000000)
                  | (vsel[5] ? 16'o000174 : 16'o000000);

assign const1[0]  = {12'o0000, ireg[3:0]};
assign const1[1]  = {9'o000, ireg[5:0], 1'b0};
assign const1[2]  = alt_cnst ? 16'o000002 : 16'o000001;
assign const1[3]  = 16'o000002;
assign const1[5]  = 16'o000004;
assign const1[4]  = (vsel[0] ? 16'o000250 : 16'o000000)
                  | (vsel[1] ? 16'o000024 : 16'o000000)
                  | (vsel[2] ? 16'o000100 : 16'o000000)
                  | (vsel[3] ? 16'o000170 : 16'o000000)
                  | (vsel[4] ? 16'o000034 : 16'o000000)
                  | (vsel[5] ? 16'o000274 : 16'o000000);

assign y       = (bir_ry               ? breg            : 16'o000000)
               | (ra_ry                ? areg            : 16'o000000)
               | (brd_ry               ? qreg            : 16'o000000)
               | (ea1_ry               ? ear1            : 16'o000000)
               | (ea2_ry               ? ear2            : 16'o000000)
               | (pc_ry                ? pc              : 16'o000000)
               | (pc1_ry               ? pc1             : 16'o000000)
               | (acc_ry               ? acc             : 16'o000000)
               | (rs_ry                ? sreg            : 16'o000000)
               | (rn_ry[0]             ? r[0]            : 16'o000000)
               | (rn_ry[1]             ? r[1]            : 16'o000000)
               | (rn_ry[2]             ? r[2]            : 16'o000000)
               | (rn_ry[3]             ? r[3]            : 16'o000000)
               | (rn_ry[4]             ? r[4]            : 16'o000000)
               | (rn_ry[5]             ? r[5]            : 16'o000000)
               | (rn_ry[6]             ? r[6]            : 16'o000000)
               | (psw_ry               ? {7'o000, psw}   : 16'o000000)
               | (cpsw_ry              ? {7'o000, cpsw}  : 16'o000000)
               | ((cn_ry0        & cn_rd[0]) ? const0[0] : 16'o000000)
               | ((cn_ry0        & cn_rd[1]) ? const0[1] : 16'o000000)
               | ((cn_ry0        & cn_rd[2]) ? const0[2] : 16'o000000)
               | ((cn_ry0        & cn_rd[3]) ? const0[3] : 16'o000000)
               | ((rd1 & ~vec[3] & cn_rd[4]) ? const0[4] : 16'o000000)
               | ((cn_ry0        & cn_rd[5]) ? const0[5] : 16'o000000)
               | ((cn_ry1        & cn_rd[0]) ? const1[0] : 16'o000000)
               | ((cn_ry1        & cn_rd[1]) ? const1[1] : 16'o000000)
               | ((cn_ry1        & cn_rd[2]) ? const1[2] : 16'o000000)
               | ((cn_ry1        & cn_rd[3]) ? const1[3] : 16'o000000)
               | ((rd1 &  vec[3] & cn_rd[4]) ? const1[4] : 16'o000000)
               | ((cn_ry1        & cn_rd[5]) ? const1[5] : 16'o000000);

assign x       = (brd_rx   ? qreg            : 16'o000000)
               | (ea1_rx   ? ear1            : 16'o000000)
               | (ea2_rx   ? ear2            : 16'o000000)
               | (pc1_rx   ? pc1             : 16'o000000)
               | (pc2_rx   ? pc2             : 16'o000000)
               | (acc_rx   ? acc             : 16'o000000)
               | (rs_rx    ? sreg            : 16'o000000)
               | (rn_rx[0] ? r[0]            : 16'o000000)
               | (rn_rx[1] ? r[1]            : 16'o000000)
               | (rn_rx[2] ? r[2]            : 16'o000000)
               | (rn_rx[3] ? r[3]            : 16'o000000)
               | (rn_rx[4] ? r[4]            : 16'o000000)
               | (rn_rx[5] ? r[5]            : 16'o000000)
               | (rn_rx[6] ? r[6]            : 16'o000000)
               | (psw_rx   ? {7'o000, psw}   : 16'o000000);

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 ay[7:0]    = (rd2 ? xbo[7:0] : 8'o000);
assign ay[15:8]   = ((sxt_rxy & (ay[7] |  sxt_y)) ? 8'o377 : 8'o000)
                  | (rd2h ? xbo[15:8] : 8'o000);

assign ax[7:0]    = (rd2 ? xbo[7:0] : 8'o000);
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] | ~salu;
assign alu_f   =  plm[16] | ~salu;
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 @(*)
begin
   if (wr1) ea22   <= ea_mux;
   if (wr1) alu_fr <= alu_af;
   if (wr1) alu_cr <= alu_cf;
   if (wr1) xb     <= alu_sh;
end

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

assign sf_sum  = (alu_cr[14] ^ alu_cr[15]) & ea_mul & ~ea_f0r;
assign sxt_rxy = rd2 & sf_byte & ~qswp;
assign axy_wh  = ~(sxt_rxy & sxt_y);

always @(*)
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)
               & (wait_vdiv | ~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 @(*)
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];

      if (acc_wa) acc[15:8] <= ax[15:8];
      if (rs_wa) sreg[15:8] <= ax[15:8];
      if (pc2_wa) pc2[15:8] <= ax[15:8];
      if (ea1_wa) ear1[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];

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

   if (pc1_wr) pc1 <= pc2;
   if (pc_wax)
      pc <= ax;
   else
      if (pc_wr) pc <= pc1;

   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 @(*)
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 @(*)
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, ad[15:8]} : ad;
end

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

   if (pswt_wa) psw[4] <= ax[4];
   if (psw8_wa) psw[8] <= ax[8];
   if (psw_wa)
   begin
      psw[3:0] <= ax[3:0];
      psw[7:5] <= ax[7:5];
   end
   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

assign rx[0]   = (plm[7:5] == 3'b000);
assign rx[1]   = (plm[7:5] == 3'b100);
assign rx[2]   = (plm[7:5] == 3'b010);
assign rx[3]   = (plm[7:5] == 3'b110);
assign rx[4]   = (plm[7:5] == 3'b001);
assign rx[5]   = (plm[7:5] == 3'b101);
assign rx[6]   = (plm[7:5] == 3'b011);
assign rx[7]   = (plm[7:5] == 3'b111);

assign ry[0]   = (plm[12:10] == 3'b000);
assign ry[1]   = (plm[12:10] == 3'b100);
assign ry[2]   = (plm[12:10] == 3'b010);
assign ry[3]   = (plm[12:10] == 3'b110);
assign ry[4]   = (plm[12:10] == 3'b001);
assign ry[5]   = (plm[12:10] == 3'b101);
assign ry[6]   = (plm[12:10] == 3'b011);
assign ry[7]   = (plm[12:10] == 3'b111);

assign rn_wa[6:0] = (wr2 & wa_gpr) ? wa[6:0] : 7'b0000000;
assign pc_wax     =  wr2 & wa_r1;
assign pc2_was    =  wr2 & wa_gpr  & wa[7];
assign pc2_wa     =  pc2_was & ~(pc2_res & ~io_rcd & ~io_cmd);
assign acc_wa     =  wr2 & wa_reg  & wa[5];
assign rs_wa      =  wr2 & wa_reg  & wa[3];
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_rx[6:0] = (rd1 & rx_gpr) ? rx[6:0] : 7'b0000000;
assign pc1_rx     =  rd1 & ~ra_fr1 & rx_gpr & rx[7];
assign pc2_rx     =  rd1 &  ra_fr1 & rx_gpr & rx[7];
assign brd_rx     =  rd1 &           rx_reg & rx[7];
assign acc_rx     =  rd1 &           rx_reg & rx[5];
assign rs_rx      =  rd1 &           rx_reg & rx[3];

assign rn_ry[6:0] = (rd1 & ry_gpr) ? ry[6:0] : 7'b0000000;
assign pc_ry      =  rd1 & rd_reg  &  plm[9];
assign cpsw_ry    =  rd1 & rd_reg  & ~plm[9] & ~plm[12];
assign bir_ry     =  rd1 & rd_reg  & ~plm[9] &  plm[12];
assign pc1_ry     =  rd1 & ry_gpr  & ry[7];
assign brd_ry     =  rd1 & ry_reg  & ry[7];
assign ra_ry      =  rd1 & ry_reg  & ry[6];
assign acc_ry     =  rd1 & ry_reg  & ry[5];
assign rs_ry      =  rd1 & ry_reg  & ry[3];

assign rd_reg     =  plm[8] & plm[10] & plm[11];
assign wa_r1      =  plm_rn[4] &  plm_rn[3];
assign wa_r2      =  plm_rn[4] & ~plm_rn[3] & ~plm_rn[0];
assign wa_gpr     = ~plm_rn[3] & ~wa_r2;
assign wa_reg     =  plm_rn[3] & ~wa_r1;

assign cpsw_wa    = wr2 &   wa_r2;
assign ea1_wa     = wr2 &   wa_reg & wa[0];
assign ea2_wa     = wr2 &   wa_reg & wa[1];
assign ea_ctld    = wr2 &   wa_reg & wa[2];
assign psw_wa     = wr2 &   wa_reg & wa[4];
assign psw8_wa    = wr2 &   wa_reg & wa[4] & ~sf_byte;
assign pswt_wa    = wr2 & ((wa_reg & wa[4] &  sf_byte & ~na0r) | psw8_wa);
assign brd_wa     = wr2 &   wa_reg & wa[7];
assign psw_stb    = wr2 &  ~plr[25];
assign pswc_stb   = wr2 &  ~plr[25] & ~plr[26];
assign wr_psw     = psw_stb | (psw_wa & ~plr[8]);
assign cpsw_stb   = (~psw[7] | ~psw[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_gpr & wa[7] & ~io_rcdr) | word27 | (wr1 & io_rcdr & ~iopc_st[1]);

assign ea1_rx     = rd1 & rx_reg & rx[0];
assign ea1_ry     = rd1 & ry_reg & ry[0];
assign ea2_rx     = rd1 & rx_reg & rx[1];
assign ea2_ry     = rd1 & ry_reg & ry[1];
assign psw_rx     = rd1 & rx_reg & rx[4];
assign psw_ry     = rd1 & ry_reg & ry[4];

assign rx_reg     =  plm[4];
assign rx_gpr     = ~plm[4];
assign ry_reg     = ~plm[8] &  plm[9];
assign ry_gpr     = ~plm[8] & ~plm[9];

assign wa[0]      = (plm_rn[2:0] == 3'b000);
assign wa[1]      = (plm_rn[2:0] == 3'b001);
assign wa[2]      = (plm_rn[2:0] == 3'b010);
assign wa[3]      = (plm_rn[2:0] == 3'b011);
assign wa[4]      = (plm_rn[2:0] == 3'b100);
assign wa[5]      = (plm_rn[2:0] == 3'b101);
assign wa[6]      = (plm_rn[2:0] == 3'b110);
assign wa[7]      = (plm_rn[2:0] == 3'b111);

assign cn_ry0     = rd1 & plm[8] &  plm[9];
assign cn_ry1     = rd1 & plm[8] & ~plm[9];
assign cn_rd[0]   = ry[0] & plm[8];
assign cn_rd[1]   = ry[1] & plm[8];
assign cn_rd[2]   = ry[2] & plm[8];
assign cn_rd[3]   = ry[3] & plm[8];
assign cn_rd[4]   = ry[4] & plm[8] & plm[9];
assign cn_rd[5]   = ry[5] & plm[8];

assign qswp       = wa[7] & wa_reg & qa0;
assign rd2h       = rd2 & (qswp | ~sf_byte);

always @(*)
begin
   if (mw_stb) plm_rn[4] <= rd_reg & ~plm[29] & ~plm[2] & ~plm[3];

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

always @(*) if (mw_stb) ra_fw <= ra_fwn;
assign ra_fwn = plm[2] & plm[3];
assign ra_fr  =  ra_fr1 | (plm[2] & ~plm[3]);
assign ra_fr1 = ~plm[2] & plm[3] & plm[29];
always @(*) if (mw_stb) ra_fr2 <= ra_fr1;
always @(*) if (wr2) wr7 <= wa_gpr & wa[7] & ~ra_fr2;

//______________________________________________________________________________
//
// Extended arithmetics processing unit
//
assign ea_enact   = ~ea_ctld & ea_nrdy;
assign ea_ctse    = ~acc[5] | ~dc_i10;
assign ea_22z     = ~rd2 | (ea22 == 16'o000000);
assign ea_shr2    = ea_sh2 & acc[5];
assign ea_shr     = ea_nrdy &  acc[5] & dc_i10;
assign ea_shl     = ea_nrdy & ~acc[5] & dc_i10;
assign ea_sh2     = ea_nrdy &  dc_i9 &  dc_i10;
assign ea_div     = ea_nrdy &  dc_i9 & ~dc_i10;
assign ea_mul     = ea_nrdy & ~dc_i9 & ~dc_i10;
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_px[1]   = (ea_ct[4:1] == 4'b0000);
assign ea_px[2]   = (ea_ct[3:0] == 4'b0010);
assign ea_px[3]   = (ea_ct[3:0] == 4'b0011);
assign ea_px[4]   = (ea_ct[3:0] == 4'b0100);

assign ea_f[0]    = ea_px[1] & ~ea_ct[0];
assign ea_f[1]    = ea_px[1] &  ea_ct[0];
assign ea_f[2]    = ea_px[2] & ~ea_ct[4];
assign ea_f[3]    = ea_px[3] & ~ea_ct[4];
assign ea_f[4]    = (ea_ct == 5'b00100);
assign ea_f[19]   = ea_px[3] &  ea_ct[4];
assign ea_f[20]   = ea_px[4] &  ea_ct[4];

assign ea_fn12    = ea_f[2] | ea_f[1];
assign ea_f218    = ~ea_f[19] & ~ea_f[20] & ~ea_f[0] & ~ea_f[1];
always @(*)
begin
   if (wr1) ea_20r   <= ear2[0];
   if (wr1) ea_fn23r <= ea_f[3] | ea_f[2];
   if (wr1) ea_1tm   <= ea_1t;
   if (wr1) ea_f0r   <= ea_f[0];
   if (ea_ctld)
      ea_f4r <= 1'b0;
   else
      if (wr1) ea_f4r <= ea_f[4];
end

assign ea_mop0    = ea_div  & ((ea_f[0] & (tlz ? ~(acc[15] ^ wait_div) : ~acc[15])) | (ea_fn12 & ~wait_div));
assign ea_mop1    = ea_muls & ((ea_f[0] & ~acc[15]) | (~ea_f[0] & ~ear2[0]));

assign ea_cts[0]  = wr2 | ~ea_enact;
assign ea_cts[1]  = wr2 & (ea_ctld | ea_cb[0]);
assign ea_cts[2]  = wr2 & (ea_ctld | ea_cb[1]) & ea_cts[1];
assign ea_cts[3]  = wr2 & (ea_ctld | ea_cb[2]) & ea_cts[2];
assign ea_cts[4]  = wr2 & (ea_ctld | ea_cb[3]) & ea_cts[3];

always @(*)
begin
   if (ea_ctld)
   begin
      ea_cb[4:0] <= ea_ctse ? ax[4:0] : ~ay[4:0];
      ea_ct[4:0] <= ea_cb[4:0];
   end
   else
   begin
      if (ea_cts[0])
         ea_ct[0] <= ea_cb[0];
      else
         ea_cb[0] <= ~ea_ct[0];

      if (ea_cts[1])
         ea_ct[1] <= ea_cb[1];
      else
         ea_cb[1] <= ~ea_ct[1];

      if (ea_cts[2])
         ea_ct[2] <= ea_cb[2];
      else
         ea_cb[2] <= ~ea_ct[2];

      if (ea_cts[3])
         ea_ct[3] <= ea_cb[3];
      else
         ea_cb[3] <= ~ea_ct[3];

      if (ea_cts[4])
         ea_ct[4] <= ea_cb[4];
      else
         ea_cb[4] <= ~ea_ct[4];
   end
end

always @(*)
begin
   if (wr2 & ea_fn23r) wait_div <= ~cond_z;
   if (wr2 & ea_1tm)  zero_div <= cond_z;
   if (wr1 & ea_1t) tlz <= ear1[15];

   if (rd2 & ~ea_1t & (tlz ^ xb[15]))
      wait_vdiv <= 1'b1;
   else
      if (ea_1t)
         wait_vdiv <= 1'b0;


   if (ea_ctld)
      ea_1t <= 1'b1;
   else
      if (wr2)
         ea_1t <= 1'b0;
end

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

assign ea_muls       = ea_mul & ea_trdy1;
assign ea_rdy        = ea_trdy0 & (~ea_trdy1 | ea_f[0] | ~dc_i10);
assign ea_nrdy       = ea_trdy1 | ea_trdy1_clr;
assign ea_trdy0_set  = mc_res | (~wr2 & ((ea_div & ea_f[4]) | (ea_f[1] & (ea_div | ea_muls))));
assign ea_trdy0_clr  = wr2 & ((ea_muls & ea_1t) | (ea_div & (ea_1tm | ea_f4r)));
assign ea_trdy1_clr  = wr2 & ~ea_ctld & ea_nrdy & ea_f0r;

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

   if (mc_res | ea_trdy1_clr)
      ea_trdy1 <= 1'b0;
   else
      if (ea_ctld)
         ea_trdy1 <= 1'b1;
end
//______________________________________________________________________________
//
// ALU state machine
//
assign en_alu     = ((mc_drdy & mc_rdy & io_rdy) | ~ea_rdy) & ~alu_st[1]
                  & ((~ra_fr & ~ra_fwn) | (~rta & ~rta_fall));

assign en_rd      = alu_st[0];
assign salu       = alu_st[3];
assign rd_end     = alu_st[1] &  alu_st[2];
assign alu_wr     = alu_st[1] & ~alu_st[2] & ea_rdy;
assign wr2        = alu_st[2] & ~alu_st[1];
assign wr1        = alu_st[4] & ~alu_st[5];
assign mw_stb     = alu_st[3] & ~alu_st[4];
assign rd2        = alu_st[5] & ~alu_st[3];
assign rd1        = wr1 | en_rd;
assign ad_rd      = bir_stb | brd_wq | rdat;

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

always @(*)
begin
   if (mc_res)
      alu_st[0] <= 1'b0;
   else
      if (f1) alu_st[0] <= en_alu;

   if (~f1) alu_st[1] <= alu_st[0];

   if (mc_res)
      alu_st[2] <= 1'b0;
   else
      if (f1) alu_st[2] <= alu_st[1];
end

always @(*)
begin
   if (mc_res)
      alu_st[3] <= 1'b0;
   else
      if (f2)
         alu_st[3] <= alu_st[0] & ~alu_st[4];

   if (~f2) alu_st[4] <= alu_st[3];
   if ( f2) alu_st[5] <= alu_st[4];
end

always @(*)
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 (word27 | io_cmdr)
      iopc_st[0] <= 1'b1;
   else
      if (io_rcdr & ~word27)
         iopc_st[0] <= 1'b0;

   if (io_cmdr)
      iopc_st[1] <= 1'b1;
   else
      if (~io_rcdr)
         iopc_st[1] <= iopc_st[0];
end

assign mc_drdy = ~plm[27] | mc_drdy1;
always @(*)
begin
   if (sk)
      mc_drdy0 <= 1'b0;
   else
      if (io_start & io_in)
         mc_drdy0 <= 1'b1;

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

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

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

   if (~io_start)
      io_st[1] <= io_st[0];

   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;

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

   if (~f1) io_st[4] <= io_st[3];
   if ( f1) io_st[5] <= io_st[4];
end

always @(*)
begin
   if (iop_stb)
      skp <= 1'b1;
   else
      if (~f1 & sk)
         skp <= 1'b0;

   if (f1) sk <= skp;
end

always @(*)
begin
   if (to_clr | word27)
      io_qto <= 1'b0;
   else
      if (~tevent)
         io_qto <= 1'b1;
end

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

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

   if (~f1) iocmd_st[1] <= iocmd_st[0];

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

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

   if (~iocmd_st[3])
      iocmd_st[4] <= 1'b0;
   else
      if (~f1 & iocmd_st[3] & ~creq)
         iocmd_st[4] <= 1'b1;

   if (wr7 | reset)
      iocmd_st[5] <= 1'b0;
   else
      if (to_rply)
         iocmd_st[5] <= 1'b1;

   if (wr7 | reset)
      buf_res <= 1'b0;
   else
      if (mdfy | to_rply)
         buf_res <= 1'b1;
end
//______________________________________________________________________________
//
endmodule
