// // Copyright (c) 2014-2022 by 1801BM1@gmail.com // // DC303 Control Chip model // // - DC303_CS = 0, 23-001C7-AA, rni = ma[8:0] == 9'x000 // - DC303_CS = 1, 23-002C7-AA, rni = ma[8:0] == 9'x000 // - DC303_CS = 2, 23-203C7-AA, rni = ma[8:4] == 5'x00 //______________________________________________________________________________ // module dc303 #(parameter DC303_FPP = 1) ( input pin_clk, // main clock input pin_mce_p, // master rising edge input pin_mce_n, // master falling edge input [15:0] pin_ad, // address/data bus output [15:0] pin_m, // microinstruction bus input [15:0] pin_mc, // microinstruction latched status input [12:0] pin_svc, // service status word input pin_bra, // microinstruction branch input pin_rst, // reset output pin_cs // chip select ); //______________________________________________________________________________ // reg [15:0] mi; // MIB input register on clock low phase reg [15:0] d; // data word input register wire [15:0] da; // reg [2:0] cs; // chip select // reg axt; // address extension bit reg [8:0] nar; // next address register wire [8:0] na; // next address mux value wire [3:0] clr_na; // special address na clear // wire [8:0] ma; // address read from ROM matrix wire [15:0] mc; // microcode read from ROM matrix reg [9:0] a_in; // address inputs for ROM/PLA reg [15:0] d_in; // data inputs for ROM/PLA // wire [8:0] ma_pla; // address from PLA wire [8:0] ma_pla0; // wire [8:0] ma_pla1; // wire [8:0] ma_pla2; // // wire [8:0] ma_rom; // address from ROM wire [8:0] ma_rom0; // wire [8:0] ma_rom1; // wire [8:0] ma_rom2; // // wire [15:0] mc_pla; // microcode from PLA wire [15:0] mc_pla0; // wire [15:0] mc_pla1; // wire [15:0] mc_pla2; // // wire [15:0] mc_rom; // microcode from ROM wire [15:0] mc_rom0; // wire [15:0] mc_rom1; // wire [15:0] mc_rom2; // // wire [15:0] svc; // service status word reg rni; // read next instruction wire jump; // jump microinstruction wire cjmp; // conditional jump microinstruction wire di_stb; // data input service word strobe // reg [2:0] pri; // priority reg tbit; // T-bit reg wpsw; // reg wpswt; // reg lplm; // reg sovf; // stack overflow // wire [7:0] dc; // processor opcode decoder wire [4:0] dcop; // decoded opcodes reg na_x00; // na == 9'b000001x00 reg na_xxx; // na == 9'b000001xxx reg na_111; // na == 9'b000001111 // wire pri_stb; // priority register strobe wire tbit_stb; // T-bit strobe wire tgl_axt; // toggle address extension wire mc_dt; // replace microcode with data wire na_dt; // replace next address with data // reg set_soft; // reg clr_soft; // wire set_sof; // set stack overflow wire set_lplm; // wire set_wpsw; // wire clr_lplm; // // //______________________________________________________________________________ // // Microinstruction bus (MIB) // always @(posedge pin_clk or posedge pin_rst) begin if (pin_rst) mi <= 16'h0000; else if (pin_mce_n) mi <= mc; end assign pin_m = mi; //______________________________________________________________________________ // // Next microinstruction address (NA) // assign jump = (mi[15:11] == 5'b00000); assign cjmp = ~pin_bra & (mi[15:11] == 5'b00001); // // na[3:0] - reset at dedicated addresses // na[7:0] - overriden by conditional jump // na[5:0] - overriden by unconditional jump // na[8:6] - cleared by unconditional jump // assign na[0] = (jump | cjmp) ? mi[0] : (nar[0] & ~(clr_na[0] & ~rni)); assign na[1] = (jump | cjmp) ? mi[1] : (nar[1] & ~(clr_na[1] & ~rni)); assign na[2] = (jump | cjmp) ? mi[2] : (nar[2] & ~(clr_na[2] & ~rni)); assign na[3] = (jump | cjmp) ? mi[3] : (nar[3] & ~(clr_na[3] & ~rni)); assign na[4] = (jump | cjmp) ? mi[4] : nar[4]; assign na[5] = (jump | cjmp) ? mi[5] : nar[5]; assign na[6] = cjmp ? mi[6] : (nar[6] & ~jump); assign na[7] = cjmp ? mi[7] : (nar[7] & ~jump); assign na[8] = nar[8] & ~jump; always @(posedge pin_clk or posedge pin_rst) begin if (pin_rst) cs <= 3'b001; else if (jump & pin_mce_p) begin cs[0] <= (mi[10:6] == 5'b00000); cs[1] <= (mi[10:6] == 5'b00001) && DC303_FPP; cs[2] <= (mi[10:6] == 5'b00010) && DC303_FPP; end end assign pin_cs = (cs[2:0] != 3'b000); //______________________________________________________________________________ // always @(posedge pin_clk) begin if (pin_mce_n) begin if (pri_stb) pri[2:0] <= pin_ad[7:5]; if (tbit_stb) tbit <= pin_ad[4]; end end function dc_cmp ( input [7:0] dc, input [3:0] mo, input [3:0] ms ); begin casex(dc) {mo, ms}: dc_cmp = 1'b1; default: dc_cmp = 1'b0; endcase end endfunction assign dc[7:0] = {mi[7:4], pin_mc[9], pin_mc[6:4]}; assign pri_stb = dc_cmp(dc, 4'bxxxx, 4'bx10x); // transfer prio assign tbit_stb = dc_cmp(dc, 4'bxxxx, 4'bx1x0); // transfer tbit assign tgl_axt = dc_cmp(dc, 4'bxx0x, 4'bx000); assign mc_dt = dc_cmp(dc, 4'bxx10, 4'bx000); // data to mc assign na_dt = dc_cmp(dc, 4'bxxx1, 4'bx000); // data to na assign set_sof = dc_cmp(dc, 4'bxxxx, 4'bx010) & set_soft; // stack ovf assign set_lplm = dc_cmp(dc, 4'b000x, 4'b1001) & tbit; assign clr_lplm = dc_cmp(dc, 4'bxxx1, 4'bx1x0); assign set_wpsw = dc_cmp(dc, 4'bxx1x, 4'b0100); always @(posedge pin_clk) begin if (pin_mce_n) begin if (set_lplm) lplm <= 1'b1; if (clr_lplm) lplm <= 1'b0; if (set_sof) sovf <= 1'b1; else if (clr_lplm & clr_soft) sovf <= 1'b0; end if (pin_mce_p) begin if (rni) set_soft <= 1'b1; if (sovf) set_soft <= 1'b0; clr_soft <= ~lplm; end if (pin_mce_n) wpswt <= wpsw; if (pin_mce_n & set_wpsw) wpsw <= 1'b1; if (pin_rst | pin_mce_p & ~rni & wpswt) wpsw <= 1'b0; if (pin_mce_p & (rni | jump)) axt <= 1'b0; else if (pin_mce_n & tgl_axt) axt <= ~axt; end //______________________________________________________________________________ // // Data input register can be written directly from AD bus on clock high (di_stb), // or be written with interrupt statuses on clock low (rni)) // always @(posedge pin_clk or posedge pin_rst) begin if (pin_rst) rni <= 1'b1; else rni <= (ma[8:4] == 5'b00000) & ((ma[3:0] == 4'b0000) | cs[2]) & (cs != 3'b000); end assign di_stb = ~pin_mc[13] & ~pin_mc[6] & ~pin_mc[5]; // // Internal requests, provided by internal logic // // DAL15 - stack overflow // DAL14 - lplm // DAL13 - wpsw // // External service word, provided by CPU board // // DAL12 - timer event request, high level // DAL11 - IRQ[4], high level // DAL10 - IRQ[5], high level // DAL9 - IRQ[6], high level // DAL8 - IRQ[7], high level // DAL7 - ACLO (power down), low level // DAL6 - ground (always asserted) // DAL5 - HALT request, high level // DAL4 - Control Chip Error, low level // DAL3 - MMU requests abort, low level // DAL2 - parity error, low level // DAL1 - bus timeout, high level // DAL0 - DCLO, low level means OK // assign svc[7:0] = pin_svc[7:0]; assign svc[8] = pin_svc[8] & (pri[2:0] < 3'o7); // IRQ7 masking assign svc[9] = pin_svc[9] & (pri[2:0] < 3'o6); // IRQ6 masking assign svc[10] = pin_svc[10] & (pri[2:0] < 3'o5); // IRQ5 masking assign svc[11] = pin_svc[11] & (pri[2:0] < 3'o4); // IRQ4 masking assign svc[12] = pin_svc[12] & (pri[2:0] < 3'o6); // EVNT masking assign svc[13] = sovf; assign svc[14] = lplm; assign svc[15] = wpsw; always @(posedge pin_clk) begin if (pin_mce_n & di_stb) d <= pin_ad; if (pin_mce_p & rni) d <= svc; end assign da = di_stb ? pin_ad : d; //______________________________________________________________________________ // // PDP-11 opcode decoder for special microcode addresses // function op_cmp ( input [9:0] d, input [9:0] m ); begin casex(d) m: op_cmp = 1'b1; default: op_cmp = 1'b0; endcase end endfunction //______________________________________________________________________________ // // The results of reading Next Address matrix from physical chip (cs=00) // and following ESPRESSO AB minimization // // na d[15:0] dcop na_xxx // // 111 0000-00001------ 1000 1 111 na_clr[3] // 111 0000100--------- 1000 1 111 // // --- -1-0000---000--- 0100 4,2 xxx na_clr[2] // --- --01000---000--- 0100 4,2 xxx // --- -01-000---000--- 0100 4,2 xxx // -11 1000110-0-000--- 0100 4,0 111 // -11 -0001100--000--- 0100 4,0 111 // -11 -000110--1000--- 0100 4,0 111 // -11 -000101---000--- 0100 4,0 111 // -11 01110-----000--- 0100 4,0 111 // -11 0111-00---000--- 0100 4,0 111 // -11 0---000011000--- 0100 4,0 111 // -00 ----------000--- 0100 4 x00 // // --- -1-0000--------- 0010 3,2 xxx na_clr[1] // --- --01000--------- 0010 3,2 xxx // --- -01-000--------- 0010 3,2 xxx // 1-1 1000110-0------- 0010 0 111 // 1-1 -0001100-------- 0010 0 111 // 1-1 -000110--1------ 0010 0 111 // 1-1 -000101--------- 0010 0 111 // 1-1 01110----------- 0010 0 111 // 1-1 0111-00--------- 0010 0 111 // 1-1 0---000011------ 0010 0 111 // // --- -1-0------------ 0001 3 xxx na_clr[0] // --- --01------------ 0001 3 xxx // --- -01------------- 0001 3 xxx // assign dcop[0] = op_cmp(d[15:6], 10'b1000110100) // mtps | op_cmp(d[15:6], 10'bx0001100xx) // single operand x06xxx | op_cmp(d[15:6], 10'bx0001101x1) // | op_cmp(d[15:6], 10'bx000101xxx) // single operand x05xxx | op_cmp(d[15:6], 10'b01110xxxxx) // eis | op_cmp(d[15:6], 10'b0111100xxx) // xor | op_cmp(d[15:6], 10'b0000000011); // swab // assign dcop[1] = op_cmp(d[15:6], 10'b0000000001) // jmp | op_cmp(d[15:6], 10'b0000100xxx); // br // assign dcop[2] = d[11:9] == 3'b000; // source register mode assign dcop[4] = d[5:3] == 3'b000; // destination register mode // assign dcop[3] = op_cmp(d[15:6], 10'bxx01xxxxxx) // not x0xxxx and not x7xxxx | op_cmp(d[15:6], 10'bx01xxxxxxx) // normal opcode | op_cmp(d[15:6], 10'bx1x0xxxxxx); // always @(posedge pin_clk or posedge pin_rst) begin if (pin_rst) begin na_x00 <= 1'b0; na_xxx <= 1'b0; na_111 <= 1'b0; nar <= 9'h000; end else if (pin_mce_n) begin na_x00 <= (ma[8:3] == 6'b000001) & (ma[1:0] == 2'b00); na_xxx <= ma[8:3] == 6'b000001; na_111 <= ma[8:0] == 9'b000001111; nar <= ma; end end assign clr_na[0] = na_xxx & dcop[3]; assign clr_na[1] = na_xxx & dcop[3] & dcop[2] | na_111 & dcop[0]; assign clr_na[2] = na_xxx & dcop[4] & dcop[2] & dcop[3] | na_111 & dcop[4] & dcop[0] | na_x00 & dcop[4]; assign clr_na[3] = na_111 & dcop[1]; //______________________________________________________________________________ // always @(posedge pin_clk) begin if (pin_mce_p) begin a_in = {axt, na}; d_in <= rni ? svc : d; end end assign ma = (na_dt ? da[8:0] : 9'o777) & ((a_in[8:7] == 2'b00) ? ma_pla : ma_rom); assign mc = (mc_dt ? da : 16'o177777) & ((a_in[8:7] == 2'b00) ? mc_pla : mc_rom); defparam pla0.DC303_PLA = 0; dc_pla pla0 ( .a_in(a_in[6:0]), .d_in(d_in), .ma(ma_pla0), .mc(mc_pla0) ); defparam pla1.DC303_PLA = 1; dc_pla pla1 ( .a_in(a_in[6:0]), .d_in(d_in), .ma(ma_pla1), .mc(mc_pla1) ); defparam pla2.DC303_PLA = 2; dc_pla pla2 ( .a_in(a_in[6:0]), .d_in(d_in), .ma(ma_pla2), .mc(mc_pla2) ); defparam rom0.DC303_ROM = 0; dc_rom rom0 ( .clk(pin_clk), .cen(pin_mce_p), .a_in({axt, na}), .ma(ma_rom0), .mc(mc_rom0) ); defparam rom1.DC303_ROM = 1; dc_rom rom1 ( .clk(pin_clk), .cen(pin_mce_p), .a_in({axt, na}), .ma(ma_rom1), .mc(mc_rom1) ); defparam rom2.DC303_ROM = 2; dc_rom rom2 ( .clk(pin_clk), .cen(pin_mce_p), .a_in({axt, na}), .ma(ma_rom2), .mc(mc_rom2) ); assign mc_pla = ( cs[0] ? mc_pla0 : 16'o000000) | ((cs[1] && DC303_FPP) ? mc_pla1 : 16'o000000) | ((cs[2] && DC303_FPP) ? mc_pla2 : 16'o000000); assign ma_pla = ( cs[0] ? ma_pla0 : 9'o000) | ((cs[1] && DC303_FPP) ? ma_pla1 : 9'o000) | ((cs[2] && DC303_FPP) ? ma_pla2 : 9'o000); assign mc_rom = ( cs[0] ? mc_rom0 : 16'o000000) | ((cs[1] && DC303_FPP) ? mc_rom1 : 16'o000000) | ((cs[2] && DC303_FPP) ? mc_rom2 : 16'o000000); assign ma_rom = ( cs[0] ? ma_rom0 : 9'o000) | ((cs[1] && DC303_FPP) ? ma_rom1 : 9'o000) | ((cs[2] && DC303_FPP) ? ma_rom2 : 9'o000); //______________________________________________________________________________ // endmodule