// // Copyright (c) 2014-2019 by 1801BM1@gmail.com //______________________________________________________________________________ // // Wishbone compatible version of 1801VM1 processor // has 3 dedicated wishbone interfaces: // - master interface - VM1 core itself // - slave interface - VM1 peripheral (1777xx registers) // - interrupt vector interface - interrupt acknowlegement // module vm1_wb #(parameter //______________________________________________________________________________ // // If VM1_CORE_REG_USES_RAM is nonzero the Register File is implemented // as library RAM module, the constant and vector generators also use // this initialized RAM to provide the data. This option is intended to // be used on FPGA with embedded RAM blocks // VM1_CORE_REG_USES_RAM = 1, //______________________________________________________________________________ // // VM1 version select - VM1A or VM1G. VM1G contains another version of // microcode, supports VE timer interrupt and MUL operation. // If VM1_CORE_MULG_VERSION is defined an nonzero the VM1G core being generated // VM1_CORE_MULG_VERSION = 0 ) ( // // Processor core clock section: // - vm_clk_p - processor core positive clock, also feeds the wishbone buses // - vm_clk_n - processor core negative clock, should be vm_clk_p 180 degree phase shifted // - vm_clk_ena - slow clock simulation strobe, enables clock at vm_clk_p // - vm_clk_tve - VE-timer clock enable strobe, enables clock at vm_clk_p // - vm_clk_slow - clock mode selector, enables clock slowdown simulation, // the external I/O cycles is launched with rate of vm_clk_ena // input vm_clk_p, // positive clock input vm_clk_n, // negative clock input vm_clk_ena, // slow clock enable input vm_clk_tve, // VE-timer clock enable input vm_clk_sp, // external pin SP clock input vm_clk_slow, // slow clock sim mode // input [1:0] vm_pa, // processor number input vm_init_in, // peripheral reset input output vm_init_out, // peripheral reset output // input vm_dclo, // processor reset input vm_aclo, // power fail notificaton input [3:1] vm_irq, // radial interrupt requests input vm_virq, // vectored interrupt request // input wbm_gnt_i, // master wishbone granted output wbm_ios_o, // master wishbone I/O select output [15:0] wbm_adr_o, // master wishbone address output [15:0] wbm_dat_o, // master wishbone data output input [15:0] wbm_dat_i, // master wishbone data input output wbm_cyc_o, // master wishbone cycle output wbm_we_o, // master wishbone direction output [1:0] wbm_sel_o, // master wishbone byte selection output wbm_stb_o, // master wishbone strobe input wbm_ack_i, // master wishbone acknowledgement // input [15:0] wbi_dat_i, // interrupt vector input output wbi_stb_o, // interrupt vector strobe input wbi_ack_i, // interrupt vector acknowledgement // input [3:0] wbs_adr_i, // slave wishbone address input [15:0] wbs_dat_i, // slave wishbone data input output [15:0] wbs_dat_o, // slave wishbone data output input wbs_cyc_i, // slave wishbone cycle input wbs_we_i, // slave wishbone direction input wbs_stb_i, // slave wishbone strobe output wbs_ack_o, // slave wishbone acknowledgement // input [15:0] vm_reg14, // register 177714 data input [15:0] vm_reg16, // register 177716 data output [2:1] vm_sel // register select outputs ); //______________________________________________________________________________ // wire [33:0] plx, plx_a, plx_g; // main microcode matrix output reg [33:0] plr; // main matrix result register (last stage) reg [33:0] plm; // main matrix result register (first stage) reg [14:0] mj; // microcode stage and condition register reg [15:0] ir; // instruction register (last stage) reg [15:0] ira; // instruction register (first stage) // wire [10:0] pli, pli_a, pli_g; // interrupt priority encode matrix output reg [19:0] rq; // interrupt request register reg aclo; // ACLO falling edge detectors reg acok; // ACLO raising edge detectors reg irq2; // IRQ2 falling edge detectors reg irq3; // IRQ3 falling edge detectors reg uop; // undefined operation latch reg qbto; // I/O bus timeout & OAT latch reg ivto; // IAKO bus timeout latch reg start_irq; // raised by 1777x2 register write (disconnected) wire tve_irq; // VE-timer interrupt request (vm1a_pli ignores) wire tve_ack; // VE-timer interrupt acknowledgement // wire exc_uop; // Undefined opcode found wire exc_oat; // Odd address trap detector wire exc_err2; // wire exc_err3; // wire exc_err7; // reg [3:0] exc_dbl; // double error detector // reg [5:0] bus_timer; // bus timeout counter reg bus_tovf; // bus timer overflow latch // // wire uop_ack; // undefined instruction wire aclo_ack; // ACLO timer acknowlegement wire irq2_ack; // IRQ2 timer acknowlegement wire irq3_ack; // IRQ3 timer acknowlegement reg [3:0] vsel; // vector selection register reg [3:0] plir; // pli[10:8:6:4] outputs latch // wire ir_stb1; // reg ir_stb2; // instruction register strobe wire ir_clr; // wire ir_set_fc; // reg ir_set; // reg ir_stop; // reg ir_seq; // wire ir_seq_rc; // // wire pli_req_rc; // interrupt encoder request reg pli_req; // source and latch wire pli_stb; // interrupt matrix strobe wire pli_nrdy; // interrupt matrix not ready // wire plm_stb_rc; // plm_register strobe source reg plm_stb; // plm_register strobe latch // wire plm1x_fc; // wire plm2x_fc; // main matrix result strobes reg plm1x, plm2x; // reg plm1x_hl; // reg plm_ena; // wire plm_ena_fc; // // reg [3:0] sop_out; // wire sop_up; // wire [7:0] plop; // wire uplr_stb; // reg mj_stb1, mj_stb2; // reg psw_stb, psw_stbc; // reg psw_mj; // // wire [3:0] plm23_fc; // reg plm23_wait; // reg plm23_ichk; // // wire [3:1] tplm_rc; // reg [3:1] tplm; // reg [3:1] tplmz; // reg [8:6] plrt; // reg [8:6] plrtz; // // reg reset; // global device hardware reset reg abort; // odd address. bus hang, invalid opcode reg mjres; // reset microcode state machine reg mjres_h; // // wire mjres_rc; // wire reset_rc; // wire abort_rc; // reg abort_tm; // // reg [15:0] wbs_d; // slave wishbone data register wire [15:0] tve_d; // timer module data output reg wbs_r, wbs_w; // reg wbs_a; // wire wbs_a_rc; // // reg wsel_00, // peripheral register selectors wsel_02, // wsel_04; // // reg iak_flag; // reg iak_vreq; // reg [2:0] init_out; // // wire bus_done; // reg bus_done_h; // reg bus_clr; // reg bus_own; // reg bus_req; // // wire bus_nrdy; // reg [1:0] bus_aseq; // address request sequencer wire din_done; // wire dout_done; // reg dout_req; // // reg wb_uplr; // transaction internal request reg wb_ios; // I/O bank select reg [15:0] wb_adr; // wishbone address register reg [15:0] wb_dat; // wishbone input data register // wire wb_start; // wire wb_wclr, wb_wset; // reg wb_swait; // reg [9:0] wb_wcnt; // reg wb_cyc; // reg wb_stb; // reg wb_we; // reg [1:0] wb_sel; // wire wb_wdone, // wb_rdone, // wb_idone; // reg wb_idone_h; // // reg [2:0] reg_csr; // 177700: control register reg [7:0] reg_err; // 177704: error register // reg [3:0] freg; // reg [15:0] psw; // processor status word wire [15:0] x, xr, xr_ff, xr_rm; // X bus wire [15:0] y, yr, yr_ff, yr_rm; // Y bus wire [15:0] f; // ALU function inverted output wire [15:0] h; // half summ wire [15:0] c; // carry wire [15:0] cpred; // carry form preceding but reg cl; // inserted least bit carry // wire [1:0] fmux; // wire [3:0] flag; // wire fbit7, fbit15; // wire [7:1] fctl; // wire fbitc; // // reg alu_b, alu_c; // ALU function selector reg alu_d, alu_e; // registered for speed reg alu_s, alu_x; // // wire cl_fc; // wire alu_b_fc; // wire alu_c_fc; // wire alu_d_fc; // wire alu_e_fc; // wire alu_x_fc; // wire alu_s_fc; // // wire [15:0] alu; // ALU output to X/Y bus wire [15:0] axy; // AND product wire [15:0] oxy; // OR product // reg ustb, ustb_h; // reg ustb1, ustb1_h; // reg ustb1_hl; // // reg alu_busy_fp; // ALU busy (not ready phase shifted) reg alu_busy_rp; // reg alu_nrdy; // ALU not ready wire alu_qrdy; // bus data ready // reg au_alsl, au_alsh; // ALU result strobes wire au_qsx, au_qsy; // bus temporary register wire au_pswx, au_pswy; // PSW read enable wire au_pstbx; // PSW write strobe wire au_astb; // wire au_qstbx; // reg au_qstbd; // wire au_xswap; // ALU X argument strobes reg au_ta0; // // reg au_astb_xa; // au_astb/au_qstb speed optimizers reg au_qstb_xa; // reg au_astb_xu; // reg au_qstb_xu; // // wire [15:0] nx; // reg [15:0] qreg; // ALU Q register (Q-bus data output) reg [15:0] areg; // ALU A register (Q-bus address) reg [15:0] xreg; // ALU X parameter register reg [15:0] yreg; // ALU Y parameter register //______________________________________________________________________________ // // synopsys translate_off initial begin plm[33:0] = 34'o000000000000; psw[15:0] = 16'o000000; end // synopsys translate_on // //______________________________________________________________________________ // assign vm_init_out = init_out[0] | reset_rc; assign wbm_dat_o = au_ta0 ? {qreg[7:0], 8'o000} : (plrt[6] ? {8'o000, qreg[7:0]} : qreg); assign wbm_adr_o = wb_adr; assign wbm_ios_o = wb_ios; //______________________________________________________________________________ // // Control and glue logic // assign ir_clr = (~tplm_rc[3] & tplm[3]) | (~ir_seq_rc & ir_seq); // // tplm1 - instruction prefetch // tplm3 - instruction fetch // assign ir_seq_rc = ~mjres & ~mjres_rc & (~ir_seq | tplm[1] | tplm[3]) & (plm23_wait | ir_seq); always @(posedge vm_clk_p) ir_seq <= ir_seq_rc; assign plm_ena_fc = ~sop_out[0] & (mjres | ustb1_h | ~alu_busy_rp) & ~bus_nrdy; always @(posedge vm_clk_n) begin plm_ena <= plm_ena_fc; end assign sop_up = sop_out[3] | (~sop_out[2] & ~sop_out[1]); always @(posedge vm_clk_p) begin sop_out[2] <= sop_out[1]; if (plm_stb_rc) sop_out[0] <= 1'b0; else if (mjres_rc | plm_ena) sop_out[0] <= 1'b1; end always @(posedge vm_clk_n) begin sop_out[1] <= sop_out[0]; sop_out[3] <= ir_stop | pli_nrdy | ir_stb2 | mjres_h | (alu_nrdy & (plop[0] | plop[4])); end assign plm_stb_rc = ~plm_stb & ~sop_up; always @(posedge vm_clk_p) plm_stb <= plm_stb_rc; always @(posedge vm_clk_n or posedge mjres) begin if (mjres) ustb <= 1'b0; else begin if (ustb_h) ustb <= 1'b0; else if ((alu_busy_rp | (alu_busy_fp & ~ustb1_h)) & alu_qrdy) ustb <= 1'b1; end end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) ustb_h <= 1'b0; else ustb_h <= ustb; end always @(posedge vm_clk_n) ustb1 <= ustb_h; always @(posedge vm_clk_p) ustb1_h <= ustb1; always @(posedge vm_clk_n) ustb1_hl <= ustb1_h; always @(posedge vm_clk_n or posedge mjres) begin if (mjres) alu_busy_fp <= 1'b0; else alu_busy_fp <= alu_busy_rp; end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) alu_busy_rp <= 1'b0; else if (plm2x) alu_busy_rp <= 1'b1; else if (ustb1) alu_busy_rp <= 1'b0; end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) alu_nrdy <= 1'b0; else if (plm2x) alu_nrdy <= 1'b1; else if (ustb1_h) alu_nrdy <= 1'b0; end assign ir_stb1 = tplm[1] | tplm[3]; assign ir_set_fc = plm23_fc[0] | plm23_fc[1] | plm23_fc[3]; always @(posedge vm_clk_n) ir_set <= ir_set_fc; always @(posedge vm_clk_p or posedge mjres) begin if (mjres) ir_stb2 <= 1'b0; else begin if (ir_clr) ir_stb2 <= 1'b0; else if (ir_set) ir_stb2 <= 1'b1; end end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) ir_stop <= 1'b0; else if (~reg_csr[0]) ir_stop <= 1'b0; else if (ir_clr) ir_stop <= 1'b1; end always @(posedge vm_clk_n or posedge mjres) begin if (mjres) tplmz <= 3'b000; else if (plm_ena_fc) begin tplmz[1] <= (plm[3:1] == 3'b100); tplmz[2] <= (plm[3:1] == 3'b010); tplmz[3] <= (plm[3:1] == 3'b011); end end assign tplm_rc[1] = ~(mjres | mjres_rc | din_done) & ((uplr_stb & tplmz[1]) | tplm[1]); // instruction early prefetch assign tplm_rc[2] = ~(mjres | mjres_rc | din_done) & ((uplr_stb & tplmz[2]) | tplm[2]); // data retrieving assign tplm_rc[3] = ~(mjres | mjres_rc | din_done) & ((uplr_stb & tplmz[3]) | tplm[3]); // instruction fetch always @(posedge vm_clk_p) tplm <= tplm_rc; always @(posedge vm_clk_p) begin // // plr[6] bus operation type: byte operation flag // plr[7] bus operation type: write flag // plr[8] bus operation type: read flag // 00x - nothing // 010 - write word // 011 - write byte // 100 - read word // 101 - read byte // 110 - read-modify-write word // 111 - read-modify-write byte // plrtz[6] <= plr[6]; plrtz[7] <= plr[7] & plr[8]; // read-modify-write flag plrtz[8] <= plr[8]; // // Reset Read Flag after read completion within // read-modify-write operations // if (din_done) plrt[8] <= 1'b0; else if (uplr_stb) plrt[8] <= plrtz[8]; if (uplr_stb) plrt[7:6] <= plrtz[7:6]; end //______________________________________________________________________________ // // bus logic (the rest of one, needed as glue core to wishbone interface) // assign bus_done = (din_done & ~plrt[7]) | dout_done | mjres; always @(posedge vm_clk_p) bus_done_h <= bus_done; // // Wishbone takes address immediately and core does not need to wait areg // assign alu_qrdy = (~dout_req | plr[23] | (plr[7] | plr[8])) // wait for write complete & (plr[10] | (~tplm[2] & ~iak_flag)); // wait for data or vector fetch always @(posedge vm_clk_p or posedge mjres) begin if (mjres) dout_req <= 1'b0; else dout_req <= (~plrt[8] & au_qstbx & (bus_own | bus_req)) | (~bus_done & dout_req); end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) bus_own <= 1'b0; else begin if (uplr_stb) bus_own <= 1'b1; else if (bus_done) bus_own <= 1'b0; end end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) bus_req <= 1'b0; else begin if (uplr_stb) bus_req <= 1'b0; else if (au_astb) bus_req <= 1'b1; end end assign din_done = wb_rdone; assign dout_done = wb_wdone; always @(posedge vm_clk_n) bus_clr <= mjres | bus_done_h; //______________________________________________________________________________ // // 1801BM1 can issue preliminary transaction address, so the plm->plr strobe // should be delayed till current transaction in progess completed // assign bus_nrdy = (bus_aseq[1] & ~bus_clr) | (au_astb & bus_aseq[0] & ~bus_clr); assign uplr_stb = (au_astb & ~bus_aseq[0]) | (au_astb & bus_aseq[0] & bus_clr) | bus_aseq[1] & bus_clr; always @(posedge vm_clk_n or posedge mjres) begin if (mjres) bus_aseq <= 2'b00; else begin // // Reset the completed request if it is only one // if (au_astb) bus_aseq[0] <= 1'b1; else if (bus_clr & ~bus_aseq[1]) bus_aseq[0] <= 1'b0; // // The third request is impossible - the state machine // is suspended by bus_nrdy // if (bus_clr) bus_aseq[1] <= 1'b0; else if (au_astb & bus_aseq[0]) bus_aseq[1] <= 1'b1; end end //______________________________________________________________________________ // assign vm_sel[2] = wbs_stb_i & (wbs_adr_i[3:1] == 3'b110) & wbs_a; // 177714 assign vm_sel[1] = wbs_stb_i & (wbs_adr_i[3:1] == 3'b111) & wbs_a; // 177716 always @(posedge vm_clk_p) begin wsel_00 <= wbs_we_i & wbs_stb_i & wbs_cyc_i & (wbs_adr_i[3:1] == 3'b000); wsel_02 <= wbs_we_i & wbs_stb_i & wbs_cyc_i & (wbs_adr_i[3:1] == 3'b001); wsel_04 <= wbs_we_i & wbs_stb_i & wbs_cyc_i & (wbs_adr_i[3:1] == 3'b010); end assign wbs_dat_o = wbs_d; assign wbs_ack_o = wbs_a; // // Register 177702 does not generate reply if start_irq is active // assign wbs_a_rc = wbs_cyc_i & wbs_stb_i & ~((wbs_adr_i[3:1] == 3'b001) & start_irq) & ((~wbs_we_i & ~wbs_r) | (wbs_we_i & ~wbs_w)); always @(posedge vm_clk_p) begin wbs_a <= wbs_a_rc; wbs_r <= wbs_cyc_i & ((wbs_stb_i & ~wbs_we_i) | wbs_r); wbs_w <= wbs_cyc_i & ((wbs_stb_i & wbs_we_i) | wbs_w); if (wbs_stb_i & ~wbs_we_i) case(wbs_adr_i[3:1]) 3'b000: wbs_d <= {11'o3777, vm_pa, reg_csr}; // 177700 3'b001: wbs_d <= 16'o177777; // 177702 3'b010: wbs_d <= {8'o377, reg_err}; // 177704 3'b011: wbs_d <= tve_d; // 177706 3'b100: wbs_d <= tve_d; // 177710 3'b101: wbs_d <= tve_d; // 177712 3'b110: wbs_d <= vm_reg14; // 177714 3'b111: wbs_d <= vm_reg16; // 177716 default: wbs_d <= 16'o000000; endcase end vm1_timer timer ( .tve_clk(vm_clk_p), .tve_ena(vm_clk_tve), .tve_reset(vm_init_out | vm_init_in), .tve_dclo(vm_dclo), .tve_sp(vm_clk_sp), .tve_din(wbs_dat_i), .tve_dout(tve_d), .tve_csr_oe(wbs_adr_i[3:1] == 3'b101), .tve_cnt_oe(wbs_adr_i[3:1] == 3'b100), .tve_lim_oe(wbs_adr_i[3:1] == 3'b011), .tve_csr_wr((wbs_adr_i[3:1] == 3'b101) & wbs_we_i & wbs_a), .tve_lim_wr((wbs_adr_i[3:1] == 3'b011) & wbs_we_i & wbs_a), .tve_irq(tve_irq), .tve_ack(tve_ack) ); //______________________________________________________________________________ // // Bus transacion timeout counter // // original 1801BM1 timer has 1/8 input prescaler which is no reset and // provides bus timeout in a range 56..63 processor clocks. This model // emulates the average value 60 clocks. // // Timeout exception request should be synchronized with raising clk's edge // always @(posedge vm_clk_p) begin bus_tovf <= &bus_timer[5:2]; end always @(posedge vm_clk_n) begin if (~((wbm_stb_o & wbm_gnt_i) | wbi_stb_o)) bus_timer <= 6'o00; else if (~bus_tovf) bus_timer <= bus_timer + 6'o01; end // // Control register at 177700 // always @(posedge vm_clk_p or posedge reset) begin if (reset) reg_csr <= 3'b000; else begin // // Bit 0 of control register // if ((plm1x_hl & ~plr[25]) | (ir_set & reg_csr[1])) reg_csr[0] <= 1'b1; else if (wsel_00) reg_csr[0] <= wbs_dat_i[0]; // // Bit 1 of control register (controls set of bit 0) // if (wsel_00) reg_csr[1] <= wbs_dat_i[1]; // // Bit 2 of control register (wait state) // if (plm1x_hl & ~plr[27]) reg_csr[2] <= 1'b0; else if (plm1x_hl & ~plr[7]) reg_csr[2] <= 1'b1; else if (wsel_00) reg_csr[2] <= wbs_dat_i[2]; end end // // Error register at 177704 // Bit 0 is Double Error // Bit 1 is Undefine Opcode // Bit 5 is not used (always read as one) // Bit 6 is Odd Address Trap (is not implmented) // always @(posedge vm_clk_p) begin if (reset_rc | ir_set) reg_err <= 8'b00100000; else begin // // Bit 0 - double error // if ( (exc_dbl[0] & exc_uop) | (exc_dbl[1] & bus_tovf) | (exc_dbl[2] & exc_oat) | (exc_dbl[3] & exc_err7)) reg_err[0] <= 1'b1; else if (wsel_04) reg_err[0] <= wbs_dat_i[0]; // // Bit 1 - undefined opcode // if (exc_uop) reg_err[1] <= 1'b1; else if (wsel_04) reg_err[1] <= wbs_dat_i[1]; // // Bit 2 & 3 - unknown error, exceptions not implemented // if (exc_err2) reg_err[2] <= 1'b1; else if (wsel_04) reg_err[2] <= wbs_dat_i[2]; if (exc_err3) reg_err[3] <= 1'b1; else if (wsel_04) reg_err[3] <= wbs_dat_i[3]; // // Bit 4 - bus timeout // if (bus_tovf) reg_err[4] <= 1'b1; else if (wsel_04) reg_err[4] <= wbs_dat_i[4]; // // Bit 6 - odd address trap // if (exc_oat) reg_err[6] <= 1'b1; else if (wsel_04) reg_err[6] <= wbs_dat_i[6]; // // Bit 7 - unknown error, no exception // if (exc_err7) reg_err[7] <= 1'b1; else if (wsel_04) reg_err[7] <= wbs_dat_i[7]; end // // Double error detectors // if (~exc_uop) exc_dbl[0] <= reg_err[1]; if (~bus_tovf) exc_dbl[1] <= reg_err[4]; if (~exc_oat) exc_dbl[2] <= reg_err[6]; if (~exc_err7) exc_dbl[3] <= reg_err[7]; end always @(posedge vm_clk_p) begin // // Original circuit contains error // The start_irq request is reset by interrupt ack and EMT execution (last one is wrong) // if (reset | ((vsel[2:0] == 3'b110) & (plr[28:25] == 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]))) start_irq <= 1'b0; else if (wsel_02) start_irq <= 1'b1; end //______________________________________________________________________________ // // Interrupt controller // assign pli = VM1_CORE_MULG_VERSION ? pli_g : pli_a; vm1g_pli pli_matrix_g(.rq(rq), .sp(pli_g)); vm1a_pli pli_matrix_a(.rq(rq), .sp(pli_a)); always @(posedge vm_clk_p) begin rq[0] <= psw[10]; rq[1] <= plir[0]; // pli4r rq[2] <= psw[11]; rq[3] <= uop; rq[4] <= psw[7]; rq[9] <= qbto; rq[10] <= reg_err[0]; rq[11] <= vm_aclo & aclo; rq[12] <= reg_csr[2]; rq[13] <= ~vm_aclo & acok; rq[14] <= vm_irq[1]; rq[15] <= psw[4]; rq[16] <= vm_irq[2] & irq2; rq[17] <= ivto; rq[18] <= vm_irq[3] & irq3; // // Only master CPU processes vectored interrupts // Matrix accepts low level as active (asserted request) // rq[8] <= ~(vm_virq & (vm_pa == 2'b00)); // // Not used matrix inputs // rq[5] <= 1'b0; rq[6] <= 1'b0; rq[7] <= 1'b0; // // VE timer interrupt // rq[19] <= tve_irq; end // // Odd address trap detector is blocked on 1801BM1 // assign exc_oat = 1'b0; assign exc_uop = plm_ena & plr[12]; assign exc_err2 = plm1x_hl & ~plr[26]; assign exc_err3 = plm1x_hl & ~plr[28]; assign exc_err7 = plm1x_hl & ~plr[30]; always @(posedge vm_clk_p or posedge reset) begin if (reset) plir[0] <= 1'b0; else if (pli_stb) plir[0] <= pli[4]; end always @(posedge vm_clk_p) begin if (pli_stb) begin plir[1] <= pli[6]; plir[2] <= pli[8]; plir[3] <= pli[10]; end end // // Detector's reset // assign aclo_ack = plm1x_hl & ~plr[27] & ~plir[3] & ~plir[2] & plir[1]; assign uop_ack = plm1x_hl & ~plr[27] & ~plir[3] & ~plir[2] & ~plir[1]; assign irq2_ack = plm1x_hl & ~plr[27] & plir[3] & plir[2] & ~plir[1]; assign irq3_ack = plm1x_hl & ~plr[27] & plir[3] & ~plir[2] & ~plir[1]; assign tve_ack = plm1x_hl & ~plr[27] & plir[3] & ~plir[2] & plir[1]; // // ACLO edge detectors // always @(posedge vm_clk_p) begin if (reset | aclo_ack) aclo <= 1'b0; else if (~vm_aclo) aclo <= 1'b1; if (vm_dclo | aclo_ack) acok <= 1'b0; else if (vm_aclo) acok <= 1'b1; end // // IRQ2 and IRQ3 falling edge detectors // Also resettable by internal INIT // always @(posedge vm_clk_p) begin if (vm_init_out | vm_init_in) begin irq2 <= 1'b0; irq3 <= 1'b0; end else begin if (irq2_ack) irq2 <= 1'b0; else if (~vm_irq[2]) irq2 <= 1'b1; if (irq3_ack) irq3 <= 1'b0; else if (~vm_irq[3]) irq3 <= 1'b1; end end // // Error exception latches // always @(posedge vm_clk_p) begin if (reset | uop_ack) begin uop <= 1'b0; qbto <= 1'b0; ivto <= 1'b0; end else begin if (exc_uop) uop <= 1'b1; if (bus_tovf & iak_flag) ivto <= 1'b1; if (bus_tovf | exc_oat) qbto <= 1'b1; end end assign pli_req_rc = plm23_ichk | abort; assign pli_nrdy = pli_req; assign pli_stb = pli_req; always @(posedge vm_clk_p) begin pli_req <= pli_req_rc; if (pli_stb) vsel <= {pli[3], ~pli[2], pli[1], pli[0]}; else if (plm1x) vsel <= {plr[18], ~plr[20], ~plr[21], ~plr[22]}; end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) iak_flag <= 1'b0; else if (wb_idone_h) iak_flag <= 1'b0; else if (plm_ena & (plr[28:25] == 4'b0010) & (plr[11] | (plr[13] & ~plr[14])) & (vsel == 4'b1111)) iak_flag <= 1'b1; end always @(posedge vm_clk_p or posedge mjres) begin if (mjres) iak_vreq <= 1'b0; else if (wb_idone) iak_vreq <= 1'b0; else if (iak_flag & ~wb_idone_h & ~wbm_cyc_o & (bus_aseq == 2'b00)) iak_vreq <= 1'b1; end //______________________________________________________________________________ // // Reset circuits // assign mjres_rc = reset_rc | abort_rc; assign reset_rc = vm_dclo | (vm_aclo & ~init_out[0] & init_out[2]); assign abort_rc = (bus_tovf | exc_oat | exc_uop | abort) & ~abort_tm & ~reset_rc; always @(posedge vm_clk_p) begin reset <= reset_rc; mjres <= mjres_rc; mjres_h <= mjres; abort <= abort_rc; abort_tm <= abort & ~reset_rc; end always @(posedge vm_clk_p) begin if (reset_rc) init_out[0] <= 1'b0; else if (plm1x_hl) begin if (~plr[23]) init_out[0] <= 1'b0; else if (~plr[10]) init_out[0] <= 1'b1; end init_out[1] <= init_out[0]; init_out[2] <= init_out[1]; end //______________________________________________________________________________ // // Microcode state machine // assign plx = VM1_CORE_MULG_VERSION ? plx_g : plx_a; vm1g_plm plm_matrix_g(.ir(ir), .mr(mj), .sp(plx_g)); vm1a_plm plm_matrix_a(.ir(ir), .mr(mj), .sp(plx_a)); assign plm1x_fc = plm_ena_fc & ~plm[12] & (plm[11] & plm[13]); assign plm2x_fc = plm_ena_fc & ~plm[12] & ~(plm[11] & plm[13]); // irq check wait IR start IR Note assign plm23_fc[0] = plm_ena_fc & (plm[3:1] == 3'b001); // no yes no RTT opcode, wait fetch completion assign plm23_fc[1] = plm_ena_fc & (plm[3:1] == 3'b011); // yes yes yes usual IR fetch assign plm23_fc[2] = plm_ena_fc & (plm[3:1] == 3'b101); // yes no no WAIT opcode, check irq only assign plm23_fc[3] = plm_ena_fc & (plm[3:1] == 3'b111); // yes yes no ~RTT opcode, wait fetch completion always @(posedge vm_clk_n) begin plm23_wait <= plm23_fc[0] | plm23_fc[3]; plm23_ichk <= plm23_fc[1] | plm23_fc[2] | plm23_fc[3]; end assign plop[0] = ~plr[22] & ~plr[21] & ~plr[4]; // 000 assign plop[1] = ~plr[22] & ~plr[21] & plr[4]; // 001 assign plop[2] = ~plr[22] & plr[21] & ~plr[4]; // 010 assign plop[3] = ~plr[22] & plr[21] & plr[4]; // 011 assign plop[4] = plr[22] & ~plr[21] & ~plr[4]; // 100 assign plop[5] = plr[22] & ~plr[21] & plr[4]; // 101 assign plop[6] = plr[22] & plr[21] & ~plr[4]; // 110 assign plop[7] = plr[22] & plr[21] & plr[4]; // 111 always @(posedge vm_clk_n) begin plm1x <= plm1x_fc; plm2x <= plm2x_fc; plm1x_hl <= plm1x; if (plm_ena) begin psw_stb <= ~plop[0] & ~plop[2] & ~plop[7]; psw_stbc <= ~plop[0] & ~plop[1] & ~plop[2] & ~plop[3] & ~plop[7]; mj_stb1 <= (plop[7] & ir_stb2) | (~plop[1] & ~plop[5] & ~plop[7]); mj_stb2 <= (plop[7] & ir_stb2) | (~plop[1] & ~plop[5] & ~plop[7] & ~plop[3]); psw_mj <= plop[7] & ir_stb2; end end // // Instruction register // always @(posedge vm_clk_p) begin if (ir_stb1) ira <= wbm_dat_i; if (ir_stb2) if (ir_stb1) ir <= wbm_dat_i; else ir <= ira; end //______________________________________________________________________________ // always @(posedge vm_clk_n) begin if (plm_ena_fc) plr <= plm; end always @(posedge vm_clk_p) begin // // Other bits have no reset facility // if (plm_stb_rc) begin // // Some of plm is not used here (microcode address directly uses plx instead) // plm <= plx; end end //______________________________________________________________________________ // // Microcode register // always @(posedge vm_clk_p or posedge abort) begin // // The least bit is reset by abort // and set by common reset // if (abort) mj[0] <= 1'b0; else if (reset) mj[0] <= 1'b1; else if (plm_stb_rc) mj[0] <= ~plx[29]; end always @(posedge vm_clk_p or posedge mjres) begin // // Least bits are produced directly from main matrix // and have the async reset feature (next microcode address) // if (mjres) mj[6:1] <= 6'b111111; else if (plm_stb_rc) begin mj[1] <= ~plx[24]; mj[2] <= ~plx[19]; mj[3] <= plx[15]; mj[4] <= plx[9]; mj[5] <= plx[5]; mj[6] <= ~plx[0]; end end always @(posedge vm_clk_p) begin if (ustb1_hl) begin if (mj_stb1) begin mj[11] <= psw[4]; mj[10:8] <= psw_mj ? psw[3:1] : freg[3:1]; end if (mj_stb2) mj[7] <= psw_mj ? psw[0] : freg[0]; end end always @(posedge vm_clk_p or posedge mjres) begin // // Bits 14:12 poll the interrupt controller state // if (mjres) mj[14:12] <= 3'b000; else if (pli_stb) mj[14:12] <= {~pli[5], ~pli[7], pli[9]}; else if (plm1x) mj[14:12] <= {~plr[14], plr[16], ~plr[17]}; end //______________________________________________________________________________ // // ALU result flags and PSW // always @(posedge vm_clk_n) begin if (au_alsl) freg <= flag; end always @(posedge vm_clk_n or posedge reset) begin // // Start microcode correctly sets the PSW // But simulator can not calculate ALU function // correctly if PSW in initially undefined // // The PSW is written by microcode with 340 value // while executing reset sequence // if (reset) psw[15:0] <= {6'o00, vm_pa[1:0], 8'o000}; else begin if (au_alsl & au_pstbx) psw[7:0] <= x[7:0]; else begin // // Latch the ALU flag results immediately after ALU completion // Rollback to the original PSW logic // if (psw_stbc & ustb1_hl) psw[0] <= freg[0]; if (psw_stb & ustb1_hl) psw[3:1] <= freg[3:1]; // // This does not work correctly for MUL instruction - result flags are wrong // due to G-version microcode urges to write flags from ALU bus directly // (au_pstbx active) // // if (psw_stbc & au_alsl) // psw[0] <= flag[0]; // if (psw_stb & au_alsl) // psw[3:1] <= flag[3:1]; // end if (au_alsh & au_pstbx) begin psw[9:8] <= vm_pa[1:0]; psw[15:10] <= x[15:10]; end end end // // ALU general purpose registers // assign xr = VM1_CORE_REG_USES_RAM ? xr_rm : xr_ff; assign yr = VM1_CORE_REG_USES_RAM ? yr_rm : yr_ff; // // Implement the Register File with library RAM module // vm1_reg_ram vreg_rm( .clk_p(vm_clk_p), .clk_n(vm_clk_n), .reset(reset), .plr(plr), .xbus_in(x), .xbus_out(xr_rm), .ybus_out(yr_rm), .wstbl(au_alsl), .wstbh(au_alsh), .ireg(ir), .vsel(vsel), .pa(vm_pa), .carry(psw[0])); // // Implement the Register File with Flip-Flops array // The constant generator can be built in the File // in some implementations // vm1_reg_ff vreg_ff( .clk_p(vm_clk_p), .clk_n(vm_clk_n), .reset(reset), .plr(plr), .xbus_in(x), .xbus_out(xr_ff), .ybus_out(yr_ff), .wstbl(au_alsl), .wstbh(au_alsh), .ireg(ir), .vsel(vsel), .pa(vm_pa), .carry(psw[0])); assign au_pswy = (plr[28:25] == 4'b1000) & ~plr[11] & ~plr[13]; assign au_qsy = (plr[28:25] == 4'b0000) & ~plr[11] & ~plr[13]; assign au_pswx = (plr[33:30] == 4'b1000); assign au_qsx = (plr[33:30] == 4'b0000); always @(posedge vm_clk_n) au_alsl <= alu_busy_rp & ustb_h; always @(posedge vm_clk_n) au_alsh <= alu_busy_rp & ustb_h & plr[18]; assign au_xswap = plr[13] & plr[14] & plr[25] & plr[26] & ~plr[27]; assign au_pstbx = (plr[33:30] == 4'b1000) & plr[20]; // // Original strobes: // // assign au_astb = (au_alsl & ~(~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8])) // | ( ustb & (~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8])); // assign au_qstbx = (au_alsl & ~(~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]) // | ( ustb & (~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]); // // Speed-optimized strobes: // assign au_astb = au_astb_xa | (ustb & au_astb_xu); assign au_qstbx = au_qstb_xa | (ustb & au_qstb_xu); always @(posedge vm_clk_n) begin au_astb_xa <= alu_busy_rp & ustb_h & ~(~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8]); au_qstb_xa <= alu_busy_rp & ustb_h & ~(~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]; au_astb_xu <= (~plr[14] & plr[13]) & ~plr[23] & (plr[7] | plr[8]); au_qstb_xu <= (~plr[14] & plr[13]) & ~plr[23] & ~plr[7] & ~plr[8]; end // // X bus (12 entries) // AU_RSX0 - general purpose regs // AU_RSX1 - general purpose regs // AU_QSX - bus temporary reg // AU_PSWX - PSW // // AU_ALSx - ALU result strobe (writeonly) // AU_ASTB - A address register (readonly) // AU_ASTB - A address register (readonly) // AU_QSTBX - bus temporary reg (readonly) // AU_QSTBX - bus temporary reg (readonly) // AU_IS0 - ALU X argument (readonly) // AU_IS1 - ALU X argument (readonly) // // Y bus, inverted (9 entries) // AU_RSY0 - general purpose regs // AU_RSY1 - general purpose regs // AU_QSY - bus temporary reg // AU_PSWY - PSW // // AU_ALSx - ALU result strobe (writeonly)) // AU_VSELY - vector generator (Y-writeonly) // AU_CSELY - constant generator (Y-writeonly) // ALU_U - ALU Y argument (readonly) // assign x[15:0] = au_alsl ? (au_alsh ? alu[15:0] : {8'o000, alu[7:0]}) : ( xr | (au_qsx ? qreg : 16'o000000) | (au_pswx ? psw : 16'o000000)); assign y[15:0] = ~(yr | (au_qsy ? qreg : 16'o000000) | (au_pswy ? psw : 16'o000000)); // // ALU bus register // always @(posedge vm_clk_n) begin if (au_qstbx) qreg[15:0] <= x[15:0]; else if (au_qstbd) begin qreg[7:0] <= ((au_ta0 & ~wb_idone_h) ? wb_dat[15:8] : wb_dat[7:0]); qreg[15:8] <= wb_dat[15:8]; end if (au_astb) areg <= x; end // // Transaction address low bit latch // always @(posedge vm_clk_p) begin wb_uplr <= uplr_stb; if (wb_uplr) begin wb_ios <= &areg[15:13]; wb_adr <= areg; au_ta0 <= areg[0] & plrt[6]; end end assign wb_start = (~wb_wset & wb_uplr) | (wb_wclr & wb_swait); assign wb_wdone = wb_stb & wbm_ack_i & wb_we; assign wb_rdone = wb_stb & wbm_ack_i & ~wb_we; assign wb_idone = wbi_stb_o & wbi_ack_i; assign wbm_cyc_o = wb_cyc; assign wbm_we_o = wb_we; assign wbm_sel_o = wb_sel; assign wbm_stb_o = wb_stb; assign wbi_stb_o = iak_vreq & ~wbm_cyc_o & (bus_aseq == 2'b00); assign wb_wset = wb_uplr & vm_clk_slow & (wb_wcnt != 10'o0000); assign wb_wclr = reset | ~vm_clk_slow | (vm_clk_ena & (wb_wcnt == 10'o0001)); always @(posedge vm_clk_p) begin au_qstbd <= wb_idone | (wb_rdone & tplm[2]); wb_idone_h <= wb_idone; if (wb_wclr) wb_swait <= 1'b0; else if (wb_wset) wb_swait <= 1'b1; if (reset) wb_wcnt <= 10'o0000; else if (wb_swait) begin if (vm_clk_ena | ~vm_clk_slow) wb_wcnt <= wb_wcnt - 10'o0001; end else begin if (~vm_clk_ena & vm_clk_slow) wb_wcnt <= wb_wcnt + 10'o0001; end if (wb_rdone) wb_dat <= wbm_dat_i; else if (wb_idone) wb_dat <= wbi_dat_i; // // plr[6] bus transaction type: byte operation flag // plr[7] bus transaction type: write flag // plr[8] bus transaction type: read flag // 00x - nothing // 010 - write word // 011 - write byte // 100 - read word // 101 - read byte // 110 - read-modify-write word // 111 - read-modify-write byte // if (mjres) begin // // Master wishbone abort/reset // wb_cyc <= 1'b0; wb_we <= 1'b0; wb_sel <= 2'b00; wb_stb <= 1'b0; end else if (wb_start) begin // // Start master bus transaction // wb_cyc <= 1'b1; wb_we <= ~plrt[8] & ~plrt[7]; wb_sel[0] <= plrt[8] | ~plrt[6] | (wb_uplr ? ~areg[0] : ~au_ta0); wb_sel[1] <= plrt[8] | ~plrt[6] | (wb_uplr ? areg[0] : au_ta0); wb_stb <= plrt[8] | (plrt[7] & dout_req); end else begin if (wb_wdone | (~plrt[7] & wb_rdone)) begin // // Write or single read completion // wb_cyc <= 1'b0; wb_we <= 1'b0; wb_sel <= 2'b00; wb_stb <= 1'b0; end else if (wb_rdone & plrt[7]) begin // // Read cycle of read-modify-write completion // wb_we <= 1'b1; wb_sel[0] <= ~plrt[6] | ~au_ta0; wb_sel[1] <= ~plrt[6] | au_ta0; wb_stb <= 1'b0; end else begin if (wb_we & dout_req) wb_stb <= 1'b1; end end end //______________________________________________________________________________ // // ALU function unit // assign nx = alu_x ? ~xreg : xreg; // // ALU input parameters (from X and Y buses) registers // always @(posedge vm_clk_n) begin xreg[15:0] <= au_xswap ? {x[7:0], x[15:8]} : x[15:0]; yreg <= y; end // // ALU controls // // plr[17:13] cl alu_b alu_c alu_d alu_e alu_x oxy axy h alu // 00x00 1 0 1 0 0 0 ~x|~y ~x&~y ~(x^y) x+y // 00x01 1 0 1 0 0 0 - - - - // 00x11 1 0 1 0 0 0 - - - - // 00x10 1 0 0 0 1 0 ~x|~y ~x ~(x&~y) x&~y // 01x00 0 0 1 0 0 1 x|~y x&~y x^y y-x // 01x01 0 0 1 0 0 1 - - - - // 01x11 0 0 1 0 0 1 - - - - // 01x10 0 0 1 0 1 0 ~x|~y ~x&~y ~(x^y) x^y // 10x00 1 1 1 0 1 0 ~x|y ~x&~y ~y y // 10x01 1 0 0 0 1 0 1 ~x ~x x // 10x10 1 0 1 0 1 0 1 ~x&~y ~(x|y) x|y // 10x11 1 0 0 0 1 0 1 ~x ~x x // 11x00 0 1 0 1 0 0 ~x|y ~x&y x^y x-y // 11x01 0 1 0 1 0 0 - - - - // 11x11 0 1 0 1 0 0 - - - - // 11x10 1 1 0 0 1 0 ~x|y ~x ~(x&y) x&y // assign cl_fc = ~plr[16] | (plr[17] & alu_e_fc); assign alu_b_fc = plr[17] & (plr[16] | (~plr[13] & ~plr[14])); assign alu_c_fc = (~plr[13] & (plr[16] ^ plr[17])) | (~alu_e_fc & ~plr[17]); assign alu_d_fc = ~alu_e_fc & plr[16] & plr[17]; assign alu_e_fc = (~plr[13] & plr[14]) | (~plr[16] & plr[17]); assign alu_x_fc = plr[16] & ~plr[17] & ~alu_e_fc; assign alu_s_fc = ~plr[13] | ~plr[14] | (plr[25] & plr[26]); always @(posedge vm_clk_n) begin cl <= cl_fc; alu_b <= alu_b_fc; alu_c <= alu_c_fc; alu_d <= alu_d_fc; alu_e <= alu_e_fc; alu_x <= alu_x_fc; alu_s <= alu_s_fc; end // // ALU selectable function // assign cpred = {c[14:0], cl}; assign c = (cpred & oxy) | (~cpred & axy & oxy); assign h = (~oxy & ~axy) | (oxy & axy); assign f = alu_e ? h : ~(cpred ^ h); // // ALU result shifter // assign fbit7 = fctl[1] & f[7] | fctl[3] & f[8] | fctl[7] & c[7] | fctl[5] & fbitc; assign fbit15 = fctl[2] & f[15] | fctl[6] & c[15] | fctl[4] & fbitc; assign fctl[1] = ~plr[25] & ~plr[26] & plr[27] & ~plr[18]; assign fctl[2] = ~plr[25] & ~plr[26] & plr[27]; assign fctl[3] = plr[27] & plr[18]; assign fctl[4] = plr[13] & plr[14] & ~plr[25] & plr[26] & plr[27]; assign fctl[5] = plr[13] & plr[14] & ~plr[25] & plr[26] & plr[27] & ~plr[18]; assign fctl[6] = plr[13] & plr[14] & plr[25] & ~plr[26] & plr[27]; assign fctl[7] = plr[13] & plr[14] & plr[25] & ~plr[26] & plr[27] & ~plr[18]; // // assign alu_shr = ~alu_s & plr[27]; // assign alu_shl = ~alu_s & ~plr[27]; // assign alu = ~(alu_s ? f : (plr[27] ? {fbit15, f[15:9], fbit7, f[7:1]} : {f[14:0], fbitc})); // // ALU result condition flags // assign flag[0] = alu_s ? ~fmux[0] : ~fmux[1]; // C assign flag[2] = (~plr[18] | (alu[15:8] == 8'o000)) & (alu[7:0] == 8'o000); // Z assign flag[3] = plr[18] ? alu[15] : alu[7]; // N assign flag[1] = ~(alu_s & alu_e) // V & ~(((fmux[1] ^ flag[3]) | alu_s) & (plr[18] ? (c[14] ^ ~c[15]) : (c[6] ^ ~c[7]))); assign fmux[0] = cl ? (alu_e | (plr[18] ? c[15] : c[7])) : ~(alu_e | (plr[18] ? c[15] : c[7])); assign fmux[1] = (f[0] | ~plr[27]) & (plr[27] | (plr[18] ? f[15] : f[7])); assign fbitc = ~(psw[0] & ~plr[25] & plr[26]); // // ALU and/or products // assign oxy = ~nx | ~((~plr[17] ? ~yreg : 16'o000000) | (alu_b ? yreg : 16'o000000)); assign axy = ~nx & ~(alu_d ? yreg : 16'o000000) & ~(alu_c ? ~yreg : 16'o000000); endmodule //______________________________________________________________________________ // // Vector address and constant generator // module vm1_vgen ( input [15:0] ireg, // instruction register input [3:0] vsel, // vector output selection input [3:0] csel, // constant output selection input vena, // vector output enable input cena, // constant output enable input carry, // carry flag psw[0] input [1:0] pa, // processor number output [15:0] value // output vector value ); reg [15:0] vmux; // variable for vector multiplexer reg [15:0] cmux; // variable for constant multiplexer // // On schematics vsel is {pli[3], ~pli[2], pli[1], pli[0]} // always @(*) begin case(vsel) 4'b0000: vmux = 16'o160006; // double error 4'b0001: vmux = 16'o000020; // IOT instruction 4'b0010: vmux = 16'o000010; // reserved opcode 4'b0011: vmux = 16'o000014; // T-bit/BPT trap 4'b0100: vmux = 16'o000004; // invalid opcode 4'b0101: // or bus timeout case (pa[1:0]) // initial start 2'b00: vmux = 16'o177716; // register base 2'b01: vmux = 16'o177736; // depends on 2'b10: vmux = 16'o177756; // processor number 2'b11: vmux = 16'o177776; // default:vmux = 16'o177716; // endcase // 4'b0110: vmux = 16'o000030; // EMT instruction 4'b0111: vmux = 16'o160012; // int ack timeout 4'b1000: vmux = 16'o000270; // IRQ3 falling edge 4'b1001: vmux = 16'o000024; // ACLO falling edge 4'b1010: vmux = 16'o000100; // IRQ2 falling edge 4'b1011: vmux = 16'o160002; // IRQ1 low level/HALT 4'b1100: vmux = 16'o000034; // TRAP instruction 4'b1101: vmux = ireg; // instruction register 4'b1110: vmux = 16'o000000; // start @177704 4'b1111: vmux = 16'o000000; // unused vector (iako) default: vmux = 16'o000000; // endcase end // // Constant generator and opcode fields shifter/truncator // // On schematics csel is plr[28:25] // // csel0 = 4b'00xx // csel1 = 4b'01xx // csel2 = 4b'10xx // csel3 = 4b'11xx // csel4 = 4b'xx00 // csel5 = 4b'xx01 // csel6 = 4b'xx10 // csel7 = 4b'xx11 // always @(*) begin case(csel) 4'b0000: cmux = {12'o0000, ireg[3:0]}; // csel0 & csel4 (CLx/SEx) 4'b0001: cmux = 16'o000340; // csel0 & csel5 (start PSW constant) 4'b0010: cmux = 16'o000000; // csel0 & csel6 (vector output) 4'b0011: cmux = 16'o000002; // csel0 & csel7 4'b0100: cmux = {9'o000, ireg[5:0], 1'b0}; // csel1 & csel4 (MARK/SOB) 4'b0101: cmux = 16'o177716; // csel1 & csel5 4'b0110: cmux = 16'o177777; // csel1 & csel6 4'b0111: cmux = 16'o000001; // csel1 & csel7 4'b1000: // begin // csel2 & csel4 if (ireg[7]) // cmux = {7'o177, ireg[7:0], 1'b0}; // low byte x2 (BR/Bxx) else // sign extension cmux = {7'o000, ireg[7:0], 1'b0}; // for branches end // 4'b1001: cmux = 16'o100000; // csel2 & csel5 4'b1010: cmux = 16'o177676; // csel2 & csel6 4'b1011: cmux = 16'o000020; // csel2 & csel7 (MUL) 4'b1100: cmux = {15'o00000, carry}; // csel3 & csel4 (ADC/SBC) 4'b1101: cmux = 16'o177400; // csel3 & csel5 (start address AND) 4'b1110: cmux = 16'o000010; // csel3 & csel6 4'b1111: cmux = 16'o000000; // csel3 & csel7 (vector read/vsel) default: cmux = 16'o000000; endcase end assign value = (vena ? vmux : 16'o000000) | (cena ? cmux : 16'o000000); endmodule //______________________________________________________________________________ // // Register file, flip-flops implementation // module vm1_reg_ff ( input clk_p, // input clk_n, // input reset, // input [33:0] plr, // control matrix input [15:0] xbus_in, // X bus input output [15:0] xbus_out, // X bus output output [15:0] ybus_out, // Y bus output input wstbl, // write strobe low byte input wstbh, // write strobe high byte // input [15:0] ireg, // instruction register input [3:0] vsel, // interrupt vector selector input [1:0] pa, // processor number input carry // carry flag ); wire vc_vsel, vc_csel; reg [3:0] vc_vreg; wire [15:0] vc_vcd; // vector/constant data wire [13:0] rs0, rs1, rsw; // register select reg [15:0] gpr[0:13]; // register array reg [3:0] xadr; reg [3:0] yadr; always @(posedge clk_n) begin xadr <= plr[33:30]; yadr <= plr[28:25]; end always @(posedge clk_n) begin vc_vreg <= vsel; end assign vc_vsel = (plr[28:25] == 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); assign vc_csel = (plr[28:25] != 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); vm1_vgen vgen( .ireg(ireg), // instruction register .vsel(vc_vreg), // vector output selection .csel(plr[28:25]), // constant output selection .vena(vc_vsel), // vector output enable .cena(vc_csel), // constant output enable .carry(carry), // carry flag psw[0] .pa(pa), // processor number .value(vc_vcd) // output vector value ); assign rs0[0] = (yadr == 4'b1111) & ~plr[11] & ~plr[13]; assign rs0[1] = (yadr == 4'b0111) & ~plr[11] & ~plr[13]; assign rs0[2] = (yadr == 4'b1011) & ~plr[11] & ~plr[13]; assign rs0[3] = (yadr == 4'b0011) & ~plr[11] & ~plr[13]; assign rs0[4] = (yadr == 4'b1101) & ~plr[11] & ~plr[13]; assign rs0[5] = (yadr == 4'b0101) & ~plr[11] & ~plr[13]; assign rs0[6] = (yadr == 4'b1001) & ~plr[11] & ~plr[13]; assign rs0[7] = (yadr == 4'b0001) & ~plr[11] & ~plr[13]; assign rs0[8] = (yadr == 4'b1110) & ~plr[11] & ~plr[13]; assign rs0[9] = (yadr == 4'b0110) & ~plr[11] & ~plr[13]; assign rs0[10] = (yadr == 4'b1010) & ~plr[11] & ~plr[13]; assign rs0[11] = (yadr == 4'b0010) & ~plr[11] & ~plr[13]; assign rs0[12] = (yadr == 4'b1100) & ~plr[11] & ~plr[13] | (plr[13] & plr[14]); assign rs0[13] = (yadr == 4'b0100) & ~plr[11] & ~plr[13]; assign rs1[0] = (xadr == 4'b1111); assign rs1[1] = (xadr == 4'b0111); assign rs1[2] = (xadr == 4'b1011); assign rs1[3] = (xadr == 4'b0011); assign rs1[4] = (xadr == 4'b1101); assign rs1[5] = (xadr == 4'b0101); assign rs1[6] = (xadr == 4'b1001); assign rs1[7] = (xadr == 4'b0001); assign rs1[8] = (xadr == 4'b1110); assign rs1[9] = (xadr == 4'b0110); assign rs1[10] = (xadr == 4'b1010); assign rs1[11] = (xadr == 4'b0010); assign rs1[12] = (xadr == 4'b1100); assign rs1[13] = (xadr == 4'b0100); assign rsw[0] = (xadr == 4'b1111) & plr[20]; assign rsw[1] = (xadr == 4'b0111) & plr[20]; assign rsw[2] = (xadr == 4'b1011) & plr[20]; assign rsw[3] = (xadr == 4'b0011) & plr[20]; assign rsw[4] = (xadr == 4'b1101) & plr[20]; assign rsw[5] = (xadr == 4'b0101) & plr[20]; assign rsw[6] = (xadr == 4'b1001) & plr[20]; assign rsw[7] = (xadr == 4'b0001) & plr[20]; assign rsw[8] = (xadr == 4'b1110) & plr[20]; assign rsw[9] = (xadr == 4'b0110) & plr[20]; assign rsw[10] = (xadr == 4'b1010) & plr[20]; assign rsw[11] = (xadr == 4'b0010) & plr[20]; assign rsw[12] = (xadr == 4'b1100) | ~plr[20]; assign rsw[13] = (xadr == 4'b0100) & plr[20]; assign xbus_out = (rs1[0] ? gpr[0] : 16'o000000) | (rs1[1] ? gpr[1] : 16'o000000) | (rs1[2] ? gpr[2] : 16'o000000) | (rs1[3] ? gpr[3] : 16'o000000) | (rs1[4] ? gpr[4] : 16'o000000) | (rs1[5] ? gpr[5] : 16'o000000) | (rs1[6] ? gpr[6] : 16'o000000) | (rs1[7] ? gpr[7] : 16'o000000) | (rs1[8] ? gpr[8] : 16'o000000) | (rs1[9] ? gpr[9] : 16'o000000) | (rs1[10] ? gpr[10] : 16'o000000) | (rs1[11] ? gpr[11] : 16'o000000) | (rs1[12] ? gpr[12] : 16'o000000) | (rs1[13] ? gpr[13] : 16'o000000); assign ybus_out = (rs0[0] ? gpr[0] : 16'o000000) | (rs0[1] ? gpr[1] : 16'o000000) | (rs0[2] ? gpr[2] : 16'o000000) | (rs0[3] ? gpr[3] : 16'o000000) | (rs0[4] ? gpr[4] : 16'o000000) | (rs0[5] ? gpr[5] : 16'o000000) | (rs0[6] ? gpr[6] : 16'o000000) | (rs0[7] ? gpr[7] : 16'o000000) | (rs0[8] ? gpr[8] : 16'o000000) | (rs0[9] ? gpr[9] : 16'o000000) | (rs0[10] ? gpr[10] : 16'o000000) | (rs0[11] ? gpr[11] : 16'o000000) | (rs0[12] ? gpr[12] : 16'o000000) | (rs0[13] ? gpr[13] : 16'o000000) | (vc_vsel ? vc_vcd : 16'o000000) | (vc_csel ? vc_vcd : 16'o000000); always @(posedge clk_n) begin if (wstbl) begin if (rsw[0]) gpr[0][7:0] <= xbus_in[7:0]; if (rsw[1]) gpr[1][7:0] <= xbus_in[7:0]; if (rsw[2]) gpr[2][7:0] <= xbus_in[7:0]; if (rsw[3]) gpr[3][7:0] <= xbus_in[7:0]; if (rsw[4]) gpr[4][7:0] <= xbus_in[7:0]; if (rsw[5]) gpr[5][7:0] <= xbus_in[7:0]; if (rsw[6]) gpr[6][7:0] <= xbus_in[7:0]; if (rsw[7]) gpr[7][7:0] <= xbus_in[7:0]; if (rsw[8]) gpr[8][7:0] <= xbus_in[7:0]; if (rsw[9]) gpr[9][7:0] <= xbus_in[7:0]; if (rsw[10]) gpr[10][7:0] <= xbus_in[7:0]; if (rsw[11]) gpr[11][7:0] <= xbus_in[7:0]; if (rsw[12]) gpr[12][7:0] <= xbus_in[7:0]; if (rsw[13]) gpr[13][7:0] <= xbus_in[7:0]; end if (wstbh) begin if (rsw[0]) gpr[0][15:8] <= xbus_in[15:8]; if (rsw[1]) gpr[1][15:8] <= xbus_in[15:8]; if (rsw[2]) gpr[2][15:8] <= xbus_in[15:8]; if (rsw[3]) gpr[3][15:8] <= xbus_in[15:8]; if (rsw[4]) gpr[4][15:8] <= xbus_in[15:8]; if (rsw[5]) gpr[5][15:8] <= xbus_in[15:8]; if (rsw[6]) gpr[6][15:8] <= xbus_in[15:8]; if (rsw[7]) gpr[7][15:8] <= xbus_in[15:8]; if (rsw[8]) gpr[8][15:8] <= xbus_in[15:8]; if (rsw[9]) gpr[9][15:8] <= xbus_in[15:8]; if (rsw[10]) gpr[10][15:8] <= xbus_in[15:8]; if (rsw[11]) gpr[11][15:8] <= xbus_in[15:8]; if (rsw[12]) gpr[12][15:8] <= xbus_in[15:8]; if (rsw[13]) gpr[13][15:8] <= xbus_in[15:8]; end end // synopsys translate_off initial begin gpr[0] = 16'o000000; gpr[1] = 16'o000000; gpr[2] = 16'o000000; gpr[3] = 16'o000000; gpr[4] = 16'o000000; gpr[5] = 16'o000000; gpr[6] = 16'o000000; gpr[7] = 16'o000000; gpr[8] = 16'o000000; gpr[9] = 16'o000000; gpr[10] = 16'o000000; gpr[11] = 16'o000000; gpr[12] = 16'o000000; gpr[13] = 16'o000000; end // synopsys translate_on endmodule //______________________________________________________________________________ // // Register file, RAM implementation // module vm1_reg_ram ( input clk_p, // input clk_n, // input reset, // input [33:0] plr, // control matrix input [15:0] xbus_in, // X bus input output [15:0] xbus_out, // X bus output output [15:0] ybus_out, // Y bus output input wstbl, // write strobe low byte input wstbh, // write strobe high byte // input [15:0] ireg, // instruction register input [3:0] vsel, // interrupt vector selector input [1:0] pa, // processor number input carry // carry flag ); wire vc_vsel, vc_csel; reg [3:0] vc_reg; wire [15:0] vc_mux; wire [5:0] xadr; wire [5:0] yadr; wire wren; always @(posedge clk_n) begin vc_reg <= vsel; end assign vc_vsel = (plr[28:25] == 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); assign vc_csel = (plr[28:25] != 4'b0010) & ((plr[13] & ~plr[14]) | plr[11]); assign wren = (wstbl & (plr[32:30] != 3'b000) & plr[20]) | (wstbl & ~plr[20]); assign xadr[5:0] = {2'b00, wstbl ? (plr[20] ? plr[33:30] : 4'b1100) : plr[33:30]}; assign yadr[3:0] = (vc_vsel ? vsel : 4'b0000) | (vc_csel ? plr[28:25] : 4'b0000) | ((plr[13] & plr[14] & ~plr[11]) ? 4'b1100 : 4'b0000) | ((~plr[11] & ~plr[13]) ? plr[28:25] : 4'b0000); assign yadr[4] = vc_vsel; assign yadr[5] = vc_csel; vm1_vcram vm1_vcram_reg( .clock(clk_n), .address_a(xadr), .data_a(xbus_in), .q_a(xbus_out), .byteena_a({wstbh | ~wstbl, 1'b1}), .wren_a(wren), .address_b(yadr), .data_b(16'o000000), .wren_b(1'b0), .q_b(vc_mux)); assign ybus_out = vc_mux | ((vc_vsel & (vc_reg == 4'b0101)) ? {10'o0000, pa, 4'o00} : 16'o000000) | ((vc_vsel & (vc_reg == 4'b1101)) ? ireg : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b0000)) ? {12'o0000, ireg[3:0]} : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b0100)) ? {9'o000, ireg[5:0], 1'b0} : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b1000)) ? {ireg[7] ? 7'o177 : 7'o000, ireg[7:0], 1'b0} : 16'o000000) | ((vc_csel & (plr[28:25] == 4'b1100)) ? {15'o00000, carry} : 16'o000000); endmodule