/* Copyright 2008, 2010 Unpublished Work of Technologic Systems
 * All Rights Reserved.
 *
 * THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL,
 * PROPRIETARY AND TRADE SECRET INFORMATION OF TECHNOLOGIC SYSTEMS.
 * ACCESS TO THIS WORK IS RESTRICTED TO (I) TECHNOLOGIC SYSTEMS 
 * EMPLOYEES WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE
 * OF THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN TECHNOLOGIC
 * SYSTEMS WHO HAVE ENTERED INTO APPROPRIATE LICENSE AGREEMENTS.  NO
 * PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, 
 * DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, 
 * EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, TRANSFORMED, ADAPTED
 * IN ANY FORM OR BY ANY MEANS, MANUAL, MECHANICAL, CHEMICAL, 
 * ELECTRICAL, ELECTRONIC, OPTICAL, BIOLOGICAL, OR OTHERWISE WITHOUT
 * THE PRIOR WRITTEN PERMISSION AND CONSENT OF TECHNOLOGIC SYSTEMS.
 * ANY USE OR EXPLOITATION OF THIS WORK WITHOUT THE PRIOR WRITTEN
 * CONSENT OF TECHNOLOGIC SYSTEMS COULD SUBJECT THE PERPETRATOR TO
 * CRIMINAL AND CIVIL LIABILITY.
 *
 */

/* Modified ISA muxed bus.  Timing is in terms of wb_clk_i clock cycles.
 * the bus_config_i input is a 16 bit configuration which should be controlled
 * by a syscon register.  5 timing paramters are controlled.  Each defaults to
 * 1 clock, and the register values specify the additional cycles.
 * Bit 0 is used as an enable if necessary, enabling the bus occurs outside
 * this module.
 * Bits 2:1 = extra ALE pulse time
 * Bits 4:3 = extra address hold time
 * Bits 6:5 = extra data setup time
 * Bits 12:7 = extra CS pulse time (use 0 to 62 -- 63 will crash it)
 * Bits 15:13 = extra data hold time
 */
module isamuxbus_bridge(
  wb_clk_i,
  wb_rst_i,
  wb_cyc_i,
  wb_stb_i,
  wb_adr_i,
  wb_dat_i,
  wb_sel_i,
  wb_dat_o,
  wb_ack_o,
  wb_we_i,
  iospace_en_i,

  bus_config_i,
  cs_8bit_i,
  // cs_8bit_i is an external signal that forces the bus to only use mux lines
  // 0-7 for data. Normally it can be just the inverse of the 8 bit CS line.
  // When not asserted, lines 8-15 are used for odd addressed bytes.

  csn_o,
  dir_o,
  ale_o,
  bhen_o,
  waitn_i,
  mux_i,
  mux_o,
  mux_oe_o,
  cycle_o
);

input wb_clk_i, wb_rst_i, wb_cyc_i, wb_stb_i, wb_we_i;
input [1:0] wb_sel_i;
input [15:0] wb_dat_i;
input [31:0] wb_adr_i;
output [15:0] wb_dat_o;
output wb_ack_o;

input [15:0] bus_config_i;
input cs_8bit_i;

output csn_o, dir_o, ale_o, bhen_o;
input waitn_i, iospace_en_i;
input [15:0] mux_i;
output [15:0] mux_o;
output mux_oe_o;
output cycle_o;

reg [5:0] state, count;
reg wb_ack, ale, mux_oe;
reg [15:0] mux, wb_dat;
assign wb_dat_o = wb_dat;
reg csn, waitn, dir;
assign csn_o = csn;
assign dir_o = dir;
assign mux_oe_o = mux_oe;
assign mux_o = mux;
assign ale_o = ale;
assign wb_ack_o = wb_ack;

// BHE# is asserted on the 16 bit bus when sel[1] is asserted.
reg bhe;
assign bhen_o = !bhe;
reg cycle;
assign cycle_o = cycle;

// timing parameters from syscon config register:
wire [1:0] tp_ale = bus_config_i[2:1];
wire [1:0] th_adr = bus_config_i[4:3]; 
wire [1:0] tsu_dat = bus_config_i[6:5]; 
wire [5:0] tp_cs = bus_config_i[12:7]; 
wire [2:0] th_dat = bus_config_i[15:13]; 

always @(posedge wb_clk_i or posedge wb_rst_i) begin
  if (wb_rst_i) begin
    bhe <= 1'b0;
    state <= 6'd0;
    mux <= 16'd0;
    mux_oe <= 1'b0;
    ale <= 1'b0;
    count <= 6'd0;
    wb_dat <= 16'd0;
    waitn <= 1'b0;
    csn <= 1'b1;
    wb_ack <= 1'b0;
    dir <= 1'b0;
    cycle <= 1'b0;
  end else begin
    wb_ack <= 1'b0;
    waitn <= waitn_i;

    case (state)
    6'd0: if (wb_cyc_i && wb_stb_i && !wb_ack) begin // 0: idle
      bhe <= wb_sel_i[1] && !cs_8bit_i;
      mux[15:1] <= wb_adr_i[15:1];
      mux[0] <= !wb_sel_i[0]; // sel[0] is asserted iff even address.
      cycle <= 1'b1;
      mux_oe <= 1'b1;
      ale <= 1'b1;
      state <= 6'd1;
      count[1:0] <= tp_ale;
    end
    6'd1: begin // 1: pulse ale
      count <= count - 1'b1;
      if (count[1:0] == 2'd0) begin
        count[1:0] <= th_adr;
        ale <= 1'b0;
        state <= 6'd2;
      end
    end
    6'd2: begin // 2: address hold time
      count <= count - 1'b1;
      if (count[1:0] == 2'd0) begin
        count[1:0] <= tsu_dat;
        state <= 6'd3;
        dir <= !wb_we_i;
        mux_oe <= wb_we_i;
        if (cs_8bit_i && wb_adr_i[0])
          mux[7:0] <= wb_dat_i[15:8];
        else
          mux <= wb_dat_i[15:0];
      end
    end
    6'd3: begin // 3: data setup time
      count <= count - 1'b1;
      if (count[1:0] == 2'd0) begin
        count <= tp_cs;
        state <= 6'd4;
        csn <= 1'b0;
      end
    end
    6'd4: begin // 4: assert CS
      if (count != 6'd0) count <= count - 1'b1;
      if (count == 6'd0 && waitn) begin
        if (cs_8bit_i) wb_dat <= {mux_i[7:0], mux_i[7:0]};
        else wb_dat <= mux_i; 
        count[2:0] <= th_dat;
        state <= 6'd5;
        wb_ack <= 1'b1;
        csn <= 1'b1;
      end
    end
    6'd5: begin // 5: data hold time
      count <= count - 1'b1;
      if (count[2:0] == 3'd0) begin
        mux_oe <= 1'b0;
        state <= 6'd0;
        cycle <= 1'b0;
      end
    end
    endcase
  end
end

endmodule
