m8266_ucode
// 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