// 11/08/04
// rev C
// start from lmcp12.v
// add BR-, SPIS07-, SDA, SCL, IO_ON
// remove ID (CFLG0- goes instead)
// make IDSEL 16 bits with only correct ones active for the board
// dummy as a place holder on pin A3
// 07/15/04
// put the id address registers in correct place
// there is only 1 id chip 
// changed idsel to a wire and fixed it at 01
// added revision register
//
// 04/26/04
// add 48 Volt switch
//
// 02/10/04
// added regulator syncs
// change output structure on D to conform
// needs 48V power switch
//
// rev 1x (started from lmcp03.v)
// CPLD now decodes at A[9] = 1 and the FPGA decodes at A[9] = 0
// 
// clean up 
// "modularize" as with declarations semi local
// 
// clock distribution
// DSP ack
// flash chip select
// FPGA parallel programming interface
// supervisor bit to change meaning of XCSn
// ID chip interface
// regulator syncs
// 48V power supply
//
// 10/21/03
// added comments before checkin
//
// 08/11/03
// revision 03 
// include ID chip selector
//
// 07/29/03
// version to have supervisor and XCS
// identical to lmcp.v
// 07/10/03
// version for bring up of the lm card derived
// derived from the iop board in turn derived
// from the cmd link test board
// 
// 05/22/03
// fixed bug in XCCLK equation
// was 
// assign XCCLK = ( (A == XCFGDATA) && (MS1n == 1'b0) && 
//               (WRn == 1'b1) ) ? 1'b1 : 1'b1;
//
// should be
// assign XCCLK = ( (A == XCFGDATA) && (MS1n == 1'b0) && 
//               (WRn == 1'b0) ) ? 1'b0 : 1'b1;
//
// making 2 xclks per word hence no sync seen
// 05/19/03 Rev2
// Use version from Ken
// change the Xilinx Programming registers from IOMS to MS1
// 10/14/02 Rev 1
// changed signal name from DCLKO to DCLK0 and XCLKO to XCLK0
//
// assuming that RSTn the reset signal is active low
//
// add Virtex programming interface and temporary decodes
// that need to be adjusted
//
// XCCLK is a combinatorial version of WRn and the decode
// and DSP should assert a write hold
//
// WARNING !! WRn does not like to be on a non clock pin with Synpilfy
// but is ok with XST Verilog
//
// FLASH decode needs to fixed -- currently arbitrarily set to all
// of MS and BMS
// 
// Virtex Config  bit positions
// 
//     +-------+-------+-------+--------+--------+------+--------+--------+
// Bit |  15   |  14   |  13   |   12   |   11   |  10  |   9    |    8   |
//     +-------+-------+-------+--------+--------+------+--------+--------+
//     |       |       |       |        |        |      |        |        |
//     +-------+-------+-------+--------+--------+------+--------+--------+
//     +-------+-------+-------+--------+--------+------+--------+--------+
// Bit |  7    |   6   |   5   |   4    |   3    |   2  |   1    |    0   |
//     +-------+-------+-------+--------+--------+------+--------+--------+
//     | FBUSYn| XDONE | XBUSY | XINITn | XRDWRn | XCSn | XPROGn | XPWDNn |
//     +-------+-------+-------+--------+--------+------+--------+--------+
//
// XBUSY has no logic and is useless really
// According to Xilinx we dont have to look at it if frequency
// is less than 66MHz
//
// XINITn is an open collector signal that will drive a 0 when
// set to 0, tristate on 1 (reset value is 1)
//
// XCFGDATA is the address the dsp writes the data
// XCFGCTL  is the address the dsp writes the control / reads the status
//
// FBUSY and ACK are without logic
//
// 10/01/02 Rev 0
// test module for initial check out
// connect the input clock (SCLK) to the 2 outgoing clocks (DCLK0,XCLK0)
// ensure the pins that talk to the virtex during configuration are
// in the correct state
// convention signals with - are n and / is deleted
//
///

module lmcp0c   ( dummy,
                  RSTn,

                  SCLK, 
                  DCLK1,
                  DCLK0, 
                  XCLK0,
                  
                  XINITn, 
                  XBUSY, 
                  XDONE, 
                  XPWDNn, 
                  XCCLK, 
                  XCSn, 
                  XRDWRn, 
                  XPROGn, 
 
                  D,
                  A,
                  RDn,
                  WRn,
                  BRn,
 
                  CFLG0n,
                  BMSn,
                  MS0n, 
                  MS1n, 
                  MS2n, 
                  MS3n, 
                  IOMSn,
                  ACK,
 
                  FBUSYn,
                  FCSn,
                  
                  SYNC10,
                  SYNC15,
                  SYNC25,
                  SYNC33,
                
                  LOCALID,

                  IOON,
                  ON48,
                  GOOD48n,

                  SPI0S7n,

                  SCL,
                  SDA
);

