//
// copyright (c) 2014 by 1801BM1@gmail.com
// Licensed under CC-BY 3.0 (https://creativecommons.org/licenses/by/3.0/)
//
//______________________________________________________________________________
//
`timescale 1ns / 1ns

module k580vm80a
(
   input         pin_clk,       // global module clock (no in original 8080)
   input         pin_f1,        // clock phase 1 (used as clock enable)
   input         pin_f2,        // clock phase 2 (used as clock enable)
   input         pin_reset,     // module reset
   output [15:0] pin_a,         // address bus outputs
   output  [7:0] pin_dout,      // data bus output
   input   [7:0] pin_din,       // data bus input
   output        pin_aena,      // address outputs enable
   output        pin_dena,      // data outputs enable
   input         pin_hold,      //
   output        pin_hlda,      //
   input         pin_ready,     //
   output        pin_wait,      //
   input         pin_int,       //
   output        pin_inte,      //
   output        pin_sync,      //
   output        pin_dbin,      //
   output        pin_wr_n
);

//______________________________________________________________________________
//
wire  [7:0]    d;
reg   [7:0]    db, di;
reg   [15:0]   a;
wire           clk, f1, f2;
reg            abufena, db_ena, db_stb, dbin_pin, dbinf2;
reg            reset;
wire           ready;
wire           dbin_ext;

reg            t851, t404, t382, t383, t712, t735, t773;
reg            hold, hlda_pin;
wire           hlda, h889;

reg            wr_n, t1124, t1011, sync;
wire           ready_int;

reg   [15:0]   r16_pc, r16_hl, r16_de, r16_bc, r16_sp, r16_wz, mxo;
wire  [15:0]   mxi;
wire           mxr0, mxr1, mxr2, mxr3, mxr4, mxr5;
wire           mxwh, mxwl, mxrh, mxrl, mxw16, mxwadr;
wire           dec16, inc16, iad16;
reg            xchg_dh, xchg_tt, t3144;
wire           t1460, t1467, t1513, t1514, t1519;

wire           sy_inta, sy_wo_n, sy_hlta, sy_out, sy_m1, sy_inp, sy_memr;
reg            sy_stack;

wire           thalt, twt2;
reg            t1, t2, tw, t3, t4, t5;
reg            t1f1, t2f1, twf1, t3f1, t4f1, t5f1;
reg            m1, m2, m3, m4, m5;
reg            m1f1, m2f1, m3f1, m4f1, m5f1;

wire           start, ms0, ms1, m836, m839, m871;
reg            eom, t789, t887, t953, t976, t980;

reg            intr, inta, inte, mstart, minta;
wire           irq;

reg   [7:0]    i;
reg            i25, i14, i03;
wire           imx, acc_sel;
wire           id_op, id_io, id_in, id_popsw, id_pupsw,
               id_nop, id_lxi, id_inx, id_inr, id_dcr, id_idr, id_mvi, id_dad,
               id_dcx, id_opa, id_idm, id_hlt, id_mov, id_opm, id_pop, id_rst,
               id_cxx, id_jxx, id_rxx, id_ret, id_jmp, id_opi, id_out, id_11x,
               id_rlc, id_rxc, id_rar, id_sha, id_daa, id_cma, id_stc, id_cmc,
               id_add, id_adc, id_sub, id_sbb, id_ana, id_xra, id_ora, id_cmp,
               id_lsax, id_mvim, id_shld, id_lhld, id_mvmr, id_mvrm, id_push,
               id_xthl, id_sphl, id_pchl, id_xchg, id_call, id_eidi, id_stlda;

wire           id80, id81, id82, id83, id84, id85, id86, id00, id01,
               id02, id03, id04, id05, id06, id07, id08, id09, id10;
wire           goto, jmpflag;
reg            jmptake, tree0, tree1, tree2;
reg            t2806, t2817, t2819, t3047, t2998, t3363, t3403, t3335, t3361;

reg   [7:0]    xr, r, acc;
wire  [7:0]    x, s, c;
wire           cl, ch, daa, daa_6x, daa_x6;
wire           a398;
reg            a327, a357, a358;
wire           alu_xout, alu_xwr, alu_xrd, alu_ald, alu_awr, alu_ard,
               alu_rld, alu_r00, alu_rwr, alu_srd, alu_zrd, alu_frd;

reg            psw_z, psw_s, psw_p, psw_c, psw_ac, tmp_c;
reg            t2222, t1375, t1497, t1698, t1668, t1780, t1993, t1994;
reg            psw_ld, psw_wr, t2046, t2133, t2175;

//_____________________________________________________________________________
//
assign clk        = pin_clk;
assign f1         = pin_f1;
assign f2         = pin_f2;

assign pin_a      = a;
assign pin_aena   = abufena;
assign pin_dout   = db;
assign pin_dena   = db_ena;

assign dbin_ext = dbinf2;
assign d[7]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[7]
               | mxrl & mxo[7]
               | mxrh & mxo[15]
               | t1f1 & sy_memr
               | alu_xrd & xr[7]
               | alu_ard & acc[7]
               | alu_frd & psw_s
               | alu_srd & s[7] );

assign d[6]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[6]
               | mxrl & mxo[6]
               | mxrh & mxo[14]
               | t1f1 & sy_inp
               | alu_xrd & xr[6]
               | alu_ard & acc[6]
               | alu_frd & psw_z
               | alu_srd & s[6] );

assign d[5]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[5]
               | mxrl & mxo[5]
               | mxrh & mxo[13]
               | t1f1 & sy_m1
               | alu_xrd & xr[5]
               | alu_ard & acc[5]
               | alu_frd & 1'b0
               | alu_srd & s[5] );

assign d[4]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[4]
               | mxrl & mxo[4]
               | mxrh & mxo[12]
               | t1f1 & sy_out
               | alu_xrd & xr[4]
               | alu_ard & acc[4]
               | alu_frd & psw_ac
               | alu_srd & s[4] );

assign d[3]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[3]
               | mxrl & mxo[3]
               | mxrh & mxo[11]
               | t1f1 & sy_hlta
               | alu_xrd & xr[3]
               | alu_ard & acc[3]
               | alu_frd & 1'b0
               | alu_srd & s[3] );

assign d[2]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[2]
               | mxrl & mxo[2]
               | mxrh & mxo[10]
               | t1f1 & sy_stack
               | alu_xrd & xr[2]
               | alu_ard & acc[2]
               | alu_frd & psw_p
               | alu_srd & s[2] );

assign d[1]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[1]
               | mxrl & mxo[1]
               | mxrh & mxo[9]
               | t1f1 & sy_wo_n
               | alu_xrd & xr[1]
               | alu_ard & acc[1]
               | alu_frd & 1'b1
               | alu_srd & s[1] );

assign d[0]    = ~reset & ~alu_zrd &
               ( dbin_ext & di[0]
               | mxrl & mxo[0]
               | mxrh & mxo[8]
               | t1f1 & sy_inta
               | alu_xrd & xr[0]
               | alu_ard & acc[0]
               | alu_frd & psw_c
               | alu_srd & s[0] );

always @(posedge clk)
begin
   if (f2 & db_stb) db <= d;
   if (f2) abufena <=  (~twt2 | ~thalt) & ~hlda_pin;
   if (f1) db_stb <= t1 | (~sy_wo_n & t2);
   if (f1) t851 <= t1 | (~sy_wo_n & (t2 | tw | t3));
   if (f2) db_ena <= ~reset & t851;
end

//______________________________________________________________________________
//
// reset input buffer
//
always @(posedge clk)
begin
   if (f1) t404  <= pin_reset;
   if (f2) reset <= t404;
end

//______________________________________________________________________________
//
// hold input buffer
//
assign pin_hlda = hlda_pin;
assign hlda = hold & (t773 | (t3 & sy_wo_n) | (~m1 & sy_hlta) | t735);
assign h889 = t2f1 | twf1;

always @(posedge clk)
begin
   if (f1)  t712 <= ~sy_wo_n & t3;
   if (f2)  t735 <= t712;
   if (~f2) t382 <= pin_hold;
   if (f2)  t383 <= ((~t382 & hold) | t383); // extend the front detector pulse for entire F2 duration
   if (~f2) t383 <= 1'b0;
   if (f2)  t773 <= hlda_pin;
   if (f1)  hlda_pin <= hlda;
end

always @(posedge clk)
begin
   if (reset)
      hold <= 1'b0;
   else
      if (f2)
         begin
            if (t382)
               begin
                  if (~sy_inta & h889) hold <= 1'b1;
               end
            else
               hold <= 1'b0;
         end
end

//______________________________________________________________________________
//
assign pin_dbin   = dbin_pin;
assign pin_wr_n   = wr_n;
assign pin_sync   = sync;

always @(posedge clk)
begin
   dbinf2 <= (f2 | dbin_pin) & ((t1124 & (m1f1 | ~sy_hlta)) | dbinf2);

   if (dbin_pin) di <= pin_din;
   if (f2) dbin_pin <= t1124 & (m1f1 | ~sy_hlta);
   if (f2) sync <= ~ready_int & t1011;
   if (f1) t1011 <= t1 & ~reset;
   if (f1) t1124 <= (t2 | tw) & sy_wo_n;
   if (f1) wr_n <= ~(t3 | tw) | ready_int | sy_wo_n;
end

//______________________________________________________________________________
//
// ready pin and internal circuits
//
assign ready_int = (m4 | m5) & id_dad;
assign ready = ready_int | pin_ready;
assign pin_wait = twf1;

//______________________________________________________________________________
//
// register unit - 6 16-bit registers
//
//    r0 - pc
//    r1 - hl, de
//    r2 - de, hl
//    r3 - bc
//    r4 - sp
//    r5 - wz
//
assign      t1467    = tree1 | (id04 & t4f1 & ~id_xthl);
assign      t1519    = tree2 | (id00 & t4f1 & ~id_xthl);
assign      mxi      = inc16 ? (a + 16'h0001)
                     : dec16 ? (a - 16'h0001)
                     : a;

assign      inc16    = iad16 & ~dec16;
assign      dec16    = iad16 & id05 & (t4f1 | t5f1 | m4f1 | m5f1);
assign      iad16    = ~(id00 & (t4f1 | t5f1)) & (~minta | m5 | t3144);

assign      mxw16    = t3403;
assign      mxwadr   = t3363 | (t4f1 & ~id_dad & ~id_hlt);
assign      t1513    = (t4f1 & id07) | t3335;
assign      t1514    = (t4f1 & id08) | t3361;

assign      mxrh     = t2998 | (id08 & t4f1 & ~i03);
assign      mxrl     = t3047 | (id08 & t4f1 & i03);
assign      mxwh     = t2817 | (t2806 & ~i03);
assign      mxwl     = t2819 | (t2806 & i03);

assign      mxr0     = tree0;
assign      mxr1     =  xchg_dh & (((t1513 | t1514) & (~i14 & i25)) | t1519)
                     | ~xchg_dh & (t1513 | t1514) & (i14 & ~i25);
assign      mxr2     =  xchg_dh & (t1513 | t1514) & (i14 & ~i25)
                     | ~xchg_dh & (((t1513 | t1514) & (~i14 & i25)) | t1519);
assign      mxr3     = (t1513 | t1514) & (~i14 & ~i25);
assign      mxr4     = t1467 | (t1513 & i14 & i25);
assign      mxr5     = ~(t1467 | t1513 | t1514 | t1519 | mxr0);

always @ (posedge clk)
begin
      if (f1) t3144 <= t4 | t5 | (m4 & ~id02);
      xchg_tt <= id_xchg & t2;
      xchg_dh <= ~reset & ((xchg_tt & ~(id_xchg & t2)) ? ~xchg_dh : xchg_dh);
end

always @ (*)
case ({mxr0, mxr1, mxr2, mxr3, mxr4, mxr5})
   6'b100000:  mxo = r16_pc;
   6'b010000:  mxo = r16_hl;
   6'b001000:  mxo = r16_de;
   6'b000100:  mxo = r16_bc;
   6'b000010:  mxo = r16_sp;
   6'b000001:  mxo = r16_wz;
   default:    mxo = 16'h0000;
endcase

always @ (posedge clk)
if (f2)
begin
   if (mxwadr) a <= mxo;
   if (mxw16)
      begin
         if (mxr0) r16_pc <= mxi;
         if (mxr1) r16_hl <= mxi;
         if (mxr2) r16_de <= mxi;
         if (mxr3) r16_bc <= mxi;
         if (mxr4) r16_sp <= mxi;
         if (mxr5) r16_wz <= mxi;
      end
   else
      begin
         if (mxwl)
            begin
               if (mxr0) r16_pc[7:0] <= d;
               if (mxr1) r16_hl[7:0] <= d;
               if (mxr2) r16_de[7:0] <= d;
               if (mxr3) r16_bc[7:0] <= d;
               if (mxr4) r16_sp[7:0] <= d;
               if (mxr5) r16_wz[7:0] <= d;
            end
         if (mxwh)
            begin
               if (mxr0) r16_pc[15:8] <= d;
               if (mxr1) r16_hl[15:8] <= d;
               if (mxr2) r16_de[15:8] <= d;
               if (mxr3) r16_bc[15:8] <= d;
               if (mxr4) r16_sp[15:8] <= d;
               if (mxr5) r16_wz[15:8] <= d;
            end
      end
end

//______________________________________________________________________________
//
// processor state
//
assign sy_hlta = id_hlt;
assign sy_m1   = m1;
assign sy_inp  = m5 & id_in;
assign sy_out  = m5 & id_out;
assign sy_inta = inta;
assign sy_memr = sy_wo_n & ~sy_inp & ~minta;
assign sy_wo_n  = m1 | m2 | m3 | (((m4 & ~id86) | (m5 & ~id85)) & ~ready_int);

always @(posedge clk)
begin
   if (f1)
      begin
         sy_stack <= (t1 & t1460)
                   | (t3 & m3 & id_cxx & ~jmptake)
                   | (t5 & m1 & id_rxx & ~jmptake);
      end
end
//______________________________________________________________________________
//
// ticks state machine
//
assign twt2    = (t2f1 | twf1) & ~start;
assign thalt   = ~m1 & sy_hlta;

always @(posedge clk)
begin
   if (f1)
      begin
         t1f1 <= t1 & ~reset; // ensure the reliable start after reset
         t2f1 <= t2;
         twf1 <= tw;
         t3f1 <= t3;
         t4f1 <= t4;
         t5f1 <= t5;
      end
   if (f2)
      begin
         t1 <= start;
         t2 <= ~start & t1f1;
         tw <= ~start & (t2f1 | twf1) & (~ready | thalt);
         t3 <= ~start & (t2f1 | twf1) &  ready & ~thalt;
         t4 <= ~start & t3f1 & ms0 & ~ms1;
         t5 <= ~start & t4f1 & ms0 & ~ms1;
      end
end

//______________________________________________________________________________
//
assign m836 = m1f1 & id82;
assign m839 = ~t976 | ~sy_hlta;
assign m871 = t789 | id81;

assign start = ~m839
             | t953
             | (eom & ~(hold & t887))
             | (f2 & ((~t382 & hold) | t383) & ~(twf1 | t3f1 | t4f1 | t5f1));

assign ms0 = ~reset & m839 & ~(sy_stack & ~t1f1) & ~(eom & ~m836);
assign ms1 = ~reset & m839 & ~(sy_stack & ~t1f1) & ~(m871 & ~m836) & eom;

always @(posedge clk)
begin
   if (f1)
      begin
         t789 <= (id84 & m3) | (id83 & ~id_mvim & m4) | m5;
         t887 <= hold;
         t953 <= reset;
         t976 <= t980 & m4;
         eom <= t5
              | t4 & m1 & id80
              | t3 & m2
              | t3 & m3
              | t3 & m4
              | t3 & m5 & ~id_xthl;
      end
   if (f2)
      begin
         t980 <= sy_inta;
      end
end

//______________________________________________________________________________
//
// processor cycles state machine
//
always @(posedge clk)
begin
   if (f1)
      begin
         m1f1 <= m1;
         m2f1 <= m2;
         m3f1 <= m3;
         m4f1 <= m4;
         m5f1 <= m5;
      end
   if (f2)
      begin
         m1 <= (~ms0 & ~ms1) | (~ms1 & m1f1);
         m2 <= (~ms0 | ~ms1) & ((ms0 & m2f1) | (ms1 & m1f1));
         m3 <= (ms0 & m3f1) | (ms1 & m2f1);
         m4 <= (ms0 & m4f1) | (ms1 & m3f1) | (ms0 & ms1);
         m5 <= (ms0 & m5f1) | (ms1 & m4f1);
      end
end

//______________________________________________________________________________
//
// interrupt logic
//
assign irq = intr & inte & ~reset & ~hold;
assign pin_inte = inte;

always @(posedge clk)
begin
   if (f2) intr <= pin_int;
   if (f2) mstart <= ~ms0 & ~ms1;
   if (sy_inta) minta <= 1;
   if (f1 & t1 & m1) minta <= 0;
end

always @(posedge clk or posedge reset)
begin
   if (reset)
      begin
         inta <= 0;
         inte <= 0;
      end
   else
      begin
         if (f1)
            begin
               if (irq & ((tw & sy_hlta) | (mstart & ~id_eidi))) inta <= 1;
               if (~intr | id_eidi | (t5 & id_rst)) inta <= 0;
            end
         if (f2)
            begin
               if (t1f1 & id_eidi) inte <= i[3];
               if (t1f1 & sy_inta) inte <= 0;
            end
      end
end
//______________________________________________________________________________
//
// instruction register and decoder
//
function cmp
(
   input [7:0] i,
   input [7:0] c,
   input [7:0] m
);
   cmp = &(~(i ^ c) | m);
endfunction

assign imx     = ~(id_op | (id_mov & t4));
assign acc_sel = imx ? (i[5:3] == 3'b111) : (i[2:0] == 3'b111);
assign jmpflag =    (psw_c &  i14 & ~i25)    // Intel original: d[0] instead of psw_c
                  | (psw_p & ~i14 &  i25)    // Intel original: d[2] instead of psw_p
                  | (psw_z & ~i14 & ~i25)    // Intel original: d[6] instead of psw_z
                  | (psw_s &  i14 &  i25);   // Intel original: d[7] instead of psw_s

always @(posedge clk)
begin
   //
   // Simplify the D-bus multiplexer and feed the I-register by input pins directly
   //
   if (~f2 & (reset | (m1 & t3))) i <= pin_din;
   if (f1)
      begin
         i25 <= imx ? i[5] : i[2];
         i14 <= imx ? i[4] : i[1];
         i03 <= imx ? i[3] : i[0];
      end
end

assign goto    = id_rst | id_jmp | id_call | (jmptake & (id_cxx | id_jxx));
assign t1460   = (t1 & ( (m2 & id00)
                      | (m3 & id00)
                      | (m4 & (id01 | id04))
                      | (m5 & (id01 | id04)))
               | t2 & ( (m2 & id00)
                      | (m4 & id01)
                      | (m5 & id01))
               | t3 & ( (m4 & (id04 | id_sphl)))
               | t5 & ( (m1 & (id04 | id_sphl)))) & ~(~jmptake & id_cxx & t5);

always @(posedge clk)
begin
   if (f2 & t4f1)
      begin
         jmptake <= i03 ? jmpflag : ~jmpflag;
      end
   if (f1)
      begin
         tree0 <= t1 & ( (m1 & ~goto)
                       | (m2 & ~id_xthl)
                       | (m3 & ~id_xthl)
                       | (m4 & id02))
                | t2 & (  m1
                       | (m2 & ~id_xthl)
                       | (m3 & ~id_xthl)
                       | (m4 & (id02 | id_rst | id_cxx | id_call))
                       | (m5 & (id_rst | id_cxx | id_call)))
                | t3 & ( (m4 & (id_ret | id_rxx))
                       | (m5 & (id_ret | id_rxx)))
                | t5 & id_pchl;

         tree1 <= t1460;

         tree2 <= t1 & ( (m4 & (id_mov | id_idr | id_op))
                       | (m5 & id08))
                | t2 & ( (m4 & (id_shld | id00 | id_dad))
                       | (m5 & (id_shld | id00 | id_dad)))
                | t3 & ( (m4 & (id_lhld | id_dad))
                       | (m5 & (id_lhld | id_dad)))
                | t5 & m5;

         t2806 <= id08 & ((t3 & m4) | (t5 & m1));
         t2817 <= reset | (t3 & (m1 | m3 | (m4 & id_io) | (m5 & id06)));
         t2819 <= reset | (t3 & (m2 | (m4 & id06) | (m5 & id_rst)));

         t3047 <= m4 & (t1 | t2) & id_dad
                | t2 & ((m4 & id_shld) | (m5 & id03));

         t2998 <= (t1 | t2) & m5 & id_dad
                | t2 & ((m5 & id_shld) | (m4 & id03));

         t3403 <= t2 & ( (m1 | m2)
                       | (m3 & ~id_xthl)
                       | ((m4 | m5) & ~id_dad & ~id09))
                | t3 & m4 & id09
                | t5 & (m5 | (m1 & ~id08));

         t3363 <= t1 & (m1 | m2 | m3 | ((m4 | m5) & ~id_hlt & ~id_dad));
         t3335 <= id07 & ((t1 & (m4 | m5)) | (t3 & (m2 | m3)) | t5);

         t3361 <= t1 & m4 & id_lsax
                | t2 & id10 & ~sy_wo_n
                | t3 & id10 & sy_wo_n & (m4 | m5)
                | t5 & id08 & m1;
      end
end

assign id_nop     = cmp(i, 8'b00xxx000, 8'b00111000);
assign id_lxi     = cmp(i, 8'b00xx0001, 8'b00110000);
assign id_lsax    = cmp(i, 8'b000xx010, 8'b00011000);
assign id_inx     = cmp(i, 8'b00xx0011, 8'b00110000);
assign id_inr     = cmp(i, 8'b00xxx100, 8'b00111000);
assign id_dcr     = cmp(i, 8'b00xxx101, 8'b00111000);
assign id_idr     = cmp(i, 8'b00xxx10x, 8'b00111001);
assign id_mvi     = cmp(i, 8'b00xxx110, 8'b00111000);
assign id_dad     = cmp(i, 8'b00xx1001, 8'b00110000);
assign id_dcx     = cmp(i, 8'b00xx1011, 8'b00110000);
assign id_opa     = cmp(i, 8'b00xxx111, 8'b00111000);
assign id_idm     = cmp(i, 8'b0011010x, 8'b00000001);
assign id_stlda   = cmp(i, 8'b0011x010, 8'b00001000);
assign id_mvim    = cmp(i, 8'b00110110, 8'b00000000);
assign id_shld    = cmp(i, 8'b00100010, 8'b00000000);
assign id_lhld    = cmp(i, 8'b00101010, 8'b00000000);
assign id_mvmr    = cmp(i, 8'b01110xxx, 8'b00000111) & ~id_hlt;
assign id_mvrm    = cmp(i, 8'b01xxx110, 8'b00111000) & ~id_hlt;
assign id_hlt     = cmp(i, 8'b01110110, 8'b00000000);
assign id_mov     = cmp(i, 8'b01xxxxxx, 8'b00111111);
assign id_op      = cmp(i, 8'b10xxxxxx, 8'b00111111);
assign id_opm     = cmp(i, 8'b10xxx110, 8'b00111000);
assign id_pop     = cmp(i, 8'b11xx0001, 8'b00110000);
assign id_push    = cmp(i, 8'b11xx0101, 8'b00110000);
assign id_rst     = cmp(i, 8'b11xxx111, 8'b00111000);
assign id_xthl    = cmp(i, 8'b11100011, 8'b00000000);
assign id_sphl    = cmp(i, 8'b11111001, 8'b00000000);
assign id_pchl    = cmp(i, 8'b11101001, 8'b00000000);
assign id_xchg    = cmp(i, 8'b11101011, 8'b00000000);
assign id_cxx     = cmp(i, 8'b11xxx100, 8'b00111000);
assign id_jxx     = cmp(i, 8'b11xxx010, 8'b00111000);
assign id_rxx     = cmp(i, 8'b11xxx000, 8'b00111000);
assign id_ret     = cmp(i, 8'b110x1001, 8'b00010000);
assign id_call    = cmp(i, 8'b11xx1101, 8'b00110000);
assign id_eidi    = cmp(i, 8'b1111x011, 8'b00001000);
assign id_jmp     = cmp(i, 8'b1100x011, 8'b00001000);
assign id_io      = cmp(i, 8'b1101x011, 8'b00001000);
assign id_opi     = cmp(i, 8'b11xxx110, 8'b00111000);
assign id_in      = cmp(i, 8'b11011011, 8'b00000000);
assign id_popsw   = cmp(i, 8'b11110001, 8'b00000000);
assign id_out     = cmp(i, 8'b11010011, 8'b00000000);
assign id_11x     = cmp(i, 8'b11xxxxxx, 8'b00111111);
assign id_pupsw   = cmp(i, 8'b11110101, 8'b00000000);

assign id_rxc     = ~i[5] & i[3] & id_opa;
assign id_sha     = ~i[5]        & id_opa;
assign id_rlc     = (i[5:3] == 3'b000) & id_opa;
assign id_rar     = (i[5:3] == 3'b011) & id_opa;
assign id_daa     = (i[5:3] == 3'b100) & id_opa;
assign id_cma     = (i[5:3] == 3'b101) & id_opa;
assign id_stc     = (i[5:3] == 3'b110) & id_opa;
assign id_cmc     = (i[5:3] == 3'b111) & id_opa;

assign id_add     = (i[5:3] == 3'b000) & (id_op | id_opi);
assign id_adc     = (i[5:3] == 3'b001) & (id_op | id_opi);
assign id_sub     = (i[5:3] == 3'b010) & (id_op | id_opi);
assign id_sbb     = (i[5:3] == 3'b011) & (id_op | id_opi);
assign id_ana     = (i[5:3] == 3'b100) & (id_op | id_opi);
assign id_xra     = (i[5:3] == 3'b101) & (id_op | id_opi);
assign id_ora     = (i[5:3] == 3'b110) & (id_op | id_opi);
assign id_cmp     = (i[5:3] == 3'b111) & (id_op | id_opi);

assign id80       = id_lxi  | id_pop   | id_opm  | id_idm  | id_dad
                  | id_xthl | id_xchg  | id_jxx  | id_ret  | id_eidi
                  | id_nop  | id_stlda | id_mvmr | id_mvrm | id_hlt
                  | id_opa  | id_mvim  | id_jmp  | id_io   | id_opi
                  | id_mvi  | id_lsax  | id_lhld | id_shld | id_op;
assign id81       = id_dcx  | id_inx   | id_sphl | id_pchl | id_xchg
                  | id_eidi | id_nop   | id_opa  | id_op   | id_mov
                  | (id_idr & ~id82);
assign id82       = id_pop  | id_push  | id_opm  | id_idm  | id_dad
                  | id_rst  | id_ret   | id_rxx  | id_mvrm | id_mvmr
                  | id_hlt  | id_mvim  | id_io   | id_opi  | id_mvi
                  | id_lsax;
assign id83       = id_opm  | id_stlda | id_mvmr | id_mvrm | id_opi
                  | id_mvi  | id_lsax;
assign id84       = id_lxi  | id_jxx   | id_jmp;
assign id85       = id_push | id_idm   | id_rst  | id_xthl | id_cxx
                  | id_call | id_mvim  | id_shld | (id_io & ~i[3]);
assign id86       = id_push | id_rst   | id_xthl | id_cxx  | id_call
                  | id_mvmr | id_shld  | (~i[3] & (id_lsax | id_stlda));

assign id00       = id_xthl   | id_pchl  | id_sphl;
assign id01       = id_pop    | id_rxx   | id_ret;
assign id02       = id_mvi    | id_opi   | id_io;
assign id03       = id_rst    | id_push  | id_xthl | id_cxx  | id_call;
assign id04       = id_rst    | id_push  | id_xthl | id_cxx  | id_call;
assign id05       = id_rst    | id_push  | id_xthl | id_cxx  | id_call | id_dcx;
assign id06       = id_pop    | id_rxx   | id_ret  | id_dad  | id_lhld | id_io;
assign id07       = id_dcx    | id_inx   | id_lxi  | id_dad;
assign id08       = id_mov    | id_mvi   | id_idr  | id_op;
assign id09       = id_rst    | id_push  | id_xthl | id_cxx  | id_call | id_shld;
assign id10       = id_pop    | id_push  | id_mvrm | id_mvi;

//______________________________________________________________________________
//
// function alu
// (
//    input    rxc,
//    input    ora,
//    input    ana,
//    input    xra,
//    input    x,
//    input    r,
//    input    nc,
//    input    rn,
//    input    cp
// );
// alu = x & r & cp        & ~(rxc | ora | ana | xra)
//     | nc & (cp | x | r) & ~(rxc | ora | ana | xra)
//     | rxc & rn
//     | ora & (x | r)
//     | ana & (x & r)
//     | xra & (x ^ r);
// endfunction
//
//
// assign s[0] = alu(id_rxc, id_ora, id_ana, id_xra, x[0], r[0], ~c[0], r[1], cl) | (id_rlc & c[7]);
// assign s[1] = alu(id_rxc, id_ora, id_ana, id_xra, x[1], r[1], ~c[1], r[2], c[0]);
// assign s[2] = alu(id_rxc, id_ora, id_ana, id_xra, x[2], r[2], ~c[2], r[3], c[1]);
// assign s[3] = alu(id_rxc, id_ora, id_ana, id_xra, x[3], r[3], ~c[3], r[4], c[2]);
// assign s[4] = alu(id_rxc, id_ora, id_ana, id_xra, x[4], r[4], ~c[4], r[5], c[3]);
// assign s[5] = alu(id_rxc, id_ora, id_ana, id_xra, x[5], r[5], ~c[5], r[6], c[4]);
// assign s[6] = alu(id_rxc, id_ora, id_ana, id_xra, x[6], r[6], ~c[6], r[7], c[5]);
// assign s[7] = alu(id_rxc, id_ora, id_ana, id_xra, x[7], r[7], ~c[7], ch,   c[6]);
//
//
//______________________________________________________________________________
//
// arithmetic and logic unit
//
// assign alu_xwr = (f1 & m1 & t3) | (f2 & (a327 | t4f1 & (id_out | ~id_11x)));
//
assign alu_xwr  =  (a327 | t4f1 & (id_rst | id_out | ~id_11x));
assign alu_xout = ~(id_sub | id_sbb | id_cmp | id_cma);
assign alu_xrd  = t1698 | a358;
assign x = alu_xout ? xr : ~xr;

assign alu_ald = t2222 & ( id_adc | id_add | id_daa | id_xra | id_sbb
                         | id_sub | id_ana | id_ora | id_sha | id_cma);
assign alu_ard = t1375 | a398;
assign alu_awr = t1497 | a357;

assign alu_r00 = id_dcr & t4f1;
assign alu_srd = t1668;
assign alu_rwr = t1780;
assign alu_rld = t4f1 & (id_sha | id_op | id_opi);

assign daa = id_daa & t4f1;
assign daa_x6 = (acc[3] & (acc[2] | acc[1])) | psw_ac;
assign daa_6x = ((acc[3] & (acc[2] | acc[1])) & acc[4] & acc[7])
              | (acc[7] & (acc[6] | acc[5])) | tmp_c;

assign s  = {7'b0000000, id_rlc & c[7]}
          | ((id_rxc | id_ora | id_ana | id_xra) ? 8'h00 : (x + r + cl))
          | (id_rxc  ? {ch, r[7:1]} : 8'h00)
          | (id_ora  ? (x | r) : 8'h00)
          | (id_ana  ? (x & r) : 8'h00)
          | (id_xra  ? (x ^ r) : 8'h00);

assign cl = tmp_c & ~id_daa & ~id_rlc & ~id_ora & ~id_xra & ~id_rxc;
assign ch = tmp_c & id_rar | r[0] & ~id_rar;

//
// wire ca0_n, ca2_n, ca1, ca3;
// assign ca0_n = ~(cl   & (x[0] | r[0])) & ~(x[0] & r[0]) & ~(id_ana & id_rxc);
// assign ca2_n = ~(ca1  & (x[2] | r[2])) & ~(x[2] & r[2]) & ~(id_ana & id_rxc);
// assign ca1   = ~(~x[1] & ~r[1]) & ~(ca0_n & (~x[1] | ~r[1])) & ~(id_ora | id_rxc | id_xra);
// assign ca3   = ~(~x[3] & ~r[3]) & ~(ca2_n & (~x[3] | ~r[3])) & ~(id_ora | id_rxc | id_xra);
//
assign c[0] = (r[0] & x[0]) | (cl & (r[0] | x[0]));
assign c[1] = (r[1] & x[1]) | (c[0] & (r[1] | x[1]));
assign c[2] = (r[2] & x[2]) | (c[1] & (r[2] | x[2]));
assign c[3] = (r[3] & x[3]) | (c[2] & (r[3] | x[3]));
assign c[4] = (r[4] & x[4]) | (c[3] & (r[4] | x[4]));
assign c[5] = (r[5] & x[5]) | (c[4] & (r[5] | x[5]));
assign c[6] = (r[6] & x[6]) | (c[5] & (r[6] | x[6]));
assign c[7] = (r[7] & x[7]) | (c[6] & (r[7] | x[7]));

assign alu_frd = t2046; /* | t4f1 & (id_11x & ~id_out); */
assign alu_zrd = m1f1 & t3f1;

assign a398 = t1993 & ((t1994 & id08) | id_opa | id_stlda | id_lsax | id_io);

always @(posedge clk)
begin
   if (f1)
      begin
         t1375 <= t2 & m4 & id_pupsw;
         t1497 <= t3 & m5 & id_popsw;
         t1698 <= t5 & m1 & ~id_inr & ~id_dcr
                | t3 & m5 & id_rst;
         t1668 <= t2 & m5 & (id_inr | id_dcr)
                | t3 & m5 & id_dad
                | t3 & m4 & id_dad
                | t5 & m1 & (id_inr | id_dcr);
         t1780 <= t3 & m1
                | t1 & (m4 | m5) & id_dad;
         t2222 <= (t2 & m1) | (t1 & m5);
         a327  <= t3 & m4 & ~(id_dad | id_out | id_rst)
                | t2 & (m4 | m5) & id_dad;
         a357  <= t3 & m5 & (id_io | id_mvim) & sy_wo_n
                | t3 & m4 & (id_stlda | id_lsax | id_mvmr) & sy_wo_n
                | acc_sel & id08 & (t5 & m1 | t3 & m4);
         a358  <= t2 &  ~sy_wo_n & (id_io | id_mvim | id_stlda | id_lsax | id_mvmr);

         psw_ld   <= t3 & m4 & id_popsw;
         psw_wr   <= t2 & m1 & (id_opi | id_inr | id_dcr | id_daa | id_op);
         t2046    <= t2 & m5 & id_pupsw;  /* | reset | t3 & m1; */
//
//       t2047    <= reset
//                 | t3 & m1
//                 | t3 & m5 & id_rst;
//
         t1993    <= t4 & m1;
         t1994    <= acc_sel;
         t2133    <= ~id_rxc & c[7];
         t2175    <= t3 & m1
                   | t2 & m5 & id_dad;
      end
end

always @(posedge clk)
begin
   if (f2)
      begin
         if (alu_xwr) xr <= id_rst ? (i & 8'b00111000) : d;
         if (alu_awr) acc <= d;
         if (alu_ald) acc <= s;
         if (alu_rld) r <= acc;
         if (alu_rwr) r <= d;
         if (alu_r00) r <= 8'hff;
         if (daa)
            begin
               r[1] <= daa_x6;
               r[2] <= daa_x6;
               r[5] <= daa_6x;
               r[6] <= daa_6x;
            end
         if (psw_ld)
            begin
               psw_c  <= d[0]; // x register was in original Intel design
               psw_p  <= d[2];
               psw_ac <= d[4];
               psw_z  <= d[6];
               psw_s  <= d[7];
            end
         if (psw_wr)
            begin
               psw_p  <= ~(^s);
               psw_ac <= (c[3] & ~id_xra & ~id_ora & ~id_rxc) | (id_ana & (x[3] | r[3]));
               psw_z  <= ~(|s);
               psw_s  <= s[7];
            end
         if (t2222)
            begin
               if (id_xra | id_stc | id_ora | id_ana | id_cmc)
                  psw_c <= ~tmp_c;
               if (id_cmp | id_sbb | id_sub)
                  psw_c <= ~(t2133 | id_rxc & x[0]);
               if (id_dad | id_sha | id_adc | id_add)
                  psw_c <= t2133 | id_rxc & x[0];
            end
         if (daa & daa_6x)
                  psw_c <= 1'b1;

         if (t2175)
            tmp_c <= psw_c;
         if (t4f1)
            begin
               if (id_sbb)
                  tmp_c <= ~psw_c;
               if (id_inr | id_ora | id_xra | id_ana | id_cmp | id_sub)
                  tmp_c <= 1'b1;
               if (id_dad | id_cma | id_dcr | id_add | id_stc)
                  tmp_c <= 1'b0;
            end
      end
end

//______________________________________________________________________________
//
endmodule
