// m8266_ucode
//
// pdp11/34a microcode system.
// Module is M8266
// see "1134A Field Maintenance Print Set (Jan 1977, MP00190).pdf"
// sheets K2-7 ,-8, -9, -10//
//
// this module
// - accesses the primary micro store 512x 48 bit made from 12 roms
// - splits the primary code store into fields
// - expands some fields with secondary ROMs
// - displays the final fields


/* unexpanded fields directly from primary code store
E110.11   00            MPC08
E110.12   01            MPC07
E110.13   02            MPC06
E110.14   03            MPC05
E109.11   04            MPC04
E109.12   05            MPC03
E109.13   06            MPC02
E109.14   07            MPC01
E108.11   08            MPC00

E108.12   09            MISC CONTROL.0 1=K2-7 LOAD IRL, 2=LOAD PSW L, 3=LOAD CC L,
E108.13   10            MISC CONTROL.1 4=BUT DEST L, 5=ENAB STOV L,
E108.14   11            MISC CONTROL.2 6=LAOD COUNT L, 7=CLK COUNT L

E107.11   12            BUF DAT TRAN H

E107.12   13            BUF C1 H
E107.13   14            BUF C0 H

E107.14   15            ENAB MAINT H

E106.11   16            LOAD BA H

E106.12   17            LONG CYCLE L

E106.13   18            AUX CONTROL

E106.14   19            ALU                  TO ROM E82
E99.11    20            ALU FUNC CODE 03 H
E99.12    21            ALU FUNC CODE 02 H
E99.13    22            ALU FUNC CODE 01 H
E99.14    23            ALU FUNC CODE 00 H

E97.11    24            B
E97.12    25            BX
E97.13    26            OVX
E97.14    27            DBE

E98.14    28            SSMUX CONTROL SS01
E98.13    29            SSMUX CONTROL SS00

E98.12    30            AMUX CONTROL AMUX S1
E98.11    31            AMUX CONTROL AMUX S0
E100.11   32            BUT BIT 0
E100.12   33            BUT BIT 1
E100.13   34            BUT BIT 2
E100.14   35            BUT BIT 3
E104.11   36            SPA SRC SEL 1
E104.12   37            SPA SRC SEL 0
E104.13   38            SPA DEST SEL 1
E104.14   39            SPA DEST SEL 0
E103.11   40            FORCE RSVI L
E103.12   41            PREVIOUS MODE L
E103.13   42            BUT SERVICE H
E103.14   43            FORCE KERNEL H

E105.11   44            ROM SPA 03
E105.12   45            ROM SPA 02
E105.13   46            ROM SPA 01
E105.14   47            ROM SPA 00
*/