output  dummy    /* synthesis xc_loc = "A3" */ ;

input   RSTn     /* synthesis xc_loc = "N9" */ ;

input   SCLK     /* synthesis xc_loc = "A7" */ ;
input   DCLK1    /* synthesis xc_loc = "J10" */ ;
output  DCLK0    /* synthesis xc_loc = "K13" */;
output  XCLK0    /* synthesis xc_loc = "G1" */ ;

inout   XINITn   /* synthesis xc_loc = "E1" */ ;
input   XBUSY    /* synthesis xc_loc = "E2" */ ;
input   XDONE    /* synthesis xc_loc = "D1" */ ;
output  XPWDNn   /* synthesis xc_loc = "B1" */ ;
output  XCCLK    /* synthesis xc_loc = "A1" */ ;
output  XCSn     /* synthesis xc_loc = "G2" */ ;
output  XRDWRn   /* synthesis xc_loc = "F2" */ ;
output  XPROGn   /* synthesis xc_loc = "F3" */ ;

inout   [15:0] D /* synthesis xc_loc = "N1,K3,M2,J3,N3,N4,M3,M4,K4,K1,M5,L1,J1,L5,H1,K5" */ ;
input   [9:0] A  /* synthesis xc_loc = "K9,M6,L10,M8,N7,K8,M10,L8,M7,N6" */ ;
input   RDn      /* synthesis xc_loc = "K2" */ ;
input   WRn      /* synthesis xc_loc = "N10" */ ;
input   BRn      /* synthesis xc_loc = "J4" */ ;

inout   CFLG0n   /* synthesis xc_loc = "M11" */ ;
input   BMSn     /* synthesis xc_loc = "N11" */ ;
input   MS0n     /* synthesis xc_loc = "M12" */ ;
input   MS1n     /* synthesis xc_loc = "K12" */ ;
input   MS2n     /* synthesis xc_loc = "J12" */ ;
input   MS3n     /* synthesis xc_loc = "H12" */ ;
input   IOMSn    /* synthesis xc_loc = "H13" */ ;
output  ACK      /* synthesis xc_loc = "G13" */ ;

input   FBUSYn   /* synthesis xc_loc = "L9" */ ;
output  FCSn     /* synthesis xc_loc = "L4" */ ;

output  SYNC10   /* synthesis xc_loc = "F12" */ ;
output  SYNC15   /* synthesis xc_loc = "F13" */ ;
output  SYNC25   /* synthesis xc_loc = "G10" */ ;
output  SYNC33   /* synthesis xc_loc = "G11" */ ;

inout   LOCALID  /* synthesis xc_loc = "D8" */ ;

output  IOON     /* synthesis xc_loc = "D9" */ ; 
output  ON48     /* synthesis xc_loc = "C10" */ ; 
output  GOOD48n  /* synthesis xc_loc = "B10" */ ; 

output  SPI0S7n  /* synthesis xc_loc = "C8" */ ; 

input   SCL      /* synthesis xc_loc = "A11" */ ; 
input   SDA      /* synthesis xc_loc = "D10" */ ; 

// address decodes
parameter [9:0]
  SPDCTL   = 10'b1000111111,    // serial presence detect prom control
  REVISION = 10'b1000001101,    // revision register
  SPICTL   = 10'b1000001111,    // spi chip select controls (all in 1)    
  IDDIR    = 10'b1000001001,    // write (direction) ctl register for ID chip
  IDSELECT = 10'b1000001000,    // select control register for ID chip
  PWR48    = 10'b1000000011,    // 48 Volt power switch
  CONTROL  = 10'b1000000010,    // control register (supervisor)
  XCFGDATA = 10'b1000000001,    // dsp writing this address makes XCCLK
  XCFGCTL  = 10'b1000000000;    // dsp writes control at this address

wire    RESET;

wire    DCLK0; 
wire    XCLK0;

wire    ACK;
wire    FCSn;

wire    [15:0] DIN; 
reg     [15:0] DOUT; 

assign RESET = ~ RSTn; // invert sense for internal use to use posedge

// repeat clocks
assign DCLK0 = SCLK;

assign XCLK0 = SCLK;

// drive ACK high is this OK
assign ACK = 1'b1;

// Flash memory located at 0x800000 (Boot sector will lie at 0x810000)
assign FCSn = MS2n & BMSn;

