// // Copyright (c) 2014-2015 by 1801BM1@gmail.com //______________________________________________________________________________ // // Real VM1 module thunk from Wishbone compatible version of 1801VM1 processor // `include "config.v" module vm1_mod ( // // 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 [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 election 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 // inout [31:0] vm_gpio, // external GPIO inout [1:0] vm_gpio_in, // output [1:0] vm_gpio_out // ); //______________________________________________________________________________ // reg [31:25] vm_gpio_t0; // reg [31:25] vm_gpio_t1; // // reg [7:0] qbus_div; // reg qbus_clk; // reg qbus_rise; // reg qbus_fall; // reg [3:0] qbus_irq; // reg qbus_rply; // reg qbus_aclo; // reg qbus_dclo; // // reg rply; // reg [15:0] addr; // reg [15:0] data_in; // reg [15:0] data_out; // // wire din, dout, wtbt; // wire sync, iako, init; // wire dmgo; // reg [2:0] wedge; // reg redge, iedge; // reg ioe, doe, roe; // // reg [15:0] wbs_d; // slave wishbone data register reg wbs_r, wbs_w; // reg wbs_a; // wire wbs_a_rc; // // reg wb_we, wb_cyc; // reg wb_stb, wbi_stb; // reg [1:0] wb_sel; // reg [1:0] wlock; // //______________________________________________________________________________ // // Clock prescaler // initial begin qbus_div = 8'h00; rply = 1'b0; wb_cyc = 1'b0; wb_we = 1'b0; wb_sel = 2'b00; wb_stb = 1'b0; wbi_stb = 1'b0; ioe = 1'b0; doe = 1'b0; roe = 1'b0; wlock = 2'b00; end // // vm_clk_n - ignored // vm_clk_ena - ignored // vm_clk_tve - ignored // vm_clk_sp - ignored // vm_clk_slow - ignored // vm_pa - ignored // vm_init_in - ignored // always @(posedge vm_clk_p) begin if (qbus_div == `VM1_CLOCK_LOW) begin qbus_div <= 8'h00; qbus_clk <= 1'b0; end else begin if (qbus_div == `VM1_CLOCK_HIGH) qbus_clk <= 1'b1; qbus_div <= qbus_div + 8'h01; end qbus_rise <= (qbus_div == `VM1_CLOCK_HIGH); qbus_fall <= (qbus_div == `VM1_CLOCK_LOW); end // // Input latches // always @(posedge vm_clk_p) begin // // Resolve metastability issues // vm_gpio_t0 <= {vm_gpio_in, vm_gpio[29:25]}; vm_gpio_t1 <= vm_gpio_t0; end assign sync = ~vm_gpio_t1[25]; assign din = ~vm_gpio_t1[26]; assign dout = ~vm_gpio_t1[27]; assign wtbt = ~vm_gpio_t1[28]; assign init = ~vm_gpio_t1[29]; assign dmgo = ~vm_gpio_t1[30]; assign iako = ~vm_gpio_t1[31]; assign vm_gpio_out[0] = qbus_clk; assign vm_gpio_out[1] = ~qbus_aclo; assign vm_gpio[14] = ~qbus_dclo; assign vm_gpio[15] = 1'b1; assign vm_gpio[16] = 1'b1; assign vm_gpio[17] = ~qbus_irq[1]; assign vm_gpio[20] = ~qbus_irq[2]; assign vm_gpio[21] = ~qbus_irq[3]; assign vm_gpio[22] = ~qbus_irq[0]; assign vm_gpio[23] = 1'bZ; assign vm_gpio[24] = ~qbus_rply; assign vm_gpio[30] = 1'b0; // nEXENA assign vm_gpio[31] = ~ioe; // nEXDIN assign vm_gpio[19:18] = (ioe & doe) ? ~data_in[15:14] : 2'bZZ; assign vm_gpio[13:0] = (ioe & doe) ? ~data_in[13:0] : 14'hZZZZ; always @(posedge vm_clk_p) begin roe <= ioe & ~din; doe <= ioe & din; if (din & rply) ioe <= 1'b1; else if (roe) ioe <= 1'b0; end // // Outputs synchronization at CLK transition // always @(posedge vm_clk_p) begin if (qbus_rise) begin qbus_aclo <= vm_aclo; qbus_dclo <= vm_dclo; qbus_irq <= {vm_irq, vm_virq}; end // if (qbus_fall) if (qbus_rise) begin qbus_rply <= rply; end end always @(posedge vm_clk_p) begin wedge[0] <= dout & sync; wedge[1] <= wedge[0]; wedge[2] <= wedge[1]; redge <= din & sync; iedge <= din & iako; if (~sync) addr <= ~{vm_gpio[19:18], vm_gpio[13:0]}; if (~wedge[2] & wedge[1]) data_out <= ~{vm_gpio[19:18], vm_gpio[13:0]}; if (wbm_ack_i & sync & (din | dout)) rply <= 1'b1; else if (wbi_ack_i & iako & din) rply <= 1'b1; else if (~din & ~dout) rply <= 1'b0; end assign vm_init_out = init; assign wbm_adr_o = addr; assign wbm_dat_o = data_out; 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 = wbi_stb; always @(posedge vm_clk_p) begin if (vm_aclo & vm_dclo) wlock[0] <= 1'b1; if (wbm_stb_o & wbm_ack_i) data_in <= wbm_dat_i; if (wbi_stb_o & wbi_ack_i) data_in <= wbi_dat_i; // // Start interrupt vector fetch // if (~iedge & iako & din) wbi_stb <= 1'b1; else if (~iako | ~din | wbi_ack_i) wbi_stb <= 1'b0; if ((addr[15:6] != 10'O1777) | (addr[3:2] == 2'b11)) begin if (~wedge[2] & wedge[1] & ~vm_dclo & (wlock == 2'b11)) begin wb_cyc <= 1'b1; wb_we <= 1'b1; wb_stb <= 1'b1; wb_sel[0] <= ~wtbt | ~addr[0]; wb_sel[1] <= ~wtbt | addr[0]; end if (~redge & sync & din) begin if ((addr == 16'O177716) & ~vm_aclo & ~vm_dclo) wlock[1] <= 1'b1; wb_cyc <= 1'b1; wb_we <= 1'b0; wb_stb <= 1'b1; wb_sel <= 2'b11; end if ((~sync & ~din & ~dout) | wbm_ack_i) begin wb_cyc <= 1'b0; wb_stb <= 1'b0; wb_we <= 1'b0; wb_sel <= 2'b00; end 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 assign wbs_dat_o = wbs_d; assign wbs_ack_o = wbs_a; assign wbs_a_rc = wbs_cyc_i & wbs_stb_i & (wbs_adr_i[3:2] == 2'b11) & ((~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'b110: wbs_d <= vm_reg14; // 177714 3'b111: wbs_d <= vm_reg16; // 177716 default: wbs_d <= 16'o000000; endcase end endmodule