// // Copyright (c) 2014-2019 by 1801BM1@gmail.com // // LSI-11 synchronous model with Wishbone interfaces //______________________________________________________________________________ // module lsi_wb #(parameter //______________________________________________________________________________ // // LSI11_ORIGINAL_MICROM nonzero value means the original DEC Microm // 1631-10/07/15 content is used, we can optimize 4 MSbs with ordinal logic // and save memory blocks // LSI11_ORIGINAL_MICROM = 1 ) ( // // 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_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 edge clock input vm_clk_n, // negative edge clock input vm_clk_ena, // slow clock enable input vm_clk_slow, // slow clock sim mode // output vm_init, // peripheral reset output input vm_dclo, // processor reset input vm_aclo, // power fail notificaton input vm_halt, // halt mode interrupt input vm_evnt, // timer 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 input wbi_ack_i, // interrupt vector acknowledgement output wbi_stb_o, // interrupt vector strobe // input [1:0] vm_bsel // boot mode selector ); //______________________________________________________________________________ // reg [15:0] wb_adr; // master wishbone address reg [15:0] wb_dat; // master wishbone data output reg [1:0] wb_sel; // master wishbone byte selection reg wb_ios; // master wishbone I/O selection reg wb_cyc; // master wishbone cycle reg wb_we; // master wishbone direction reg wb_stb; // master wishbone strobe reg wb_iak; // interrupt vector strobe reg wb_rdy; // data read completed reg [1:0] wb_ra; // extended reply // wire wb_wdone; // wire wb_rdone; // wire wb_idone; // // reg [7:0] wb_wcnt; // slow clock counter wire wb_wset, wb_wclr; // // wire [21:0] m_rom; // microcode instructions from 1631 wire [21:0] m_mux; // microcode multiplexer wire [15:0] m_dat; // microcode data from 1611 wire [10:0] m_lc; // wire m_nop; // translate NOP while in reset wire m_inp; // translate data for input // wire m_astb; // address strobe wire m_dstb; // data strobe wire [15:0] m_ado; // data chip output reg [15:0] m_adi; // data chip input // // code 010 - not used wire mc_clr_init; // code 011 - deassert peripheral INIT wire mc_clr_berr; // code 012 - clear refresh and bus error wire mc_set_init; // code 014 - assert peripheral INIT wire mc_set_fdin; // code 015 - set fast input flag wire mc_clr_aclo; // code 016 - clear ACLO detector wire mc_clr_evnt; // code 017 - clear event/timer interrupt // reg wcyc_ed; // cycle edge detector reg aclo_ed; // nACLO edge detector reg evnt_ed; // nEVNT edge detector // reg aclo_rq; // nACLO falling edge detected reg evnt_rq; // nEVNT falling edge detected reg init_st; // nINIT flag reg fdin_st; // fast data input flag reg berr_rq; // bus error (timeout) request reg berr_st; // bus error sticky status reg [5:0] qtim; // Q-bus transaction timer wire qtim_to; // Q-bus timer output wire qtim_en; // Q-bus time enable wire [3:0] fdin; // fast data input // wire [4:1] m_inrrq; // interrupt requests reg m_sr; // system reset wire m_wi; // wait line wire m_br; // condidion taken reg m_bbusy; // bus busy wire m_ra; // reply wire m_synr; // sync reset wire m_syns; // sync set wire m_dclr; // read completed wire m_di; // data input wire m_do; // data output wire m_iak; // interrupt ack wire m_wrby; // write byte wire m_breq; // bus request // //______________________________________________________________________________ // // Master and Interrupt Wishbone assignments // assign wbm_adr_o[15:0] = wb_adr[15:0]; assign wbm_dat_o[15:0] = wb_dat[15:0]; assign wbm_sel_o[1:0] = wb_sel[1:0]; assign wbm_ios_o = wb_ios; assign wbm_cyc_o = wb_cyc; assign wbm_stb_o = wb_stb; assign wbi_stb_o = wb_iak; assign wbm_we_o = wb_we; assign vm_init = init_st; always @(posedge vm_clk_p) begin if (m_astb) wb_ios = &m_ado[15:13]; if (m_astb) wb_adr = m_ado; if (m_dstb) wb_dat = m_ado; if (wb_rdone | wb_idone) begin if (wb_stb) m_adi <= fdin_st ? {wbm_dat_i[15:4], fdin} : wbm_dat_i; else m_adi <= wbi_dat_i; end end //_____________________________________________________________________________ // // Wishbone logic // assign wb_wdone = wb_stb & wbm_ack_i & wb_we; assign wb_rdone = wb_stb & wbm_ack_i & ~wb_we; assign wb_idone = wb_iak & wbi_ack_i; always @(posedge vm_clk_p or posedge m_sr) begin if (m_sr) begin wb_cyc <= 1'b0; wb_stb <= 1'b0; wb_iak <= 1'b0; wb_sel <= 2'b11; wb_we <= 1'b0; wb_ra <= 2'b00; wb_rdy <= 1'b0; end else begin // // Cycle starts on the active m_syns // if (m_syns) wb_cyc <= 1'b1; // // Completes on write or actual data read by data chip // if (wb_wdone | wb_rdone & m_synr | wb_rdy & m_synr) wb_cyc <= 1'b0; if (m_syns | m_synr | m_dclr) wb_rdy <= 1'b0; else if (wb_rdone) wb_rdy <= 1'b1; wb_we <= m_do & ~wbm_ack_i & wb_cyc; if (wb_cyc & m_do & m_wrby) wb_sel <= wb_adr[0] ? 2'b10 : 2'b01; else wb_sel <= 2'b11; wb_stb <= m_do & ~wb_stb & wb_cyc | m_di | wb_stb & ~(wb_rdone | wb_wdone); if (m_iak) wb_iak <= 1'b1; else if (wb_idone) wb_iak <= 1'b0; // // Completion strobe for control chip // wb_ra[0] <= wb_rdone | wb_rdy & ~m_dclr | wb_wdone | wb_idone; wb_ra[1] <= wb_ra[0] & ~(m_synr | wb_rdy & m_dclr); end end assign m_ra = wb_ra[0] | wb_ra[1]; //_____________________________________________________________________________ // // Bus moderator - holds the Control chip with m_bbusy signal // always @(posedge vm_clk_p or posedge m_sr) begin if (m_sr) m_bbusy <= 1'b0; else if (wb_wset) m_bbusy <= vm_clk_slow; else if (wb_wclr) m_bbusy <= 1'b0; end assign wb_wset = vm_clk_slow & ~m_breq & (wb_wcnt != 8'h00); assign wb_wclr = ~vm_clk_slow | (vm_clk_ena & (wb_wcnt == 8'h01)); always @(posedge vm_clk_p or posedge m_sr) begin if (m_sr) wb_wcnt <= 8'h00; else begin if (~vm_clk_slow) wb_wcnt <= 8'h00; else if (m_bbusy & m_breq) begin if (vm_clk_ena) wb_wcnt <= wb_wcnt - 8'h01; end else if (~vm_clk_ena & vm_clk_slow & (wb_wcnt != 8'hFF)) wb_wcnt <= wb_wcnt + 8'h01; end end //_____________________________________________________________________________ // assign fdin[0] = vm_bsel[0]; // fast data input assign fdin[1] = vm_bsel[1]; // boot mode assign fdin[2] = berr_st; // bus error assign fdin[3] = vm_aclo | aclo_rq; // power failure //_____________________________________________________________________________ // // Microcode controlled strobes (with M18-M21 extra bits) // assign mc_clr_init = (m_mux[21:18] == 4'b1001); // code 011 - deassert INIT assign mc_clr_berr = (m_mux[21:18] == 4'b1010); // code 012 - clear bus error assign mc_set_init = (m_mux[21:18] == 4'b1100); // code 014 - assert INIT assign mc_set_fdin = (m_mux[21:18] == 4'b1101); // code 015 - set fast input assign mc_clr_aclo = (m_mux[21:18] == 4'b1110); // code 016 - clear ACLO assign mc_clr_evnt = (m_mux[21:18] == 4'b1111); // code 017 - clear event //_____________________________________________________________________________ // // Reset, interrupts and exceptions // // AC power failure interrupt edge detector // always @(posedge vm_clk_p) begin aclo_ed <= vm_aclo; if (mc_clr_aclo | vm_dclo) aclo_rq <= 1'b0; else if (vm_aclo & ~aclo_ed) aclo_rq <= 1'b1; end // // Periodic timer interrupt edge detector // always @(posedge vm_clk_p) begin evnt_ed <= vm_evnt; if (mc_clr_evnt | vm_dclo) evnt_rq <= 1'b0; else if (vm_evnt & ~evnt_ed) evnt_rq <= 1'b1; end // // // Processor interrupts // assign m_inrrq[1] = vm_virq; assign m_inrrq[2] = evnt_rq; assign m_inrrq[3] = aclo_rq | vm_halt; assign m_inrrq[4] = 1'b0; // // Peripheral devices reset, controlled by microcode M18-M21 // always @(posedge vm_clk_p) begin if (vm_dclo | mc_set_init) init_st <= 1'b1; else if (mc_clr_init) init_st <= 1'b0; end // // Fast input (unaddressed) flag, controlled by microcode M18-M21 // always @(posedge vm_clk_p) begin wcyc_ed <= wbm_cyc_o; if (~wbm_cyc_o & wcyc_ed) fdin_st <= 1'b0; else if (mc_set_fdin & wbm_cyc_o) fdin_st <= 1'b1; end // // Processor data cycle abort // always @(posedge vm_clk_p) begin if (vm_dclo) m_sr <= 1'b1; else m_sr <= berr_rq; end //_____________________________________________________________________________ // // Q-bus timer // always @(posedge vm_clk_p) begin if (~qtim_en) qtim <= 6'b000000; else if (~qtim_to) qtim <= qtim + 6'b000001; if (init_st | mc_clr_berr) berr_st <= 1'b0; else if (qtim_to) berr_st <= 1'b1; berr_rq <= qtim_en & qtim_to; end assign qtim_to = qtim == 6'b111111; assign qtim_en = wbm_gnt_i & (wbm_stb_o | wbi_stb_o); //_____________________________________________________________________________ // assign m_mux[15:0] = m_dat[15:0] | (m_inp ? 16'h0000 : m_rom[15:0]) | (m_nop ? 16'hFF00 : 16'h0000); assign m_mux[21:16] = (m_nop | m_inp) ? 6'h00 : m_rom[21:16]; mcp1611 data ( .pin_clk_p(vm_clk_p), .pin_clk_n(vm_clk_n), .pin_mi(m_mux[15:0]), .pin_mo(m_dat[15:0]), .pin_wi(m_wi), .pin_cond(m_br), .pin_ado(m_ado), .pin_adi(m_adi), .pin_astb(m_astb), .pin_dstb(m_dstb) ); mcp1621 control ( .pin_clk_p(vm_clk_p), .pin_clk_n(vm_clk_n), .pin_lc(m_lc[10:0]), .pin_mi(m_mux[17:0]), .pin_nop(m_nop), .pin_inp(m_inp), .pin_cond(m_br), .pin_wi(m_wi), .pin_inrrq(m_inrrq), .pin_bbusy(m_bbusy), .pin_sr(m_sr), .pin_ra(m_ra), .pin_synr(m_synr), .pin_syns(m_syns), .pin_dclr(m_dclr), .pin_di(m_di), .pin_do(m_do), .pin_inrak(m_iak), .pin_wrby(m_wrby), .pin_breq(m_breq) ); defparam microm.LSI11_ORIGINAL_MICROM = LSI11_ORIGINAL_MICROM; mcp1631 microm ( .pin_clk(vm_clk_p), .pin_lc(m_lc[10:0]), .pin_mo(m_rom[21:0]) ); //_____________________________________________________________________________ // endmodule