assign DIN = D; 

// FPGA parallel programming interface
wire    XCCLK;
reg     XPWDNn;
reg     XPROGn;
reg     XCSPn;        // was XCSn
reg     XRDWRn;
wire    XINITIn;      // incoming XINITn
reg     XINITOn;      // outgoing XINITn
reg     XINITEN;      // open collector enable for XINITn
wire    [15:0] XSTAT; // xilinx status to dsp

assign XCCLK = ( (A == XCFGDATA) && (MS1n == 1'b0) && 
                 (WRn == 1'b0) ) ? 1'b0 : 1'b1;

// write control registers
always @ (posedge WRn or posedge RESET) begin
  if (RESET) begin
    XPWDNn  <= 1'b1;
    XPROGn  <= 1'b1;
    XCSPn   <= 1'b1;
    XRDWRn  <= 1'b1;
    XINITEN <= 1'b1;
    end
  else if ( (A == XCFGCTL) && (MS1n == 1'b0) ) begin
// change bit assignments as needed
    XPWDNn  <= DIN[0];
    XPROGn  <= DIN[1];
    XCSPn   <= DIN[2];
    XRDWRn  <= DIN[3];
    XINITEN <= DIN[4];
    end
  end

assign XINITIn = XINITn;

always @ (XINITEN) begin    
  if (~XINITEN) begin       // drive when XINITEN is low
    XINITOn = 1'b0;
    end
  else begin                // tristate otherwise
    XINITOn = 1'bz;
    end
  end

assign XINITn = XINITOn;

assign XSTAT = {8'b10100101, FBUSYn, XDONE, XBUSY, 
                XINITIn, XRDWRn, XCSPn, XPROGn, XPWDNn};

// since XCSn has dual use the DSP changes the meaning by setting
// the SUP bit 
// in that case XCSn now corresponds to the decode in address space
// for the FPGA

reg     SUP;
wire    XCSUn;
wire    XCSn;
wire    [15:0] CSTAT;  // control status to dsp

always @ (posedge WRn or posedge RESET) begin
  if (RESET) begin
    SUP <= 1'b1;
    end
  else if ( (A == CONTROL) && (MS1n == 1'b0) ) begin
    SUP <= DIN[0];
    end
  end

// FPGA decodes when ever A[9] == 1 and MS1n is active
assign XCSUn = (A[9] == 1'b0) && (MS1n == 1'b0) ? 1'b0 : 1'b1;

assign XCSn = SUP ? XCSPn : XCSUn;

assign CSTAT = {15'b0, SUP};

// ID Chip switch
// there are multiple ID chips that the DSP can talk to
// and these are connected to the CPLD
// there is a local id wire that connects the CPLD to the DSP
// the DSP sets the IDSEL register which allows it to talk
// to upto 7 ID chips (currently) and then
// it is bidirectionally connected to that ID chip (or
// the corresponding one wire)

reg    [15:0] IDSEL;  // ID select switch 
reg    IDWR;          // Write ID Chip
wire   DIDIN;         // dsp end of the id (data in) 
reg    DIDOUT;        // dsp end of the id (data out) 
wire   DIDEN;         // dsp end of the id (enable)

wire   [15:0] BIDIN;  // board end of the id (data in)
reg    [15:0] BIDOUT; // board end of the id (data out) 
wire   [15:0] BIDEN;  // board end of the id (enable)

// all bits get reset but only appropriate ones for board get set
// hopefully compiler will simplify all of this
always @ (posedge WRn or posedge RESET) begin
  if (RESET) begin
    IDSEL <= 16'b0;
    end
  else if ( (A == IDSELECT) && (MS1n == 1'b0) ) begin
    IDSEL[8] <= DIN[8];
    end
  end

always @ (posedge WRn or posedge RESET) begin
  if (RESET) begin
    IDWR  <= 1'b0;
    end
  else if ( (A == IDDIR) && (MS1n == 1'b0) ) begin
    IDWR  <= DIN[0];
    end
  end

assign DIDIN = CFLG0n;
assign BIDIN[8] = LOCALID;

assign DIDEN = ( (IDSEL[15] & ~IDWR) ||
                 (IDSEL[14] & ~IDWR) ||
                 (IDSEL[13] & ~IDWR) ||
                 (IDSEL[12] & ~IDWR) ||
                 (IDSEL[11] & ~IDWR) ||
                 (IDSEL[10] & ~IDWR) ||
                 (IDSEL[9]  & ~IDWR) ||
                 (IDSEL[8]  & ~IDWR) ||
                 (IDSEL[7]  & ~IDWR) ||
                 (IDSEL[6]  & ~IDWR) ||
                 (IDSEL[5]  & ~IDWR) ||
                 (IDSEL[4]  & ~IDWR) ||
                 (IDSEL[3]  & ~IDWR) ||
                 (IDSEL[2]  & ~IDWR) ||
                 (IDSEL[1]  & ~IDWR) ||
                 (IDSEL[0]  & ~IDWR) ) ;

always @ (DIDEN or IDSEL or BIDIN) begin
  DIDOUT = DIDEN ? ( (IDSEL[15] & BIDIN[15]) ||
                     (IDSEL[14] & BIDIN[14]) ||
                     (IDSEL[13] & BIDIN[13]) ||
                     (IDSEL[12] & BIDIN[12]) ||
                     (IDSEL[11] & BIDIN[11]) ||
                     (IDSEL[10] & BIDIN[10]) ||
                     (IDSEL[9]  & BIDIN[9]) ||
                     (IDSEL[8]  & BIDIN[8]) ||
                     (IDSEL[7]  & BIDIN[7]) ||
                     (IDSEL[6]  & BIDIN[6]) ||
                     (IDSEL[5]  & BIDIN[5]) ||
                     (IDSEL[4]  & BIDIN[4]) ||
                     (IDSEL[3]  & BIDIN[3]) ||
                     (IDSEL[2]  & BIDIN[2]) ||
                     (IDSEL[1]  & BIDIN[1]) ||
                     (IDSEL[0]  & BIDIN[0]) ) : 1'bz ;
   end

// could be done as a vector ?

assign BIDEN[0]  = IDSEL[0] & IDWR;
assign BIDEN[1]  = IDSEL[1] & IDWR;
assign BIDEN[2]  = IDSEL[2] & IDWR;
assign BIDEN[3]  = IDSEL[3] & IDWR;
assign BIDEN[4]  = IDSEL[4] & IDWR;
assign BIDEN[5]  = IDSEL[5] & IDWR;
assign BIDEN[6]  = IDSEL[6] & IDWR;
assign BIDEN[7]  = IDSEL[7] & IDWR;
assign BIDEN[8]  = IDSEL[8] & IDWR;
assign BIDEN[9]  = IDSEL[9] & IDWR;
assign BIDEN[10] = IDSEL[10] & IDWR;
assign BIDEN[11] = IDSEL[11] & IDWR;
assign BIDEN[12] = IDSEL[12] & IDWR;
assign BIDEN[13] = IDSEL[13] & IDWR;
assign BIDEN[14] = IDSEL[14] & IDWR;
assign BIDEN[15] = IDSEL[15] & IDWR;

always @ (BIDEN or DIDIN) begin
  BIDOUT[0]  = BIDEN[0]  ? DIDIN : 1'bz;
  BIDOUT[1]  = BIDEN[1]  ? DIDIN : 1'bz;
  BIDOUT[2]  = BIDEN[2]  ? DIDIN : 1'bz;
  BIDOUT[3]  = BIDEN[3]  ? DIDIN : 1'bz;
  BIDOUT[4]  = BIDEN[4]  ? DIDIN : 1'bz;
  BIDOUT[5]  = BIDEN[5]  ? DIDIN : 1'bz;
  BIDOUT[6]  = BIDEN[6]  ? DIDIN : 1'bz;
  BIDOUT[7]  = BIDEN[7]  ? DIDIN : 1'bz;
  BIDOUT[8]  = BIDEN[8]  ? DIDIN : 1'bz;
  BIDOUT[9]  = BIDEN[9]  ? DIDIN : 1'bz;
  BIDOUT[10] = BIDEN[10] ? DIDIN : 1'bz;
  BIDOUT[11] = BIDEN[11] ? DIDIN : 1'bz;
  BIDOUT[12] = BIDEN[12] ? DIDIN : 1'bz;
  BIDOUT[13] = BIDEN[13] ? DIDIN : 1'bz;
  BIDOUT[14] = BIDEN[14] ? DIDIN : 1'bz;
  BIDOUT[15] = BIDEN[15] ? DIDIN : 1'bz;
  end

assign CFLG0n = DIDOUT;
assign LOCALID = BIDOUT[8];

// regualor syncs
parameter [5:0] TWOMHZ = 6'b100111;    // divide by 40 to give 2 MHz
parameter [5:0] CT01   = 6'b000001;    // count of 1
parameter [5:0] CT11   = 6'b001011;    // count of 11
parameter [5:0] CT21   = 6'b010101;    // count of 21
parameter [5:0] CT31   = 6'b011111;    // count of 31

reg     [5:0] SCT;
reg     SYNC10;
reg     SYNC15;
reg     SYNC25;
reg     SYNC33;

always @ (posedge SCLK or posedge RESET) begin
  if (RESET) begin
    SCT <= 6'b0;
    end
  else if (SCT == TWOMHZ) begin
    SCT <= 6'b0;
    end
  else begin
    SCT <= SCT + 1;
    end
  end

always @ (posedge SCLK or posedge RESET) begin
  if (RESET) begin
    SYNC10 <= 1'b0;
    end
  else if (SCT == CT01) begin          // count = 1
    SYNC10 <= 1'b1;
    end
  else if (SCT == CT21) begin          // count = 21
    SYNC10 <= 1'b0;
    end
  end

always @ (posedge SCLK or posedge RESET) begin
  if (RESET) begin
    SYNC15 <= 1'b0;
    end
  else if (SCT == CT11) begin          // count = 11
    SYNC15 <= 1'b1;
    end
  else if (SCT == CT31) begin          // count = 31
    SYNC15 <= 1'b0;
    end
  end

always @ (posedge SCLK or posedge RESET) begin
  if (RESET) begin
    SYNC25 <= 1'b0;
    end
  else if (SCT == CT21) begin          // count = 21
    SYNC25 <= 1'b1;
    end
  else if (SCT == CT01) begin          // count = 1
    SYNC25 <= 1'b0;
    end
  end

always @ (posedge SCLK or posedge RESET) begin
  if (RESET) begin
    SYNC33 <= 1'b0;
    end
  else if (SCT == CT31) begin          // count = 31
    SYNC33 <= 1'b1;
    end
  else if (SCT == CT11) begin          // count = 11
    SYNC33 <= 1'b0;
    end
  end

// SPI chip selects 
// this needs consultation with Roy 10/21/03

reg     [7:0] SPISEL;
wire    SPI0S7n;
wire    [15:0] SSTAT;

always @ (posedge WRn or posedge RESET) begin
  if (RESET) begin
    SPISEL[7] <= 1'b1;
    end
  else if ( (A == SPICTL) && (MS1n == 1'b0) ) begin
    SPISEL[7] <= DIN[7];
    end
  end

// direct CFLG0n to the appropriate chip select chosen
// and make the others inactive

assign SPI0S7n = SPISEL[7] == 1'b0 ? CFLG0n : 1'b1;

assign SSTAT = {8'b0, SPISEL}; 

// 48 Volt power switch
reg     ON48;
reg     GOOD48;
reg     IOON;
wire    GOOD48n;

always @ (posedge WRn or posedge RESET) begin
  if (RESET) begin
    ON48   <= 1'b0;
    GOOD48 <= 1'b0;
    IOON   <= 1'b0;
    end
  else if ( (A == PWR48) && (MS1n == 1'b0) ) begin
    ON48   <= DIN[0];
    GOOD48 <= DIN[1];
    IOON   <= DIN[2];
    end
  end

assign GOOD48n = ~GOOD48;

wire    [3:0] REV;

assign REV = 4'h1;

// read status registers
//always @ (RDn or A or MS1n or XSTAT or FSTAT) begin
always begin
  if ( (A == XCFGCTL) && (MS1n == 1'b0) && (RDn == 1'b0) ) begin
    DOUT = XSTAT;
    end
  else if ( (A == CONTROL) && (MS1n == 1'b0) && (RDn == 1'b0) ) begin
    DOUT = CSTAT;
    end
  else if ( (A == IDSELECT) && (MS1n == 1'b0) && (RDn == 1'b0) ) begin
    DOUT = IDSEL;
    end
  else if ( (A == IDDIR) && (MS1n == 1'b0) && (RDn == 1'b0) ) begin
    DOUT = {15'b0, IDWR};
    end
  else if ((A == SPICTL) && (MS1n == 1'b0) && (RDn == 1'b0) ) begin
    DOUT = SSTAT;
    end
  else if ( (A == PWR48) && (MS1n == 1'b0) && (RDn == 1'b0) ) begin
    DOUT = {13'b0, IOON, GOOD48, ON48};
    end
  else if ( (A == REVISION) && (MS1n == 1'b0) && (RDn == 1'b0) ) begin
    DOUT = {12'b0, REV};
    end
  else  begin
    DOUT = 16'bz;
    end
  end

assign D = DOUT;

// place holder so as not to loose the signals
// hope it does not mess the dsp up

assign dummy = DCLK1 | MS0n | MS3n | IOMSn | BRn | SCL | SDA;

endmodule