// output: print
module m8266_ucode() ;

  reg [8:0]     mpc ; // micro program counter is 9 bit

  /*** the different micro code fields ***/
  wire [47:0]   ustore_primary_q ; // primary ustore data
  // fields
  wire [8:0]    mpc_next ; // next mpc for this micro word
  wire [2:0]    misc_control ;
  wire          buf_dat_tran ;
  wire [1:0]    buf_c1c0 ; // type of UNIBUs bus cycle: c1, C0
  wire          enab_maint ;
  wire          load_ba ;
  wire          long_cycle_l ;
  wire          aux_control ;
  wire [4:0]    _e82_addr ; // input to e82 address lines, unlabeld, function code s3..s0
  wire [7:0]    _e82_q ; // data output
  wire [3:0]    alu_func ;// ALU s3..s0
  wire          alu_mode ;
  wire          alu_cin_l ;
  wire [1:0]    bleg ; // bleg control 01,00

  wire [4:0]    _e87_addr ; // input to e87 address lines, decode B,BX,OVX,DBE
  wire [7:0]    _e87_q ; // data output
  wire [1:0]    b_mode_l ; // BMODE 01,00
  wire [1:0]    bx_mode_l ; // BXMODE 01,00
  wire [1:0]    shift_mux_l ; // 01,00
  wire          enab_ovx_l ;
  wire          enab_dbe_l ;

  wire [1:0]    ssmux ; //ss01, ss00
  wire [1:0]    amux_l ; // amux s1, s0

  wire [4:0]    _e102_addr ; // encode control lines for microbranch
  wire [7:0]    _e102_q ; // data output
  wire          but_alu_out_mpc7 ; // if 1: add certain signals to mpc
  wire          but_cc_n_mpc6 ; //
  wire          but_bxreg01_mpc5 ; //
  wire          but_bxreg00_mpc4 ; //
  wire          but_sp15_mpc3 ; //
  wire          but_count05_mpc2 ; //
  wire          but_cc_z_mpc1 ; //
  wire          but_ir09_mpc0 ; //

  wire [1:0]    spa_src_sel ; // scratch pad source select
  wire [1:0]    spa_dst_sel ; // scratch pad destination select

  wire         force_rsv1_l ;

  wire          previous_mode_l ;   // last memory management mode

  wire          but_service ;   //
  wire          force_kernel ;   //
  wire [3:0]    rom_spa ;   //  netx scratch pad register addr

  // wire the fields
  assign mpc_next[8]      = ustore_primary_q[0] ; // next mpc is encoded bit reveresed
  assign mpc_next[7]      = ustore_primary_q[1] ;
  assign mpc_next[6]      = ustore_primary_q[2] ;
  assign mpc_next[5]      = ustore_primary_q[3] ;
  assign mpc_next[4]      = ustore_primary_q[4] ;
  assign mpc_next[3]      = ustore_primary_q[5] ;
  assign mpc_next[2]      = ustore_primary_q[6] ;
  assign mpc_next[1]      = ustore_primary_q[7] ;
  assign mpc_next[0]      = ustore_primary_q[8] ;

  assign misc_control[2]  = ustore_primary_q[9] ;
  assign misc_control[1]  = ustore_primary_q[10] ;
  assign misc_control[0]  = ustore_primary_q[11] ;

  assign buf_dat_tran     =  ustore_primary_q[12] ;
  assign buf_c1c0[1]      = ustore_primary_q[13] ;
  assign buf_c1c0[0]      = ustore_primary_q[14] ;
  assign enab_maint       = ustore_primary_q[15] ;
  // attention: error in DEC dock!
  assign load_ba          = ustore_primary_q[17] ;
  assign long_cycle_l       = ustore_primary_q[16] ;
  // assign load_ba          = ustore_primary_q[16] ;
  // assign long_cycle       = ustore_primary_q[17] ;
  assign aux_control      = ustore_primary_q[18] ;

  // alu signal generation with e82 = n82s123
  assign _e82_addr[1]     = ustore_primary_q[19] ; // A1 = pin 11
  assign _e82_addr[3]     = ustore_primary_q[20] ; // A3 = pin 13
  assign _e82_addr[2]     = ustore_primary_q[21] ;  // A2 = pin 12
  assign _e82_addr[0]     = ustore_primary_q[22] ;  // A0 = pin 10
  assign _e82_addr[4]     = ustore_primary_q[23] ;  // A4 = pin 14
  // output of e82 controls the alu
  assign alu_func[3]      = ~_e82_q[0] ; // O1 = pin 1, + inverter E81
  assign alu_func[2]      = ~_e82_q[1] ; // O2 = pin 2
  assign alu_func[1]      = ~_e82_q[3] ; // O4 = pin 4
  assign alu_func[0]      = ~_e82_q[4] ; // O5 = pin 5
  assign alu_mode         = _e82_q[2] ; // O3 = pin 3
  assign alu_cin_l        = _e82_q[5] ; // O6 = pin 6
  assign bleg[1]          = _e82_q[6] ; // O7 = pin 7
  assign bleg[0]          = _e82_q[7] ; // O8 = pin 9

  // BX,B,OVX,DBE signal generation with E87 = N82S123
  assign _e87_addr[0]     = 0 ; // A0 = pin 10
  assign _e87_addr[1]     = ustore_primary_q[24] ; // A1 = pin 11
  assign _e87_addr[4]     = ustore_primary_q[25] ;  // A4 = pin 14
  assign _e87_addr[2]     = ustore_primary_q[26] ;  // A2 = pin 12
  assign _e87_addr[3]     = ustore_primary_q[27] ;  // A3 = pin 13

  assign b_mode_l[1]      = ~_e87_q[0] ; // O1 = pin 1 + inverter E91
  assign b_mode_l[0]      = ~_e87_q[1] ; // O2 = pin 2
  assign bx_mode_l[1]     = _e87_q[2] ; // O3 = pin 3
  assign bx_mode_l[0]     = _e87_q[3] ; // O4 = pin 4
  assign shift_mux_l[1]   = _e87_q[4] ; // O5 = pin 5
  assign shift_mux_l[0]   = _e87_q[5] ; // O6 = pin 6
  assign enab_ovx_l       = _e87_q[6] ; // O7 = pin 7
  assign enab_dbe_l       = _e87_q[7] ; // O8 = pin 9

  assign ssmux[1]         = ustore_primary_q[28] ;
  assign ssmux[0]         = ustore_primary_q[29] ;

  assign amux_l[1]        = ustore_primary_q[30] ;
  assign amux_l[0]        = ustore_primary_q[31] ;

  // encode control lines for microbranch with E102 = N82S123
  assign _e102_addr[1]    = ustore_primary_q[32] ; // A1 = pin 11
  assign _e102_addr[4]    = ustore_primary_q[33] ;  // A4 = pin 14
  assign _e102_addr[2]    = ustore_primary_q[34] ;  // A2 = pin 12
  assign _e102_addr[3]    = ustore_primary_q[35] ;  // A3 = pin 13
  assign _e102_addr[0]    = 1 ; // A0 = pin 10

  assign but_alu_out_mpc7 = _e102_q[0] ; // O1 = pin 1
  assign but_cc_n_mpc6    = _e102_q[1] ; // O2 = pin 2
  assign but_bxreg01_mpc5 = _e102_q[3] ; // O4 = pin 4
  assign but_bxreg00_mpc4 = _e102_q[4] ; // O5 = pin 5
  assign but_sp15_mpc3    = _e102_q[2] ; // O3 = pin 3
  assign but_count05_mpc2 = _e102_q[5] ; // O6 = pin 6
  assign but_cc_z_mpc1    = _e102_q[6] ; // O7 = pin 7
  assign but_ir09_mpc0    = _e102_q[7] ; // O8 = pin 9

  assign spa_src_sel[1]   = ustore_primary_q[36] ; // scratch pad source select
  assign spa_src_sel[0]   = ustore_primary_q[37] ;
  assign spa_dst_sel[1]   = ustore_primary_q[38] ; // scratch pad destination select
  assign spa_dst_sel[0]   = ustore_primary_q[39] ;

  assign force_rsv1_l     = ustore_primary_q[40] ;
  assign previous_mode_l  = ustore_primary_q[41] ;  // last memory management mode
  assign but_service      = ustore_primary_q[42] ;
  assign force_kernel     = ustore_primary_q[43] ;

  assign rom_spa[3]       = ustore_primary_q[44] ;  //  netx scratch pad register addr
  assign rom_spa[2]       = ustore_primary_q[45] ;
  assign rom_spa[1]       = ustore_primary_q[46] ;
  assign rom_spa[0]       = ustore_primary_q[47] ;

        /***************** print all micro code words *****************/

 integer fileid ;
 integer i, j, empty ;
 // save for every mpc the next address
 reg [8:0]mpc_next_table[0:511] ;

 initial
   begin
     fileid = $fopen("m8266_ucode.out", "w");
     if (fileid == 0) begin
       $display("ERROR : CAN NOT OPEN THE FILE");
     end
     // build jump table
     mpc = 0 ;
     for (i=0 ; i < 512 ; i = i+1) begin
       #1 // necessary for evaluation!!!
       mpc_next_table[i] = mpc_next ;
       mpc = mpc + 1 ;
     end  
     
     mpc = 0 ;
     for (i=0 ; i < 512 ; i = i+1) begin
       #1 // necessary for evaluation!!!
       // $display("B %o: %b", mpc, ustore_primary_q) ;
       print_uword_fields ;
       mpc = mpc + 1 ;
     end
   $fclose(fileid) ;
  end

  reg [256*8:0] s; // string

  /*** function which prints one micro word with addr 'mpc' ***/
  task print_uword_fields ;
    begin
      $fwrite(fileid, "***** PDP-11/34a micro code word for MPC = %o *****\n", mpc);
      $fwrite(fileid, "  (MSB is left, indented fields generated by expansion ROMs)\n");

      $fwrite(fileid, "micro word........ = %b %b %b %b %b %b %b %b %b %b %b %b\n",
      ustore_primary_q[47:44],
      ustore_primary_q[43:40],
      ustore_primary_q[39:36],
      ustore_primary_q[35:32],
      ustore_primary_q[31:28],
      ustore_primary_q[27:24],
      ustore_primary_q[23:20],
      ustore_primary_q[19:16],
      ustore_primary_q[15:12],
      ustore_primary_q[11:8],
      ustore_primary_q[7:4],
      ustore_primary_q[3:0]
      );
      $fwrite(fileid, "           from ROM: E105 E103 E104 E100 E98  E97  E99  E106 E107 E108 E109 E110\n");


    // which steps can call this micro word
      $fwrite(fileid, "Called by......... = ");
    empty = 1 ;
    for (j=0 ; j < 512 ; j = j+1) begin
      if (mpc_next_table[j] == mpc) begin
        $fwrite(fileid, "%o ", j[8:0]) ;
        empty = 0 ;
      end 
    end 
    if (empty == 1)
        // no direct jumps to this uword found
        $fwrite(fileid, "IR or BUT only") ;
    $fwrite(fileid, "\n") ;

      $fwrite(fileid, "NEXT MPC.......... = %o\n", mpc_next) ;

      case (misc_control)
        1: s = "LOAD IR L" ;
        2: s = "LOAD PSW L" ;
        3: s = "LOAD CC L" ;
        4: s = "BUT DEST L" ;
        5: s = "ENAB STOV L" ;
        6: s = "LOAD COUNT L" ;
        7: s = "CLK COUNT L" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "Misc Control...... = %b = %0s\n", misc_control, s) ;

      $fwrite(fileid, "BUF DAT TRAN...... = %b\n", buf_dat_tran) ;

      case (buf_c1c0)
        0: s = "DATI" ;
        1: s = "DATIP" ;
        2: s = "DATO" ;
        3: s = "DATOB" ;
      endcase
      $fwrite(fileid, "Bus Control ...... = %b = %0s\n", buf_c1c0, s) ;

      $fwrite(fileid, "ENAB MAINT........ = %b\n", enab_maint) ;
      $fwrite(fileid, "LOAD BAR.......... = %b\n", load_ba) ;
      $fwrite(fileid, "LONG CYCLE L...... = %b\n", long_cycle_l) ;
      $fwrite(fileid, "AUX CONTROL....... = %b\n", aux_control) ;
      $fwrite(fileid, "_e82_addr......... = %b\n", _e82_addr) ;
      $fwrite(fileid, "  _e82_data....... = %b\n", _e82_q) ;
      // see 74181 data sheet
      // symbol interpretion: https://en.wikipedia.org/wiki/List_of_logic_symbols
      // Table for "High operands". 
      // comments: listed on Table 4-2 on page 4-7
      case (alu_mode) 
        0: // mode=L: arithmetic. 
        case ({~alu_cin_l,alu_func}) 
        // Carry in = 0
        5'b00000: s= "A" ;
        5'b00001: s= "A | B" ;
        5'b00010: s= "A | ~B" ;
        5'b00011: s= "minus 1" ;
        5'b00100: s= "A plus (A & ~B)" ;
        5'b00101: s= "(A | B) plus (A & ~B)" ;
        5'b00110: s= "A minus B minus 1" ;
        5'b00111: s= "(A & B) minus 1" ;
        5'b01000: s= "A plus (A & B)" ;
        5'b01001: s= "A plus B" ;
        5'b01010: s= "(A | ~B) plus (A & B)" ;
        5'b01011: s= "(A & B) minus 1" ;
        5'b01100: s= "A plus A (shift)" ;
        5'b01101: s= "(A | B) plus A" ;
        5'b01110: s= "(A | ~B) plus A" ;
        5'b01111: s= "A minus 1" ;
        // carry in = 1: always "plus 1"
        5'b10000: s= "A plus 1" ;
        5'b10001: s= "(A | B) plus 1" ;
        5'b10010: s= "(A | ~B) plus 1" ;
        5'b10011: s= "0" ;
        5'b10100: s= "A plus (A & ~B) plus 1" ;
        5'b10101: s= "(A | B) plus (A & ~B)  plus 1" ;
        5'b10110: s= "A minus B" ;
        5'b10111: s= "(A & B)" ;
        5'b11000: s= "A plus (A & B) plus 1" ;
        5'b11001: s= "A plus B plus 1" ;
        5'b11010: s= "(A | ~B) plus (A & B) plus 1" ;
        5'b11011: s= "(A & B)" ;
        5'b11100: s= "A plus A  plus 1" ;
        5'b11101: s= "(A | B) plus A plus 1" ;
        5'b11110: s= "(A | ~B) plus A plus 1" ;
        5'b11111: s= "A" ;
        endcase
      1:
        // mode=H: logic
        case (alu_func) 
        4'b0000: s= "~A" ;
        4'b0001: s= "~A | ~B" ;
        4'b0010: s= "~A & B" ;
        4'b0011: s= "Logic 0" ;
        4'b0100: s= "~(A & B)" ;
        4'b0101: s= "~B" ;
        4'b0110: s= "A xor B" ;
        4'b0111: s= "A & ~B" ;
        4'b1000: s= "~A | B" ;
        4'b1001: s= "~A xor ~B" ;
        4'b1010: s= "B" ;
        4'b1011: s= "A & B" ;
        4'b1100: s= "logic 1" ;
        4'b1101: s= "A | ~B" ;
        4'b1110: s= "A | B" ;
        4'b1111: s= "A" ;
      endcase
      endcase
      /* original table 4-2 on page 4-7 .. .trash??
      case ({alu_func,~alu_cin_l,alu_mode}) 
        6'b001101: s = "ZERO" ;
        6'b000001: s = "A" ;
        6'b000000: s = "A plus 1" ;
        6'b111110: s = "A minus 1" ;
        6'b011000: s = "A minus B" ;
        6'b111101: s = "A" ;
        6'b101001: s = "B" ;
        6'b100110: s = "A plus B" ;
        6'b101101: s = "A B" ;
        6'b001001: s = "A B" ;
        6'b100000: s = "A plus B plus 1" ;
        6'b110010: s = "A plus A" ;
        6'b010101: s = "B" ;
        6'b110000: s = "A plus A plus 1" ;
        6'b011001: s = "A + B" ;
        default: s = "?" ;
      endcase
      */
      $fwrite(fileid, "  ALU FUNC,MODE,CIN_L= %b,%b,%b = %0s\n", alu_func, alu_mode, alu_cin_l, s);

      case (bleg) // Figure 4-9 "BMUX Block Diagram", page 4-16
        0: s = "B-REG to BMUX" ;
        1: s = "BX-REG to BMUX" ;
        2: s = "+16 to BMUX" ;
        3: s = "+1 to BMUX" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "  BLEG............ = %b = %0s\n", bleg, s);

      $fwrite(fileid, "_e87_addr......... = %b\n", _e87_addr) ;
      $fwrite(fileid, "  _e87_data....... = %b\n", _e87_q) ;

      case ({~b_mode_l[1],~b_mode_l[0]}) // Figure 4-6 "B Leg Block Diagram", page 4-12
        0: s = "HOLD" ;
        1: s = "SHIFT RIGHT" ;
        2: s = "SHIFT LEFT" ;
        3: s = "LOAD" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "  B MODE L........ = %b = %0s\n", b_mode_l, s) ;

      case ({~bx_mode_l[1],~bx_mode_l[0]}) // Figure 4-8 "BX REG Block Diagram", page 4-15
        0: s = "HOLD" ;
        1: s = "SHIFT RIGHT" ;
        2: s = "SHIFT LEFT" ;
        3: s = "LOAD" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "  BX MODE L....... = %b = %0s\n", bx_mode_l, s) ;

      $fwrite(fileid, "  SHIFT MUX L..... = %b\n", shift_mux_l) ;
      $fwrite(fileid, "  ENAB OVX L...... = %b\n", enab_ovx_l) ;
      $fwrite(fileid, "  ENAB DBE L...... = %b\n", enab_dbe_l) ;

      case ({ssmux[1],ssmux[0]})
        0: s = "Straight" ;
        1: s = "Sign Extend" ;
        2: s = "Swap Bytes" ;
        3: s = "External Data" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "SSMUX SS.......... = %b = %0s\n", ssmux, s) ;

      case ({~amux_l[1],~amux_l[0]}) // Figure 4-11 " AMUX" page 4-22
        0: s = "Unibus" ;
        1: s = "Constants" ;
        2: s = "ALU" ;
        3: s = "PSW" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "AMUX L............ = %b = %0s\n", amux_l, s) ;

      $fwrite(fileid, "_e102_addr........ = %b\n", _e102_addr) ;
      $fwrite(fileid, "  _e102_data...... = %b\n", _e102_q) ;
      $fwrite(fileid, "  but_alu_out_mpc7 = %b\n", but_alu_out_mpc7);
      $fwrite(fileid, "  but_cc_n_mpc6... = %b\n", but_cc_n_mpc6);
      $fwrite(fileid, "  but_bxreg01_mpc5 = %b\n", but_bxreg01_mpc5);
      $fwrite(fileid, "  but_bxreg00_mpc4 = %b\n", but_bxreg00_mpc4);
      $fwrite(fileid, "  but_sp15_mpc3... = %b\n", but_sp15_mpc3);
      $fwrite(fileid, "  but_count05_mpc2 = %b\n", but_count05_mpc2);
      $fwrite(fileid, "  but_cc_z_mpc1... = %b\n", but_cc_z_mpc1);
      $fwrite(fileid, "  but_ir09_mpc0... = %b\n", but_ir09_mpc0);

      case (spa_src_sel)
        0: s = "ROM" ;
        1: s = "RS" ;
        2: s = "RD" ;
        3: s = "RBA" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "SPA SRC SEL....... = %b = %0s\n", spa_src_sel, s) ;

      case (spa_dst_sel)
        0: s = "ROM" ;
        1: s = "RS" ;
        2: s = "RD" ;
        3: s = "RBA" ;
        default: s = "?" ;
      endcase
      $fwrite(fileid, "SPA DST SEL....... = %b = %0s\n", spa_dst_sel, s) ;

      $fwrite(fileid, "FORCE RSV1 L...... = %b\n", force_rsv1_l) ;
      $fwrite(fileid, "PREVIOUS MODE L... = %b\n", previous_mode_l) ;
      $fwrite(fileid, "BUT SERVICE....... = %b\n", but_service) ;
      $fwrite(fileid, "FORCE KERNEL.....  = %b\n", force_kernel) ;
      $fwrite(fileid, "ROM SPA..........  = %b\n", rom_spa) ;

      $fwrite(fileid, "\n\n\n");
    end
  endtask


  // Instantiate the primary 512x48 micro store
  m8266_ustore_primary ustore_primary( .mpc(mpc), .q(ustore_primary_q) ) ;

  // Instantiating secondary ROMS E82,E87,E102
  m8266_e82 e82( .a(_e82_addr), .q(_e82_q) ) ;

  m8266_e87 e87( .a(_e87_addr), .q(_e87_q) ) ;

  m8266_e102 e102( .a(_e102_addr), .q(_e102_q) ) ;


endmodule
