moved clkdiv to bsv

moved clkdiv to bsv

Related git tag:
    imageon c0b942e5012a0b2ed16d9913b44149bd459a6330

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface Iserdesbvi;
    method Action           align_start(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(3)          samplein();
    method Action           autoalign(Bit#(1) v);
    method Action           training(Bit#(10) v);
    method Action           manual_tap(Bit#(10) v);
    method Action           reset(Bit#(1) v);
    method Action           dataout(Bit#(10) v);
    method Bit#(1)          itemreq();
    method Bit#(1)          ctrl_bitslip();
    method Bit#(1)          ctrl_fifo_reset();
    method Bit#(3)          ctrl_reset_inc_ce();
    method Action           dackint(Bit#(1) v);
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Reset clkdiv_reset)(Iserdesbvi);
    input_clock clkdiv () = clkdiv;
    default_clock clock(CLOCK);
    input_reset clkdiv_reset() clocked_by(clkdiv) = clkdiv_reset;
    method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
    method ALIGN_BUSY       align_busy() clocked_by (clock);
    method ALIGNED          aligned() clocked_by (clock);
    method SAMPLEIN samplein() clocked_by (clock);
    method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
    method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
    method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
    method                  reset(RESET) enable((*inhigh*) en17) clocked_by (clkdiv) reset_by(clkdiv_reset);
    method                  dataout(ISERDES_DATA) enable((*inhigh*) en18) clocked_by(clkdiv) reset_by(clkdiv_reset);
    method ITEMREQ_o        itemreq() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_BITSLIP_o   ctrl_bitslip() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_FIFO_RESET_o   ctrl_fifo_reset() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_RESET_INC_CE_o ctrl_reset_inc_ce() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method                  dackint(DACKINT) enable((*inhigh*) en19) clocked_by(clkdiv) reset_by(clkdiv_reset);
    schedule (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, reset, dataout, align_busy, aligned, samplein, align_start, autoalign, training, manual_tap)
         CF (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, reset, dataout, align_busy, aligned, samplein, align_start, autoalign, training, manual_tap);
endmodule: mkIserdesbvi

interface IserdesDatadeser;
    method Action           ibufdso(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(1)          sampleinfirstbit();
    method Bit#(1)          sampleinlastbit();
    method Bit#(1)          sampleinotherbit();
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          empty();
    method Bit#(10)         dataout();
endinterface: IserdesDatadeser

interface FIFO18;
   method Action            di(Bit#(16) v);
   method Action            rden(Bit#(1) v);
   method Action            wren(Bit#(1) v);
   method Action            reset(Bit#(1) v);
   method Bit#(16)          dataout();
   method Bit#(1)           empty();
endinterface: FIFO18

import "BVI" FIFO18 =
module mkFIFO18#(Clock clkdiv)(FIFO18);
    parameter ALMOST_FULL_OFFSET = 'h80;
    parameter ALMOST_EMPTY_OFFSET = 'h80;
    parameter DATA_WIDTH = 18;
    parameter DO_REG = 1;
    parameter EN_SYN = 0;
    parameter FIRST_WORD_FALL_THROUGH = 0;
    parameter SIM_MODE = "SAFE";

    default_clock clock(RDCLK);
    input_clock clkdiv (WRCLK) = clkdiv;
    no_reset;
    port DIP = 0;

    method          reset(RST) enable((*inhigh*) en9) clocked_by (clkdiv);
    method          di(DI) enable((*inhigh*) en0) clocked_by (clkdiv);
    method          rden(RDEN) enable((*inhigh*) en2) clocked_by (clock);
    method          wren(WREN) enable((*inhigh*) en3) clocked_by (clock);
    method DO       dataout() clocked_by(clock);
    method EMPTY    empty() clocked_by(clock);
    schedule (reset, di, rden, wren, dataout, empty) CF (reset, di, rden, wren, dataout, empty);
endmodule: mkFIFO18

typedef enum { DIdle, DValid, DLow} DState deriving (Bits,Eq);

module mkIserdesDatadeser#(Clock serdes_clock, Reset serdes_reset, Clock serdest, Bit#(1) align_start,
    Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock, serdes_reset);
    FIFO18 dfifo <- mkFIFO18(serdes_clock);
    IdelayE2 delaye2 <- mkIDELAYE2(IDELAYE2_Config {
        cinvctrl_sel: "FALSE", delay_src: "IDATAIN",
        high_performance_mode: "TRUE",
        idelay_type: "VARIABLE", idelay_value: 0,
        pipe_sel: "FALSE", refclk_frequency: 200, signal_pattern: "DATA"},
        defaultClock, clocked_by serdes_clock);
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    IserdesE2 master_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "MASTER", iobdelay: "IFD"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    IserdesE2 slave_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "SLAVE", iobdelay: "NONE"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    Wire#(Bit#(1)) bvi_delay_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_reset_reg <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_fifo_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) dcounter <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(10)) iserdes_data <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(DState)  dstate <- mkReg(DIdle, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe0 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe1 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_reset <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_reset_r <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_wren_r <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_sync <- mkSyncReg(0, serdes_clock, serdes_reset, defaultClock);
    Reg#(Bit#(1)) sync_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) sync_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dackint <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    ReadOnly#(Bit#(3)) samplein_null <- mkNullCrossingWire(serdes_clock, serbvi.samplein());

    Reg#(Bit#(1)) iserdes_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) iodelay_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    rule wrensyncr_rule if (bvi_reset_reg == 0);
        dfifo_wren_r <= 0;
        fifo_wren_sync <= 0;
        iserdes_bitslip <= 0;
        iodelay_reset_inc_ce <= 0;
        dstate <= DIdle;
        dackint <= 0;
    endrule
    rule wrensync_rule if (bvi_reset_reg != 0);
        let fwsync = 0;
        dfifo_wren_r <= bvi_fifo_wren_wire;
        if (bvi_delay_wren_wire == 1 && samplein_null[2] == 1)
            fwsync = dfifo_wren_r;
        else
            fwsync = bvi_fifo_wren_wire;
        fifo_wren_sync <= fwsync;
        iodelay_reset_inc_ce <= sync_reset_inc_ce;
    endrule
    rule wren_dfifo_rule;
        dfifo.wren(fifo_wren_sync);
    endrule

    rule clkdiv_rule if (bvi_reset_reg != 0);
        let ds = dstate;
        let dc = dcounter;
        let da = dackint;
        let sric = sync_reset_inc_ce;
        let sbs = 0;

        dc = dc - 1;
        dreqpipe0 <= serbvi.itemreq();
        dreqpipe1 <= dreqpipe0;
        dfifo_reset_r <= serbvi.ctrl_fifo_reset();
        fifo_reset <= dfifo_reset_r;
        sric[0] = 0;
        sric[1] = 0;
        iserdes_bitslip <= sync_bitslip;
        if (dstate == DIdle && dreqpipe1 == 1)
            begin
            sric = serbvi.ctrl_reset_inc_ce();
            sbs = serbvi.ctrl_bitslip();
            dc = 3'b011;
            ds = DValid;
            end
        if (dstate == DValid && dcounter[2] == 1)
            begin
            da = 1;
            ds = DLow;
            end
        if (dstate == DLow && dreqpipe1 == 0)
            begin
            da = 0;
            ds = DIdle;
            end
        dstate <= ds;
        dcounter <= dc;
        dackint <= da;
        sync_reset_inc_ce <= sric;
        sync_bitslip <= sbs;
    endrule
    rule dackint_rule;
        serbvi.dackint(dackint);
    endrule

    rule setrule;
        dfifo.reset(iodelay_reset_inc_ce[2]);
        delaye2.reset(iodelay_reset_inc_ce[2]);
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(iodelay_reset_inc_ce[1] == 1);
        delaye2.ce(iodelay_reset_inc_ce[0]);
    endrule

    rule serdesdata_rule;
        let dout = 10'b0;
        master_data.d(0);
        master_data.bitslip(iserdes_bitslip);
        master_data.ce1(1);
        master_data.ce2(1);
        master_data.ddly(delaye2.dataout());
        master_data.ofb(0);
        master_data.dynclkdivsel(0);
        master_data.dynclksel(0);
        master_data.shiftin1(0);
        master_data.shiftin2(0);
        master_data.oclk(0);
        master_data.oclkb(0);
        master_data.reset(iodelay_reset_inc_ce[2]);
        slave_data.d(0);
        slave_data.bitslip(iserdes_bitslip);
        slave_data.ce1(1);
        slave_data.ce2(1);
        slave_data.ddly(0);
        slave_data.ofb(0);
        slave_data.dynclkdivsel(0);
        slave_data.dynclksel(0);
        slave_data.shiftin1(master_data.shiftout1());
        slave_data.shiftin2(master_data.shiftout2());
        dout = {slave_data.q4(), slave_data.q3(), master_data.q8(),
           master_data.q7(), master_data.q6(), master_data.q5(),
           master_data.q4(), master_data.q3(), master_data.q2(), master_data.q1()};
        slave_data.oclk(0);
        slave_data.oclkb(0);
        slave_data.reset(iodelay_reset_inc_ce[2]);
        iserdes_data <= dout;
        serbvi.dataout(iserdes_data);
        dfifo.di({6'b0,dout});
    endrule

    rule serdesrule;
        serbvi.align_start(align_start);
        serbvi.autoalign(autoalign);
        serbvi.training(training);
        serbvi.manual_tap(manual_tap);
        dfifo.rden(rden);
    endrule

    method Action ibufdso(Bit#(1) v);
        delaye2.idatain(v);
    endmethod
    method Bit#(1)                align_busy();
        return serbvi.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serbvi.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return serbvi.samplein()[2];
    endmethod
    method Bit#(1)                sampleinlastbit();
        return serbvi.samplein()[1];
    endmethod
    method Bit#(1)                sampleinotherbit();
        return serbvi.samplein()[0];
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        bvi_delay_wren_wire <= v;
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        bvi_fifo_wren_wire <= v;
    endmethod
    method Action                 reset(Bit#(1) v);
        bvi_reset_reg <= v;
        serbvi.reset(v);
    endmethod
    method Bit#(1)                empty();
        return dfifo.empty();
    endmethod
    method Bit#(10)               dataout();
        return dfifo.dataout()[9:0];
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdes_reset, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufdso(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    endinterface
endmodule

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import Vector::*;
import Clocks :: *;
import XilinxCells::*;
import XbsvXilinxCells::*;

interface Iserdesbvi;
    method Action           align_start(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(3)          samplein();
    method Bit#(3)          iodelay_reset_inc_ce();
    method Bit#(1)          bitslip();
    method Action           autoalign(Bit#(1) v);
    method Action           training(Bit#(10) v);
    method Action           manual_tap(Bit#(10) v);
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          fifo_wren_sync();
    method Action           dataout(Bit#(10) v);
    method Bit#(1)          itemreq();
    method Bit#(1)          ctrl_bitslip();
    method Bit#(1)          ctrl_fifo_reset();
    method Bit#(3)          ctrl_reset_inc_ce();
    method Action           dackint(Bit#(1) v);
endinterface: Iserdesbvi

import "BVI" iserdes_datadeser =
module mkIserdesbvi#(Clock clkdiv, Reset clkdiv_reset)(Iserdesbvi);
    input_clock clkdiv (CLKDIV) = clkdiv;
    default_clock clock(CLOCK);
    input_reset clkdiv_reset() clocked_by(clkdiv) = clkdiv_reset;
    method                  align_start(ALIGN_START) enable((*inhigh*) en1) clocked_by (clock);
    method ALIGN_BUSY       align_busy() clocked_by (clock);
    method ALIGNED          aligned() clocked_by (clock);
    method ISERDES_BITSLIP  bitslip() clocked_by (clkdiv) reset_by(clkdiv_reset);
    method SAMPLEIN samplein() clocked_by (clock);
    method IODELAY_RESET_INC_CE iodelay_reset_inc_ce() clocked_by (clkdiv) reset_by(clkdiv_reset);
    method                  autoalign(AUTOALIGN) enable((*inhigh*) en7) clocked_by (clock);
    method                  training(TRAINING) enable((*inhigh*) en8) clocked_by (clock);
    method                  manual_tap(MANUAL_TAP) enable((*inhigh*) en9) clocked_by (clock);
    method                  fifo_wren(FIFO_WREN) enable((*inhigh*) en10) clocked_by (clkdiv) reset_by(clkdiv_reset);
    method FIFO_WREN_SYNC   fifo_wren_sync() clocked_by (clock);
    method                  delay_wren(DELAY_WREN) enable((*inhigh*) en11) clocked_by (clkdiv) reset_by(clkdiv_reset);
    method                  reset(RESET) enable((*inhigh*) en17) clocked_by (clkdiv) reset_by(clkdiv_reset);
    method                  dataout(ISERDES_DATA) enable((*inhigh*) en18) clocked_by(clkdiv) reset_by(clkdiv_reset);
    method ITEMREQ_o        itemreq() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_BITSLIP_o   ctrl_bitslip() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_FIFO_RESET_o   ctrl_fifo_reset() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method CTRL_RESET_INC_CE_o ctrl_reset_inc_ce() clocked_by(clkdiv) reset_by(clkdiv_reset);
    method                  dackint(DACKINT) enable((*inhigh*) en19) clocked_by(clkdiv) reset_by(clkdiv_reset);
    schedule (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip)
         CF (dackint, ctrl_reset_inc_ce, itemreq, ctrl_bitslip, ctrl_fifo_reset, fifo_wren, reset, delay_wren, dataout, iodelay_reset_inc_ce, bitslip, align_busy, aligned, samplein, fifo_wren_sync, align_start, autoalign, training, manual_tap, bitslip);
endmodule: mkIserdesbvi

interface IserdesDatadeser;
    method Action           ibufdso(Bit#(1) v);
    method Bit#(1)          align_busy();
    method Bit#(1)          aligned();
    method Bit#(1)          sampleinfirstbit();
    method Bit#(1)          sampleinlastbit();
    method Bit#(1)          sampleinotherbit();
    method Action           delay_wren(Bit#(1) v);
    method Action           fifo_wren(Bit#(1) v);
    method Action           reset(Bit#(1) v);
    method Bit#(1)          empty();
    method Bit#(10)         dataout();
endinterface: IserdesDatadeser

interface FIFO18;
   method Action            di(Bit#(16) v);
   method Action            rden(Bit#(1) v);
   method Action            wren(Bit#(1) v);
   method Action            reset(Bit#(1) v);
   method Bit#(16)          dataout();
   method Bit#(1)           empty();
endinterface: FIFO18

import "BVI" FIFO18 =
module mkFIFO18#(Clock clkdiv)(FIFO18);
    parameter ALMOST_FULL_OFFSET = 'h80;
    parameter ALMOST_EMPTY_OFFSET = 'h80;
    parameter DATA_WIDTH = 18;
    parameter DO_REG = 1;
    parameter EN_SYN = 0;
    parameter FIRST_WORD_FALL_THROUGH = 0;
    parameter SIM_MODE = "SAFE";

    default_clock clock(RDCLK);
    input_clock clkdiv (WRCLK) = clkdiv;
    no_reset;
    port DIP = 0;

    method          reset(RST) enable((*inhigh*) en9) clocked_by (clkdiv);
    method          di(DI) enable((*inhigh*) en0) clocked_by (clkdiv);
    method          rden(RDEN) enable((*inhigh*) en2) clocked_by (clock);
    method          wren(WREN) enable((*inhigh*) en3) clocked_by (clock);
    method DO       dataout() clocked_by(clock);
    method EMPTY    empty() clocked_by(clock);
    schedule (reset, di, rden, wren, dataout, empty) CF (reset, di, rden, wren, dataout, empty);
endmodule: mkFIFO18

typedef enum { DIdle, DValid, DLow} DState deriving (Bits,Eq);

module mkIserdesDatadeser#(Clock serdes_clock, Reset serdes_reset, Clock serdest, Bit#(1) align_start,
    Bit#(1) autoalign, Bit#(10) training, Bit#(10) manual_tap, Bit#(1) rden)(IserdesDatadeser);

    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();
    Iserdesbvi serbvi <- mkIserdesbvi(serdes_clock, serdes_reset);
    FIFO18 dfifo <- mkFIFO18(serdes_clock);
    IdelayE2 delaye2 <- mkIDELAYE2(IDELAYE2_Config {
        cinvctrl_sel: "FALSE", delay_src: "IDATAIN",
        high_performance_mode: "TRUE",
        idelay_type: "VARIABLE", idelay_value: 0,
        pipe_sel: "FALSE", refclk_frequency: 200, signal_pattern: "DATA"},
        defaultClock, clocked_by serdes_clock);
    ClockDividerIfc serdest_inverted <- mkClockInverter(clocked_by serdest);
    IserdesE2 master_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "MASTER", iobdelay: "IFD"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    IserdesE2 slave_data <- mkISERDESE2( ISERDESE2_Config{
        data_rate: "DDR", data_width: 10,
        dyn_clk_inv_en: "FALSE", dyn_clkdiv_inv_en: "FALSE",
        interface_type: "NETWORKING", num_ce: 2, ofb_used: "FALSE",
        init_q1: 0, init_q2: 0, init_q3: 0, init_q4: 0,
        srval_q1: 0, srval_q2: 0, srval_q3: 0, srval_q4: 0,
        serdes_mode: "SLAVE", iobdelay: "NONE"},
        serdest, serdest_inverted.slowClock, clocked_by serdes_clock);
    Wire#(Bit#(1)) bvi_delay_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_reset_reg <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) bvi_fifo_wren_wire <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) dcounter <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(10)) iserdes_data <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(DState)  dstate <- mkReg(DIdle, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe0 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dreqpipe1 <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_reset <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_reset_r <- mkReg(1, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) dfifo_wren_r <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_sync <- mkSyncReg(0, serdes_clock, serdes_reset, defaultClock);
    Reg#(Bit#(1)) sync_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(3)) sync_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    //outputs
    Reg#(Bit#(1)) dackint <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    ReadOnly#(Bit#(3)) samplein_null <- mkNullCrossingWire(serdes_clock, serbvi.samplein());

    //Reg#(Bit#(1)) iserdes_bitslip <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    //Reg#(Bit#(3)) iodelay_reset_inc_ce <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(1)) iserdes_bitslip <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);
    Wire#(Bit#(3)) iodelay_reset_inc_ce <- mkDWire(0, clocked_by serdes_clock, reset_by serdes_reset);

    rule wrensyncr_rule if (bvi_reset_reg == 0);
        dfifo_wren_r <= 0;
        fifo_wren_sync <= 0;
    endrule
    rule wrensync_rule if (bvi_reset_reg != 0);
        let fwsync = 0;
        dfifo_wren_r <= bvi_fifo_wren_wire;
        if (bvi_delay_wren_wire == 1 && samplein_null[2] == 1)
            fwsync = dfifo_wren_r;
        else
            fwsync = bvi_fifo_wren_wire;
        fifo_wren_sync <= fwsync;
    endrule

    rule clkdiv_rule if (bvi_reset_reg != 0);
        let ds = dstate;
        let dc = dcounter;
        let da = dackint;
        let sric = sync_reset_inc_ce;
        let sbs = 0;

        dc = dc - 1;
        dreqpipe0 <= serbvi.itemreq();
        dreqpipe1 <= dreqpipe0;
        dfifo_reset_r <= serbvi.ctrl_fifo_reset();
        fifo_reset <= dfifo_reset_r;
        sric[0] = 0;
        sric[1] = 0;
        //iodelay_reset_inc_ce <= sync_reset_inc_ce;
        //iserdes_bitslip <= sync_bitslip;
        iodelay_reset_inc_ce <= serbvi.iodelay_reset_inc_ce();
        iserdes_bitslip <= serbvi.bitslip();
        if (dstate == DIdle && dreqpipe1 == 1)
            begin
            sric = serbvi.ctrl_reset_inc_ce();
            sbs = serbvi.ctrl_bitslip();
            dc = 3'b011;
            ds = DValid;
            end
        if (dstate == DValid && dcounter[2] == 1)
            begin
            da = 1;
            ds = DLow;
            end
        if (dstate == DLow && dreqpipe1 == 0)
            begin
            da = 0;
            ds = DIdle;
            end
        dstate <= ds;
        dcounter <= dc;
        dackint <= da;
        sync_reset_inc_ce <= sric;
        sync_bitslip <= sbs;
    endrule
    rule dackint_rule;
        serbvi.dackint(dackint);
    endrule

    rule setrule;
        dfifo.reset(iodelay_reset_inc_ce[2]);
        delaye2.reset(iodelay_reset_inc_ce[2]);
        delaye2.cinvctrl(0);
        delaye2.cntvaluein(0);
        delaye2.ld(0);
        delaye2.ldpipeen(0);
        delaye2.datain(0);
        delaye2.inc(iodelay_reset_inc_ce[1] == 1);
        delaye2.ce(iodelay_reset_inc_ce[0]);
    endrule

    rule serdesdata_rule;
        let dout = 10'b0;
        master_data.d(0);
        master_data.bitslip(iserdes_bitslip);
        master_data.ce1(1);
        master_data.ce2(1);
        master_data.ddly(delaye2.dataout());
        master_data.ofb(0);
        master_data.dynclkdivsel(0);
        master_data.dynclksel(0);
        master_data.shiftin1(0);
        master_data.shiftin2(0);
        master_data.oclk(0);
        master_data.oclkb(0);
        master_data.reset(iodelay_reset_inc_ce[2]);
        slave_data.d(0);
        slave_data.bitslip(iserdes_bitslip);
        slave_data.ce1(1);
        slave_data.ce2(1);
        slave_data.ddly(0);
        slave_data.ofb(0);
        slave_data.dynclkdivsel(0);
        slave_data.dynclksel(0);
        slave_data.shiftin1(master_data.shiftout1());
        slave_data.shiftin2(master_data.shiftout2());
        dout = {slave_data.q4(), slave_data.q3(), master_data.q8(),
           master_data.q7(), master_data.q6(), master_data.q5(),
           master_data.q4(), master_data.q3(), master_data.q2(), master_data.q1()};
        slave_data.oclk(0);
        slave_data.oclkb(0);
        slave_data.reset(iodelay_reset_inc_ce[2]);
        iserdes_data <= dout;
        serbvi.dataout(iserdes_data);
        dfifo.di({6'b0,dout});
    endrule

    rule wren_dfifo_rule;
        dfifo.wren(fifo_wren_sync);
    endrule

    rule serdesrule;
        serbvi.align_start(align_start);
        serbvi.autoalign(autoalign);
        serbvi.training(training);
        serbvi.manual_tap(manual_tap);
        dfifo.rden(rden);
    endrule

    method Action ibufdso(Bit#(1) v);
        delaye2.idatain(v);
    endmethod
    method Bit#(1)                align_busy();
        return serbvi.align_busy();
    endmethod
    method Bit#(1)                aligned();
        return serbvi.aligned();
    endmethod
    method Bit#(1)                sampleinfirstbit();
        return serbvi.samplein()[2];
    endmethod
    method Bit#(1)                sampleinlastbit();
        return serbvi.samplein()[1];
    endmethod
    method Bit#(1)                sampleinotherbit();
        return serbvi.samplein()[0];
    endmethod
    method Action                 delay_wren(Bit#(1) v);
        bvi_delay_wren_wire <= v;
        serbvi.delay_wren(v);
    endmethod
    method Action                 fifo_wren(Bit#(1) v);
        bvi_fifo_wren_wire <= v;
        serbvi.fifo_wren(v);
    endmethod
    method Action                 reset(Bit#(1) v);
        bvi_reset_reg <= v;
        serbvi.reset(v);
    endmethod
    method Bit#(1)                empty();
        return dfifo.empty();
    endmethod
    method Bit#(10)               dataout();
        return dfifo.dataout()[9:0];
    endmethod
endmodule: mkIserdesDatadeser

(* always_enabled *)
interface ImageonSerdesPins;
    method Action io_vita_sync_p(Bit#(1) v);
    method Action io_vita_sync_n(Bit#(1) v);
    method Action io_vita_data_p(Bit#(4) v);
    method Action io_vita_data_n(Bit#(4) v);
    method Action io_vita_clk_p(Bit#(1) v);
    method Action io_vita_clk_n(Bit#(1) v);
endinterface

interface ImageonSerdesControl;
    method Action set_decoder_control(Bit#(32) v);
    method Action set_iserdes_control(Bit#(32) v);
    method Action set_serdes_manual_tap(Bit#(10) v);
    method Action set_serdes_training(Bit#(10) v);
    method Bit#(32) get_iserdes_control();
endinterface

interface SerdesData;
    method Wire#(Bit#(1)) reset();
    method Bit#(1) raw_empty();
    method Bit#(50) raw_data();
endinterface

interface ISerdes;
    interface ImageonSerdesControl control;
    interface ImageonSerdesPins pins;
    interface SerdesData data;
endinterface

module mkISerdes#(Clock axi_clock, Reset axi_reset)(ISerdes);
    Clock defaultClock <- exposeCurrentClock();
    Reset defaultReset <- exposeCurrentReset();

    Wire#(Bit#(1)) vita_clk_p <- mkDWire(0);
    Wire#(Bit#(1)) vita_clk_n <- mkDWire(0);
    Clock ibufds_clk <- mkClockIBUFDS(vita_clk_p, vita_clk_n);
    ClockGenIfc serdes_clk <- mkBUFR5(ibufds_clk);
    Clock serdes_clock = serdes_clk.gen_clk;
    Reset serdes_reset <- mkAsyncReset(2, defaultReset, serdes_clock);

    Vector#(5, Wire#(Bit#(1))) vita_data_p <- replicateM(mkDWire(0));
    Vector#(5, Wire#(Bit#(1))) vita_data_n <- replicateM(mkDWire(0));
    Reg#(Bit#(1)) decoder_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_auto_align_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_align_start_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_fifo_enable_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_fifo_enable_null <- mkNullCrossingWire(serdes_clock, serdes_fifo_enable_reg);
    Reg#(Bit#(10)) serdes_manual_tap_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(10)) serdes_training_reg <- mkSyncReg(0, axi_clock, axi_reset, defaultClock);
    Reg#(Bit#(1)) serdes_reset_reg <- mkSyncReg(1, axi_clock, axi_reset, defaultClock);
    ReadOnly#(Bit#(1)) serdes_reset_null <- mkNullCrossingWire(serdes_clock, serdes_reset_reg);

    Wire#(Bit#(50)) raw_data_wire <- mkDWire(0);

    Wire#(Bit#(1)) empty_wire <- mkDWire(0);
    Wire#(Bit#(1)) bittest_wire <- mkDWire(0);
    Reg#(Bit#(1)) delay_wren_r_reg <-mkReg(0);
    Reg#(Bit#(1)) delay_wren_r2_reg <- mkSyncReg(0, defaultClock, defaultReset, serdes_clock);
    Reg#(Bit#(1)) delay_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_r2_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);
    Reg#(Bit#(1)) fifo_wren_c_reg <- mkReg(0, clocked_by serdes_clock, reset_by serdes_reset);

    ClockGenIfc serdest_clk <- mkBUFIO(ibufds_clk);
    Vector#(5, ReadOnly#(Bit#(1))) ibufds_v;
    for (Integer i = 0; i < 5; i = i + 1)
        ibufds_v[i] <- mkIBUFDS(vita_data_p[i], vita_data_n[i]);
    Reg#(Bit#(1)) serdes_align_busy_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_align_busy_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Reg#(Bit#(1)) serdes_aligned_temp <- mkReg(0);
    Reg#(Bit#(1)) serdes_aligned_reg <- mkSyncReg(0, defaultClock, defaultReset, axi_clock);
    Wire#(Bit#(1)) new_raw_empty_wire <- mkDWire(0);
    Vector#(5, IserdesDatadeser) serdes_v <- replicateM(mkIserdesDatadeser(serdes_clock, serdes_reset, serdest_clk.gen_clk,
	  serdes_align_start_reg, serdes_auto_align_reg, serdes_training_reg,
	  serdes_manual_tap_reg, decoder_enable_reg));

    rule serdes_copybits;
        serdes_aligned_reg <= serdes_aligned_temp;
        serdes_align_busy_reg <= serdes_align_busy_temp;
    endrule

    rule sendup_imageon_clock;
       Bit#(5) alignbusyw = 0;
       Bit#(5) alignedw = 0;
       Bit#(5) firstw = 0;
       Bit#(5) lastw = 0;
       Bit#(5) otherw = 0;
       Bit#(5) emptyw = 0;
       Bit#(50) rawdataw = 0;
       for (Bit#(8) i = 0; i < 5; i = i+1) begin
	  serdes_v[i].ibufdso(ibufds_v[i]);
	  alignbusyw[i] = serdes_v[i].align_busy();
	  alignedw[i] = serdes_v[i].aligned();
	  firstw[i] = serdes_v[i].sampleinfirstbit();
	  lastw[i] = serdes_v[i].sampleinlastbit();
	  otherw[i] = serdes_v[i].sampleinotherbit();
	  emptyw[i] = serdes_v[i].empty();
	  rawdataw[(i+1)*10-1: i*10] = serdes_v[i].dataout();
       end
       serdes_align_busy_temp <= pack(alignbusyw != 0);
       serdes_aligned_temp <= pack(alignedw == 5'b11111);
       bittest_wire <= pack(otherw == 0 && firstw != 0 && lastw != 0);
       empty_wire <= pack(emptyw != 0);
       raw_data_wire <= rawdataw;
    endrule

    rule sendup_sdes_clock;
    for (Bit#(8) i = 0; i < 5; i = i+1) begin
       serdes_v[i].reset(serdes_reset_null);
       serdes_v[i].delay_wren(delay_wren_c_reg);
       serdes_v[i].fifo_wren(serdes_fifo_enable_null);
    end
    endrule

    rule serdes_reset_rule if (serdes_reset_reg == 0);
        new_raw_empty_wire <= 0;
        delay_wren_r_reg <= 0;
        delay_wren_r2_reg <= 0;
    endrule

    rule serdes_resetc_rule if (serdes_reset_null == 0);
        delay_wren_c_reg <= 0;
        fifo_wren_r2_reg <= 0;
        fifo_wren_c_reg <= 0;
    endrule

    rule serdes_calc2 if (serdes_reset_reg == 1);
        new_raw_empty_wire <= empty_wire;
        delay_wren_r_reg <= bittest_wire;
        delay_wren_r2_reg <= delay_wren_r_reg;
    endrule

    rule serdes_calc2c if (serdes_reset_null == 1);
        delay_wren_c_reg <= delay_wren_r2_reg;
        fifo_wren_r2_reg <= serdes_fifo_enable_null;
        fifo_wren_c_reg <= fifo_wren_r2_reg;
    endrule

    interface ImageonSerdesControl control;
	method Action set_serdes_manual_tap(Bit#(10) v);
	    serdes_manual_tap_reg <= v;
	endmethod
	method Action set_serdes_training(Bit#(10) v);
	    serdes_training_reg <= v;
	endmethod
	method Action set_iserdes_control(Bit#(32) v);
	    serdes_reset_reg <= ~v[0];
	    serdes_auto_align_reg <= v[1];
	    serdes_align_start_reg <= v[2];
	    serdes_fifo_enable_reg <= v[3];
	endmethod
	method Bit#(32) get_iserdes_control();
	    let v = 0;
	    v[8] = 1;
	    v[9] = serdes_align_busy_reg;
	    v[10] = serdes_aligned_reg;
	    return v;
	endmethod
	method Action set_decoder_control(Bit#(32) v);
	    decoder_enable_reg <= v[1];
	endmethod
    endinterface

    interface ImageonSerdesPins pins;
        method Action io_vita_sync_p(Bit#(1) v);
            vita_data_p[0] <= v;
        endmethod
        method Action io_vita_sync_n(Bit#(1) v);
            vita_data_n[0] <= v;
        endmethod
        method Action io_vita_data_p(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_p[i+1] <= v[i];
        endmethod
        method Action io_vita_data_n(Bit#(4) v);
            for (Integer i = 0; i < 4; i = i + 1)
                vita_data_n[i+1] <= v[i];
        endmethod
        method Action io_vita_clk_p(Bit#(1) v);
            vita_clk_p <= v;
        endmethod
        method Action io_vita_clk_n(Bit#(1) v);
            vita_clk_n <= v;
        endmethod
    endinterface
    interface SerdesData data;
        method Wire#(Bit#(1)) reset();
            return serdes_reset_reg;
        endmethod
        method Bit#(1) raw_empty();
            return new_raw_empty_wire;
        endmethod
        method Bit#(50) raw_data();
            return raw_data_wire;
	endmethod
    endinterface
endmodule


oops forgot to extend

oops forgot to extend

import FIFOF::*;
import FIFO::*;
import FIFOLevel::*;
import BRAMFIFO::*;
import BRAM::*;
import GetPut::*;
import ClientServer::*;
import Arbiter::*;
import Vector::*;
import List::*;

import MemTypes::*;
import ControllerTypes::*;

interface PageBuffers;
	interface PhysMemSlave#(FlashAddrWidth, 128) memSlave; //to user hw
	interface Get#(FlashCmd) flashReq;
	interface Put#(Tuple2#(Bit#(WordSz), TagT)) readResp;
endinterface

typedef TLog#(PageWords) PageOffsetSz;

typedef enum {
	ST_INIT,
	ST_CMD,
	ST_HIT,
	ST_MISS,
	ST_MISS_READDATA
} BufOpState deriving (Bits, Eq);

typedef struct {
	Bool valid;
	FlashAddr faddr;
} PageBufferEntry deriving (Bits, Eq);

typedef struct {
	FlashAddr faddr;
	Bit#(PageOffsetSz) offset;
} PageAddrOff deriving (Bits, Eq);

function PageAddrOff decodePhysMemAddr(Bit#(FlashAddrWidth) addr);
	//byte addressible
	Tuple2#(PageAddrOff, Bit#(TLog#(WordBytes))) decodedAddr = unpack(truncate(addr));
	return tpl_1(decodedAddr);
	//PageAddrOff decodedAddr = unpack(truncate(addr)); //FIXME FIXME FIXME
	//return decodedAddr;
endfunction

function TagT splitTagsByBus(Integer id, Bit#(32) cnt);
	Bit#(32) group = fromInteger(id * (valueOf(NumTags)/valueOf(NUM_BUSES)));
	return truncate(group + cnt);
endfunction

function BusT tag2bus(TagT tag);
	return truncate( tag>>(log2(num_tags/num_buses)) );
endfunction

//TODO: for now assumes that the request does not cross page boundaries
(* synthesize *)
module mkPageBuffers(PageBuffers);

	//Page Buffers
	Vector#(NUM_BUSES, PageBuffers) pageBuffers = newVector();
	for (Integer bus=0; bus<valueOf(NUM_BUSES); bus=bus+1) begin
		pageBuffers[bus] <- mkSinglePageBuffer(bus);
	end

	//Arbiter
	Arbiter_IFC#(NUM_BUSES) arb <- mkStickyArbiter();

	FIFO#(Tuple2#(Bit#(WordSz), TagT)) flashReadAggrQ <- mkFIFO();
	FIFO#(FlashCmd) flashCmdAggrQ <- mkFIFO();
	FIFO#(MemData#(128)) slaveRespAggrQ <- mkFIFO;

	rule distrFlashRead;
		flashReadAggrQ.deq;
		let tdata = flashReadAggrQ.first;
		let tag = tpl_2(tdata);
		let bus = tag2bus(tag);
		pageBuffers[bus].readResp.put(tdata);
	endrule

	//Handle flash cmd and data
	for (Integer bus=0; bus<valueOf(NUM_BUSES); bus=bus+1) begin
		rule funnelFlashCmd;
			let cmd <- pageBuffers[bus].flashReq.get();
			flashCmdAggrQ.enq(cmd);
			$display("PageBufferTop: flashCmdAggrQ enq");
		endrule

		//Handle mem slave read data arbitration
		FIFOF#(MemData#(128)) slaveRespBufs <- mkFIFOF;
		rule getBuffSlaveData;
			let rd <- pageBuffers[bus].memSlave.read_server.readData.get();
			slaveRespBufs.enq(rd);
		endrule

		Reg#(Bool) granted <- mkReg(False);
		rule arbReq if (slaveRespBufs.notEmpty && !granted);
			arb.clients[bus].request();
			if (arb.clients[bus].grant) begin
				granted <= True;
			end
		endrule

		rule holdGrant if (granted);
			arb.clients[bus].request();
		endrule

		rule send if (granted);
			slaveRespBufs.deq;
			slaveRespAggrQ.enq(slaveRespBufs.first);
			if (slaveRespBufs.first.last) begin
				granted <= False;
			end
		endrule

	end //for buses

	interface PhysMemSlave memSlave;
		interface PhysMemReadServer read_server;
			interface Put readReq;
				method Action put(PhysMemRequest#(FlashAddrWidth) req);
					//distribute each request to each buffer by bus
					PageAddrOff decAddr = decodePhysMemAddr(req.addr);
					pageBuffers[decAddr.faddr.bus].memSlave.read_server.readReq.put(req);
				endmethod
			endinterface
			interface Get readData = toGet(slaveRespAggrQ);
		endinterface
		interface PhysMemWriteServer write_server = ?;
	endinterface

	interface Get flashReq = toGet(flashCmdAggrQ);
	interface Put readResp = toPut(flashReadAggrQ);
endmodule

module mkSinglePageBuffer#(Integer busId)(PageBuffers);

	//BRAM
	BRAM2Port#(Bit#(PageOffsetSz), Bit#(WordSz)) pageBuffer <- mkBRAM2Server(defaultValue);
	Reg#(PageBufferEntry) pageBufEntry <- mkReg(unpack(0));
	FIFO#(Tuple2#(Bit#(WordSz), TagT)) flashReadQ <- mkFIFO();
	FIFO#(FlashCmd) flashCmdQ <- mkFIFO();
	Reg#(Bit#(BurstLenSize)) reqRemain <- mkReg(0);
	Reg#(Bit#(BurstLenSize)) respRemain <- mkReg(0);
	Reg#(Bit#(PageOffsetSz)) writePtr <- mkReg(0);

	FIFO#(MemData#(128)) slaveRespQ <- mkFIFO;
	FIFO#(TagT) freeTagQ <- mkSizedFIFO(num_tags);
	FIFO#(PhysMemRequest#(FlashAddrWidth)) slaveReqQ <- mkSizedFIFO(valueOf(NumTags)/valueOf(NUM_BUSES));
	Reg#(BufOpState) state <- mkReg(ST_INIT);

	//split tags among these buffers
	Reg#(Bit#(32)) tagCnt <- mkReg(0); //initialize to the id of this buffer
	rule init (state==ST_INIT);
		let tag = splitTagsByBus(busId, tagCnt);
		freeTagQ.enq(tag);
		$display("FreeTag enq: %d", tag);
		if (tagCnt == fromInteger(num_tags/num_buses-1)) begin
			state <= ST_CMD;
			tagCnt <= 0;
		end
		else begin
			tagCnt <= tagCnt + 1;
		end
	endrule

	//decode address
	let currReq = slaveReqQ.first;
	PageAddrOff addrOff = decodePhysMemAddr(currReq.addr);
	rule handleSlaveReq (state==ST_CMD);
		$display("PageBuffers: Received slave command: addr=%x, len=%d, tag=%d", currReq.addr,
			currReq.burstLen, currReq.tag);
		//slaveReqQ.deq; //FIXME: debug
		//look up in cache
		let bus = addrOff.faddr.bus;
		if (pageBufEntry.valid && pageBufEntry.faddr==addrOff.faddr) begin
			//if hit, make request to BRAM
			$display("PageBuffers: hit");
			state <= ST_HIT;
			reqRemain <= currReq.burstLen>>fromInteger(valueOf(WordBytesLog));
			respRemain <= currReq.burstLen>>fromInteger(valueOf(WordBytesLog));
		end
		else begin
			//if miss, make request to flash controller
			$display("PageBuffers: miss");
			state <= ST_MISS;
			pageBufEntry.valid <= False;
		end

	endrule

	rule handleHit (state==ST_HIT && reqRemain>0);
		Bit#(32) burstOffset = zeroExtend((currReq.burstLen>>fromInteger(valueOf(WordBytesLog))) - reqRemain);
		if (burstOffset >= fromInteger(pageWords)) begin
			$display("PageBuffer: **ERROR burstOffset exceeds number of pageWords");
		end
		Bit#(PageOffsetSz) baddr = addrOff.offset + truncate(burstOffset); //safe truncation
		$display("PageBuffer: portB read req addrOff=%x, burstOffset=%x, baddr= %x", addrOff.offset, burstOffset, baddr);
		pageBuffer.portB.request.put(
			BRAMRequest{
				write: False,
				responseOnWrite: ?,
				address: baddr,
				datain: ?}
		);
		reqRemain <= reqRemain - 1;
	endrule

	rule handleHitData (state==ST_HIT);
		let data <- pageBuffer.portB.response.get();
		Bool last = (respRemain==1);
		slaveRespQ.enq( MemData { data: data, tag: currReq.tag, last: last} );
		$display("PageBuffer: hit data=%x, tag=%d, last=%d", data, currReq.tag, last);
		if (respRemain==1) begin
			state <= ST_CMD;
			slaveReqQ.deq;
		end
		else begin
			respRemain <= respRemain - 1;
		end
	endrule

	rule missFlashRequest (state==ST_MISS);
		//get free tag
		freeTagQ.deq;
		let ftag = freeTagQ.first;
		FlashCmd fcmd = FlashCmd {
			tag: ftag,
			op: READ_PAGE,
			bus: addrOff.faddr.bus,
			chip: addrOff.faddr.chip,
			block: addrOff.faddr.block,
			page: addrOff.faddr.page
		};
		flashCmdQ.enq(fcmd);
		$display("PageBuffers: missFlashRequest issued for: ftag=%d, bus=%d, chip=%d, blk=%d, page=%d",
					ftag, addrOff.faddr.bus, addrOff.faddr.chip, addrOff.faddr.block, addrOff.faddr.page);
		state <= ST_MISS_READDATA;
	endrule

	rule missGetFlashRead (state==ST_MISS_READDATA);
		//TODO: only one buffer, so no reordering per bus
		flashReadQ.deq;
		let data = tpl_1(flashReadQ.first);
		let tag = tpl_2(flashReadQ.first);
		$display("PageBuffers: got read data from flash: tag=%d, data=%x", tag, data);
		pageBuffer.portA.request.put(
				BRAMRequest{ write:True,
							responseOnWrite:False,
							address:writePtr ,
							datain: data }
						);
		if (writePtr==fromInteger(pageWords-1)) begin
			//update metadata about what's in the buffer
			pageBufEntry <= PageBufferEntry { valid: True, faddr: addrOff.faddr};
			freeTagQ.enq(tag);
			state <= ST_CMD; //reattempt command
			writePtr <= 0;
		end
		else begin
			writePtr <= writePtr + 1;
		end
	endrule

	interface PhysMemSlave memSlave;
		interface PhysMemReadServer read_server;
			interface Put readReq = toPut(slaveReqQ);
			interface Get readData = toGet(slaveRespQ);
		endinterface
		interface PhysMemWriteServer write_server = ?;
	endinterface

	interface Get flashReq = toGet(flashCmdQ);
	interface Put readResp = toPut(flashReadQ);

endmodule

import FIFOF::*;
import FIFO::*;
import FIFOLevel::*;
import BRAMFIFO::*;
import BRAM::*;
import GetPut::*;
import ClientServer::*;
import Arbiter::*;
import Vector::*;
import List::*;

import MemTypes::*;
import ControllerTypes::*;

interface PageBuffers;
	interface PhysMemSlave#(FlashAddrWidth, 128) memSlave; //to user hw
	interface Get#(FlashCmd) flashReq;
	interface Put#(Tuple2#(Bit#(WordSz), TagT)) readResp;
endinterface

typedef TLog#(PageWords) PageOffsetSz;

typedef enum {
	ST_INIT,
	ST_CMD,
	ST_HIT,
	ST_MISS,
	ST_MISS_READDATA
} BufOpState deriving (Bits, Eq);

typedef struct {
	Bool valid;
	FlashAddr faddr;
} PageBufferEntry deriving (Bits, Eq);

typedef struct {
	FlashAddr faddr;
	Bit#(PageOffsetSz) offset;
} PageAddrOff deriving (Bits, Eq);

function PageAddrOff decodePhysMemAddr(Bit#(FlashAddrWidth) addr);
	//byte addressible
	Tuple2#(PageAddrOff, Bit#(TLog#(WordBytes))) decodedAddr = unpack(truncate(addr));
	return tpl_1(decodedAddr);
	//PageAddrOff decodedAddr = unpack(truncate(addr)); //FIXME FIXME FIXME
	//return decodedAddr;
endfunction

function TagT splitTagsByBus(Integer id, Bit#(32) cnt);
	Bit#(32) group = fromInteger(id * (valueOf(NumTags)/valueOf(NUM_BUSES)));
	return truncate(group + cnt);
endfunction

function BusT tag2bus(TagT tag);
	return truncate( tag>>(log2(num_tags/num_buses)) );
endfunction

//TODO: for now assumes that the request does not cross page boundaries
(* synthesize *)
module mkPageBuffers(PageBuffers);

	//Page Buffers
	Vector#(NUM_BUSES, PageBuffers) pageBuffers = newVector();
	for (Integer bus=0; bus<valueOf(NUM_BUSES); bus=bus+1) begin
		pageBuffers[bus] <- mkSinglePageBuffer(bus);
	end

	//Arbiter
	Arbiter_IFC#(NUM_BUSES) arb <- mkStickyArbiter();

	FIFO#(Tuple2#(Bit#(WordSz), TagT)) flashReadAggrQ <- mkFIFO();
	FIFO#(FlashCmd) flashCmdAggrQ <- mkFIFO();
	FIFO#(MemData#(128)) slaveRespAggrQ <- mkFIFO;

	rule distrFlashRead;
		flashReadAggrQ.deq;
		let tdata = flashReadAggrQ.first;
		let tag = tpl_2(tdata);
		let bus = tag2bus(tag);
		pageBuffers[bus].readResp.put(tdata);
	endrule

	//Handle flash cmd and data
	for (Integer bus=0; bus<valueOf(NUM_BUSES); bus=bus+1) begin
		rule funnelFlashCmd;
			let cmd <- pageBuffers[bus].flashReq.get();
			flashCmdAggrQ.enq(cmd);
			$display("PageBufferTop: flashCmdAggrQ enq");
		endrule

		//Handle mem slave read data arbitration
		FIFOF#(MemData#(128)) slaveRespBufs <- mkFIFOF;
		rule getBuffSlaveData;
			let rd <- pageBuffers[bus].memSlave.read_server.readData.get();
			slaveRespBufs.enq(rd);
		endrule

		Reg#(Bool) granted <- mkReg(False);
		rule arbReq if (slaveRespBufs.notEmpty && !granted);
			arb.clients[bus].request();
			if (arb.clients[bus].grant) begin
				granted <= True;
			end
		endrule

		rule holdGrant if (granted);
			arb.clients[bus].request();
		endrule

		rule send if (granted);
			slaveRespBufs.deq;
			slaveRespAggrQ.enq(slaveRespBufs.first);
			if (slaveRespBufs.first.last) begin
				granted <= False;
			end
		endrule

	end //for buses

	interface PhysMemSlave memSlave;
		interface PhysMemReadServer read_server;
			interface Put readReq;
				method Action put(PhysMemRequest#(FlashAddrWidth) req);
					//distribute each request to each buffer by bus
					PageAddrOff decAddr = decodePhysMemAddr(req.addr);
					pageBuffers[decAddr.faddr.bus].memSlave.read_server.readReq.put(req);
				endmethod
			endinterface
			interface Get readData = toGet(slaveRespAggrQ);
		endinterface
		interface PhysMemWriteServer write_server = ?;
	endinterface

	interface Get flashReq = toGet(flashCmdAggrQ);
	interface Put readResp = toPut(flashReadAggrQ);
endmodule

module mkSinglePageBuffer#(Integer busId)(PageBuffers);

	//BRAM
	BRAM2Port#(Bit#(PageOffsetSz), Bit#(WordSz)) pageBuffer <- mkBRAM2Server(defaultValue);
	Reg#(PageBufferEntry) pageBufEntry <- mkReg(unpack(0));
	FIFO#(Tuple2#(Bit#(WordSz), TagT)) flashReadQ <- mkFIFO();
	FIFO#(FlashCmd) flashCmdQ <- mkFIFO();
	Reg#(Bit#(BurstLenSize)) reqRemain <- mkReg(0);
	Reg#(Bit#(BurstLenSize)) respRemain <- mkReg(0);
	Reg#(Bit#(PageOffsetSz)) writePtr <- mkReg(0);

	FIFO#(MemData#(128)) slaveRespQ <- mkFIFO;
	FIFO#(TagT) freeTagQ <- mkSizedFIFO(num_tags);
	FIFO#(PhysMemRequest#(FlashAddrWidth)) slaveReqQ <- mkSizedFIFO(valueOf(NumTags)/valueOf(NUM_BUSES));
	Reg#(BufOpState) state <- mkReg(ST_INIT);

	//split tags among these buffers
	Reg#(Bit#(32)) tagCnt <- mkReg(0); //initialize to the id of this buffer
	rule init (state==ST_INIT);
		let tag = splitTagsByBus(busId, tagCnt);
		freeTagQ.enq(tag);
		$display("FreeTag enq: %d", tag);
		if (tagCnt == fromInteger(num_tags/num_buses-1)) begin
			state <= ST_CMD;
			tagCnt <= 0;
		end
		else begin
			tagCnt <= tagCnt + 1;
		end
	endrule

	//decode address
	let currReq = slaveReqQ.first;
	PageAddrOff addrOff = decodePhysMemAddr(currReq.addr);
	rule handleSlaveReq (state==ST_CMD);
		$display("PageBuffers: Received slave command: addr=%x, len=%d, tag=%d", currReq.addr,
			currReq.burstLen, currReq.tag);
		//slaveReqQ.deq; //FIXME: debug
		//look up in cache
		let bus = addrOff.faddr.bus;
		if (pageBufEntry.valid && pageBufEntry.faddr==addrOff.faddr) begin
			//if hit, make request to BRAM
			$display("PageBuffers: hit");
			state <= ST_HIT;
			reqRemain <= currReq.burstLen>>fromInteger(valueOf(WordBytesLog));
			respRemain <= currReq.burstLen>>fromInteger(valueOf(WordBytesLog));
		end
		else begin
			//if miss, make request to flash controller
			$display("PageBuffers: miss");
			state <= ST_MISS;
			pageBufEntry.valid <= False;
		end

	endrule

	rule handleHit (state==ST_HIT && reqRemain>0);
		Bit#(32) burstOffset = (currReq.burstLen>>fromInteger(valueOf(WordBytesLog))) - reqRemain;
		if (burstOffset >= fromInteger(pageWords)) begin
			$display("PageBuffer: **ERROR burstOffset exceeds number of pageWords");
		end
		Bit#(PageOffsetSz) baddr = addrOff.offset + truncate(burstOffset); //safe truncation
		$display("PageBuffer: portB read req addrOff=%x, burstOffset=%x, baddr= %x", addrOff.offset, burstOffset, baddr);
		pageBuffer.portB.request.put(
			BRAMRequest{
				write: False,
				responseOnWrite: ?,
				address: baddr,
				datain: ?}
		);
		reqRemain <= reqRemain - 1;
	endrule

	rule handleHitData (state==ST_HIT);
		let data <- pageBuffer.portB.response.get();
		Bool last = (respRemain==1);
		slaveRespQ.enq( MemData { data: data, tag: currReq.tag, last: last} );
		$display("PageBuffer: hit data=%x, tag=%d, last=%d", data, currReq.tag, last);
		if (respRemain==1) begin
			state <= ST_CMD;
			slaveReqQ.deq;
		end
		else begin
			respRemain <= respRemain - 1;
		end
	endrule

	rule missFlashRequest (state==ST_MISS);
		//get free tag
		freeTagQ.deq;
		let ftag = freeTagQ.first;
		FlashCmd fcmd = FlashCmd {
			tag: ftag,
			op: READ_PAGE,
			bus: addrOff.faddr.bus,
			chip: addrOff.faddr.chip,
			block: addrOff.faddr.block,
			page: addrOff.faddr.page
		};
		flashCmdQ.enq(fcmd);
		$display("PageBuffers: missFlashRequest issued for: ftag=%d, bus=%d, chip=%d, blk=%d, page=%d",
					ftag, addrOff.faddr.bus, addrOff.faddr.chip, addrOff.faddr.block, addrOff.faddr.page);
		state <= ST_MISS_READDATA;
	endrule

	rule missGetFlashRead (state==ST_MISS_READDATA);
		//TODO: only one buffer, so no reordering per bus
		flashReadQ.deq;
		let data = tpl_1(flashReadQ.first);
		let tag = tpl_2(flashReadQ.first);
		$display("PageBuffers: got read data from flash: tag=%d, data=%x", tag, data);
		pageBuffer.portA.request.put(
				BRAMRequest{ write:True,
							responseOnWrite:False,
							address:writePtr ,
							datain: data }
						);
		if (writePtr==fromInteger(pageWords-1)) begin
			//update metadata about what's in the buffer
			pageBufEntry <= PageBufferEntry { valid: True, faddr: addrOff.faddr};
			freeTagQ.enq(tag);
			state <= ST_CMD; //reattempt command
			writePtr <= 0;
		end
		else begin
			writePtr <= writePtr + 1;
		end
	endrule

	interface PhysMemSlave memSlave;
		interface PhysMemReadServer read_server;
			interface Put readReq = toPut(slaveReqQ);
			interface Get readData = toGet(slaveRespQ);
		endinterface
		interface PhysMemWriteServer write_server = ?;
	endinterface

	interface Get flashReq = toGet(flashCmdQ);
	interface Put readResp = toPut(flashReadQ);

endmodule


formatting

formatting

// Copyright (c) 2013 Quanta Research Cambridge, Inc.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFOF::*;
import GetPutF::*;
import RingTypes::*;

module mkNopEngine ( ServerF#(Bit#(64), Bit#(64)));
   FIFOF#(Bit#(64)) f_nop <- mkSizedFIFOF(2);

   rule discard;
      let x = f_nop.deq();
      $display("Nop %h\n", x);
   endrule

   interface PutF request = toPutF(f_nop);
   interface GetF response = ?;

endmodule: mkNopEngine


PortalTop -> PortalDmaTop

PortalTop -> PortalDmaTop

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;

// portz libraries
import AxiMasterSlave::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import PortalMemory::*;
import AxiRDMA::*;
import BsimRDMA::*;
import PortalMemory::*;
import PortalRMemory::*;

// for PCIE
import Connectable::*;
import Xilinx            :: *;
import XilinxPCIE        :: *;
import Xilinx7PcieBridge :: *;
import PcieToAxiBridge   :: *;

// generated by tool
import MemreadRequestWrapper::*;
import DMARequestWrapper::*;
import MemreadIndicationProxy::*;
import DMAIndicationProxy::*;

// defined by user
import Memread::*;

module mkPortalDmaTop(PortalDmaTop);

   DMAIndicationProxy dmaIndicationProxy <- mkDMAIndicationProxy(9);

   MemreadIndicationProxy memreadIndicationProxy <- mkMemreadIndicationProxy(7);
   Memread memread <- mkMemread(memreadIndicationProxy.ifc);
   MemreadRequestWrapper memreadRequestWrapper <- mkMemreadRequestWrapper(1008,memread.request);

   Vector#(1, DMAReadClient#(64)) clients = cons(memread.dmaClient, nil);
`ifdef BSIM
   BsimDMAServer#(64)  dma <- mkBsimDMAServer(dmaIndicationProxy.ifc, clients, nil);
`else
   Integer             numRequests = 2;
   AxiDMAServer#(64,8) dma <- mkAxiDMAServer(dmaIndicationProxy.ifc, numRequests, clients, nil);
`endif

   DMARequestWrapper dmaRequestWrapper <- mkDMARequestWrapper(1005,dma.request);

   Vector#(4,StdPortal) portals;
   portals[0] = memreadRequestWrapper.portalIfc;
   portals[1] = memreadIndicationProxy.portalIfc;
   portals[2] = dmaRequestWrapper.portalIfc;
   portals[3] = dmaIndicationProxy.portalIfc;

   Directory dir <- mkDirectory(portals);
   Vector#(1,StdPortal) directories;
   directories[0] = dir.portalIfc;

   // when constructing ctrl and interrupt muxes, directories must be the first argument
   let ctrl_mux <- mkAxiSlaveMux(directories,portals);
   let interrupt_mux <- mkInterruptMux(portals);
`ifndef BSIM
   let axi_master <- mkAxi3Master(dma.m_axi);
`endif

   interface ReadOnly interrupt = interrupt_mux;
   interface StdAxi3Slave ctrl = ctrl_mux;
`ifndef BSIM
   interface StdAxi3Master m_axi = axi_master;
`endif
endmodule : mkPortalDmaTop

module mkZynqTop(PortalDmaTop);
   let portalTop <- mkPortalDmaTop();
   return portalTop;
endmodule : mkZynqTop

import "BDPI" function Action      initPortal(Bit#(32) d);
import "BDPI" function Bool                    writeReq();
import "BDPI" function ActionValue#(Bit#(32)) writeAddr();
import "BDPI" function ActionValue#(Bit#(32)) writeData();
import "BDPI" function Bool                     readReq();
import "BDPI" function ActionValue#(Bit#(32))  readAddr();
import "BDPI" function Action        readData(Bit#(32) d);

module mkBsimTop();
   PortalDmaTop top <- mkPortalDmaTop;
   let wf <- mkPipelineFIFO;
   let init_seq = (action
		      initPortal(0);
		      initPortal(1);
		      initPortal(2);
		      initPortal(3);
		      initPortal(4);
                   endaction);
   let init_fsm <- mkOnce(init_seq);
   rule init_rule;
      init_fsm.start;
   endrule
   rule wrReq (writeReq());
      let wa <- writeAddr;
      let wd <- writeData;
      top.ctrl.write.writeAddr(wa,0,0,0,0,0,0);
      wf.enq(wd);
   endrule
   rule wrData;
      wf.deq;
      top.ctrl.write.writeData(wf.first,0,0,0);
   endrule
   rule rdReq (readReq());
      let ra <- readAddr;
      top.ctrl.read.readAddr(ra,0,0,0,0,0,0);
   endrule
   rule rdResp;
      let rd <- top.ctrl.read.readData;
      readData(rd);
   endrule
endmodule

(* no_default_clock, no_default_reset *)
module mkPcieTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
                          Clock sys_clk_p,     Clock sys_clk_n,
                          Reset pci_sys_reset_n)
                         (VC707_FPGA);

   let contentId = 64'h4563686f;

   X7PcieBridgeIfc#(8) x7pcie <- mkX7PcieBridge( pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,
                                                 contentId );

   Reg#(Bool) interruptRequested <- mkReg(False, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // instantiate user portals
   let portalTop <- mkPortalDmaTop(clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // connect them to PCIE
   mkConnection(x7pcie.portal0, portalTop.ctrl, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   AxiSlaveEngine#(64,8) axiSlaveEngine <- mkAxiSlaveEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(x7pcie.slave), tpl_2(axiSlaveEngine.tlps), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(axiSlaveEngine.tlps), tpl_2(x7pcie.slave), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(portalTop.m_axi, axiSlaveEngine.slave3, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   rule requestInterrupt;
      if (portalTop.interrupt && !interruptRequested)
	 x7pcie.interrupt();
      interruptRequested <= portalTop.interrupt;
   endrule

   interface pcie = x7pcie.pcie;
   //interface ddr3 = x7pcie.ddr3;
   method leds = zeroExtend({  pack(x7pcie.isCalibrated)
			     , pack(True)
			     , pack(False)
			     , pack(x7pcie.isLinkUp)
			     });

endmodule: mkPcieTop

// bsv libraries
import SpecialFIFOs::*;
import Vector::*;
import StmtFSM::*;
import FIFO::*;

// portz libraries
import AxiMasterSlave::*;
import Directory::*;
import CtrlMux::*;
import Portal::*;
import Leds::*;
import PortalMemory::*;
import AxiRDMA::*;
import BsimRDMA::*;
import PortalMemory::*;
import PortalRMemory::*;

// for PCIE
import Connectable::*;
import Xilinx            :: *;
import XilinxPCIE        :: *;
import Xilinx7PcieBridge :: *;
import PcieToAxiBridge   :: *;

// generated by tool
import MemreadRequestWrapper::*;
import DMARequestWrapper::*;
import MemreadIndicationProxy::*;
import DMAIndicationProxy::*;

// defined by user
import Memread::*;

interface AxiTop;
   interface StdAxi3Slave     ctrl;
   interface StdAxi3Master    m_axi;
   interface ReadOnly#(Bool)  interrupt;
   interface LEDS             leds;
endinterface

module mkAxiTop(AxiTop);

   DMAIndicationProxy dmaIndicationProxy <- mkDMAIndicationProxy(9);

   MemreadIndicationProxy memreadIndicationProxy <- mkMemreadIndicationProxy(7);
   Memread memread <- mkMemread(memreadIndicationProxy.ifc);
   MemreadRequestWrapper memreadRequestWrapper <- mkMemreadRequestWrapper(1008,memread.request);

   Vector#(1, DMAReadClient#(64)) clients = cons(memread.dmaClient, nil);
`ifdef BSIM
   BsimDMAServer#(64)  dma <- mkBsimDMAServer(dmaIndicationProxy.ifc, clients, nil);
`else
   Integer             numRequests = 2;
   AxiDMAServer#(64,8) dma <- mkAxiDMAServer(dmaIndicationProxy.ifc, numRequests, clients, nil);
`endif

   DMARequestWrapper dmaRequestWrapper <- mkDMARequestWrapper(1005,dma.request);

   Vector#(4,StdPortal) portals;
   portals[0] = memreadRequestWrapper.portalIfc;
   portals[1] = memreadIndicationProxy.portalIfc;
   portals[2] = dmaRequestWrapper.portalIfc;
   portals[3] = dmaIndicationProxy.portalIfc;

   Directory dir <- mkDirectory(portals);
   Vector#(1,StdPortal) directories;
   directories[0] = dir.portalIfc;

   // when constructing ctrl and interrupt muxes, directories must be the first argument
   let ctrl_mux <- mkAxiSlaveMux(directories,portals);
   let interrupt_mux <- mkInterruptMux(portals);
`ifndef BSIM
   let axi_master <- mkAxi3Master(dma.m_axi);
`endif

   interface ReadOnly interrupt = interrupt_mux;
   interface StdAxi3Slave ctrl = ctrl_mux;
`ifndef BSIM
   interface StdAxi3Master m_axi = axi_master;
`endif
endmodule : mkAxiTop

module mkZynqTop(AxiTop);
   let axiTop <- mkAxiTop();
   return axiTop;
endmodule : mkZynqTop

import "BDPI" function Action      initPortal(Bit#(32) d);
import "BDPI" function Bool                    writeReq();
import "BDPI" function ActionValue#(Bit#(32)) writeAddr();
import "BDPI" function ActionValue#(Bit#(32)) writeData();
import "BDPI" function Bool                     readReq();
import "BDPI" function ActionValue#(Bit#(32))  readAddr();
import "BDPI" function Action        readData(Bit#(32) d);

module mkBsimTop();
   AxiTop top <- mkAxiTop;
   let wf <- mkPipelineFIFO;
   let init_seq = (action
		      initPortal(0);
		      initPortal(1);
		      initPortal(2);
		      initPortal(3);
		      initPortal(4);
                   endaction);
   let init_fsm <- mkOnce(init_seq);
   rule init_rule;
      init_fsm.start;
   endrule
   rule wrReq (writeReq());
      let wa <- writeAddr;
      let wd <- writeData;
      top.ctrl.write.writeAddr(wa,0,0,0,0,0,0);
      wf.enq(wd);
   endrule
   rule wrData;
      wf.deq;
      top.ctrl.write.writeData(wf.first,0,0,0);
   endrule
   rule rdReq (readReq());
      let ra <- readAddr;
      top.ctrl.read.readAddr(ra,0,0,0,0,0,0);
   endrule
   rule rdResp;
      let rd <- top.ctrl.read.readData;
      readData(rd);
   endrule
endmodule

(* no_default_clock, no_default_reset *)
module mkPcieTop #(Clock pci_sys_clk_p, Clock pci_sys_clk_n,
                          Clock sys_clk_p,     Clock sys_clk_n,
                          Reset pci_sys_reset_n)
                         (VC707_FPGA);

   let contentId = 64'h4563686f;

   X7PcieBridgeIfc#(8) x7pcie <- mkX7PcieBridge( pci_sys_clk_p, pci_sys_clk_n, sys_clk_p, sys_clk_n, pci_sys_reset_n,
                                                 contentId );

   Reg#(Bool) interruptRequested <- mkReg(False, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // instantiate user portals
   let axiTop <- mkAxiTop(clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   // connect them to PCIE
   mkConnection(x7pcie.portal0, axiTop.ctrl, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   AxiSlaveEngine#(64,8) axiSlaveEngine <- mkAxiSlaveEngine(x7pcie.pciId(), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(x7pcie.slave), tpl_2(axiSlaveEngine.tlps), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(tpl_1(axiSlaveEngine.tlps), tpl_2(x7pcie.slave), clocked_by x7pcie.clock125, reset_by x7pcie.reset125);
   mkConnection(axiTop.m_axi, axiSlaveEngine.slave3, clocked_by x7pcie.clock125, reset_by x7pcie.reset125);

   rule requestInterrupt;
      if (axiTop.interrupt && !interruptRequested)
	 x7pcie.interrupt();
      interruptRequested <= axiTop.interrupt;
   endrule

   interface pcie = x7pcie.pcie;
   //interface ddr3 = x7pcie.ddr3;
   method leds = zeroExtend({  pack(x7pcie.isCalibrated)
			     , pack(True)
			     , pack(False)
			     , pack(x7pcie.isLinkUp)
			     });

endmodule: mkPcieTop


fixed simulation clock cycle

fixed simulation clock cycle

// Copyright (c) 2016 Cornell University.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import Clocks::*;

interface SimClocks;
   interface Clock clock_50;
   interface Reset reset_50_n;
   interface Clock clock_156_25;
   interface Reset reset_156_25_n;
   interface Clock clock_644_53;
endinterface

// assume timescale
module mkSimClocks(SimClocks);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   Clock clock50mhz <- mkAbsoluteClock(0, 20);
   Clock clock644mhz <- mkAbsoluteClock(0, 2);
   Clock clock156mhz <- mkAbsoluteClock(0, 6);

   Reset reset50n <- mkSyncReset(2, defaultReset, clock50mhz);
   Reset reset156n <- mkSyncReset(2, defaultReset, clock156mhz);

   interface clock_50 = clock50mhz;
   interface clock_156_25 = clock156mhz;
   interface clock_644_53 = clock644mhz;
   interface reset_50_n = reset50n;
   interface reset_156_25_n = reset156n;
endmodule

// Copyright (c) 2016 Cornell University.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import Clocks::*;

interface SimClocks;
   interface Clock clock_50;
   interface Reset reset_50_n;
   interface Clock clock_156_25;
   interface Reset reset_156_25_n;
   interface Clock clock_644_53;
endinterface

// assume timescale
module mkSimClocks(SimClocks);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   Clock clock50mhz <- mkAbsoluteClock(0, 20);
   Clock clock644mhz <- mkAbsoluteClock(0, 1);
   Clock clock156mhz <- mkAbsoluteClock(0, 6);

   Reset reset50n <- mkSyncReset(2, defaultReset, clock50mhz);
   Reset reset156n <- mkSyncReset(2, defaultReset, clock156mhz);

   interface clock_50 = clock50mhz;
   interface clock_156_25 = clock156mhz;
   interface clock_644_53 = clock644mhz;
   interface reset_50_n = reset50n;
   interface reset_156_25_n = reset156n;
endmodule


print name in matchtable sim

print name in matchtable sim

// Copyright (c) 2016 Cornell University.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFO::*;
import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import StmtFSM::*;
import Vector::*;
import DefaultValue::*;
import BRAM::*;
import FShow::*;
import Pipe::*;
import StringUtils::*;
import List::*;
import Bcam::*;
import BcamTypes::*;

interface MatchTable#(numeric type id, numeric type depth, numeric type keySz, numeric type actionSz);
   interface Server#(Bit#(keySz), Maybe#(Bit#(actionSz))) lookupPort;
   interface Put#(Tuple2#(Bit#(keySz), Bit#(actionSz))) add_entry;
   interface Put#(Bit#(TLog#(depth))) delete_entry;
   interface Put#(Tuple2#(Bit#(TLog#(depth)), Bit#(actionSz))) modify_entry;
endinterface

typeclass MatchTableSim#(numeric type id, numeric type ksz, numeric type vsz);
   function ActionValue#(Bit#(vsz)) matchtable_read(Bit#(id) v, Bit#(ksz) key);
   function Action matchtable_write(Bit#(id) v, Bit#(ksz) key, Bit#(vsz) data);
endtypeclass

module mkMatchTable#(String name)(MatchTable#(id, depth, keySz, actionSz))
   provisos(Mul#(c__, 256, d__),
            Add#(c__, 7, TLog#(depth)),
            Log#(d__, TLog#(depth)),
            Mul#(e__, 9, keySz),
            Add#(TAdd#(TLog#(c__), 4), 2, TLog#(TDiv#(depth, 4))),
            Log#(TDiv#(depth, 16), TAdd#(TLog#(c__), 4)),
            Add#(9, f__, keySz),
            PriorityEncoder::PEncoder#(d__),
            Add#(2, g__, TLog#(depth)),
            Add#(4, h__, TLog#(depth)),
`ifdef SIMULATION
            MatchTableSim#(id, keySz, actionSz),
`endif
            Add#(TAdd#(TLog#(c__), 4), i__, TLog#(depth)));

   MatchTable#(id, depth, keySz, actionSz) ret_ifc;
`ifdef SIMULATION
   ret_ifc <- mkMatchTableBluesim(name);
`else
   ret_ifc <- mkMatchTableSynth();
`endif
   return ret_ifc;
endmodule

module mkMatchTableSynth(MatchTable#(id, depth, keySz, actionSz))
   provisos (NumAlias#(depthSz, TLog#(depth)),
             Mul#(a__, 256, b__),
             Add#(a__, 7, depthSz),
             Log#(b__, depthSz),
             Mul#(c__, 9, keySz),
             Add#(TAdd#(TLog#(a__), 4), 2, TLog#(TDiv#(depth, 4))),
             Log#(TDiv#(depth, 16), TAdd#(TLog#(a__), 4)),
             Add#(9, d__, keySz),
             PriorityEncoder::PEncoder#(b__),
             Add#(2, e__, TLog#(depth)),
             Add#(4, f__, TLog#(depth)),
             Add#(TAdd#(TLog#(a__), 4), g__, TLog#(depth))
            );
   let verbose = True;
   Reg#(Bit#(32)) cycle <- mkReg(0);

   rule every1 (verbose);
      cycle <= cycle + 1;
   endrule

   BinaryCam#(depth, keySz) bcam <- mkBinaryCam();
   FIFO#(Bool) bcamMatchFifo <- mkFIFO();

   BRAM_Configure cfg = defaultValue;
   cfg.latency = 2;
   BRAM2Port#(Bit#(depthSz), Bit#(actionSz)) ram <- mkBRAM2Server(cfg);

   Reg#(Bit#(depthSz)) addrIdx <- mkReg(0);

   rule handle_bcam_response;
      let v <- bcam.readServer.response.get;
      if (verbose) $display("(%0d) matchTable recv bcam response ", $time, fshow(v));
      if (isValid(v)) begin // if match
         let address = fromMaybe(?, v);
         ram.portA.request.put(BRAMRequest{write:False, responseOnWrite: False, address: address, datain:?});
         bcamMatchFifo.enq(True);
      end
      else begin // if miss
         ram.portA.request.put(BRAMRequest{write:False, responseOnWrite: False, address: 0, datain: ?});
         bcamMatchFifo.enq(False);
      end
   endrule

   // Interface for lookup from data-plane modules
   interface Server lookupPort;
      interface Put request;
         method Action put (Bit#(keySz) v);
            BcamReadReq#(Bit#(keySz)) req_bcam = BcamReadReq{data: v};
            bcam.readServer.request.put(pack(req_bcam));
            //if (verbose) $display("matchTable %d: lookup ", cycle, fshow(req_bcam));
         endmethod
      endinterface
      interface Get response;
         method ActionValue#(Maybe#(Bit#(actionSz))) get();
            let m <- toGet(bcamMatchFifo).get;
            let act <- ram.portA.response.get;
            if (verbose) $display("(%0d) matchTable: recv ram response ", $time, fshow(act));
            case (m) matches
               True: return tagged Valid act;
               False: return tagged Invalid;
            endcase
         endmethod
      endinterface
   endinterface

   // Interface for write from control-plane
   interface Put add_entry;
      method Action put (Tuple2#(Bit#(keySz), Bit#(actionSz)) v);
         BcamWriteReq#(Bit#(depthSz), Bit#(keySz)) req_bcam = BcamWriteReq{addr: addrIdx, data: pack(tpl_1(v))};
         BRAMRequest#(Bit#(depthSz), Bit#(actionSz)) req_ram = BRAMRequest{write: True, responseOnWrite: False, address: addrIdx, datain: pack(tpl_2(v))};
         bcam.writeServer.put(req_bcam);
         ram.portA.request.put(req_ram);
         $display("(%0d) match_table: add flow %x %x %x", $time, addrIdx, tpl_1(v), tpl_2(v));
         addrIdx <= addrIdx + 1; //FIXME: currently no reuse of address.
      endmethod
   endinterface
   interface Put delete_entry;
      method Action put (Bit#(depthSz) id);
         BcamWriteReq#(Bit#(depthSz), Bit#(keySz)) req_bcam = BcamWriteReq{addr: id, data: 0};
         BRAMRequest#(Bit#(depthSz), Bit#(actionSz)) req_ram = BRAMRequest{write: True, responseOnWrite: False, address: id, datain: 0};
         bcam.writeServer.put(req_bcam);
         ram.portA.request.put(req_ram);
         $display("(%0d) match_table: delete flow %x", $time, id);
      endmethod
   endinterface
   interface Put modify_entry;
      method Action put (Tuple2#(Bit#(depthSz), Bit#(actionSz)) v);
         match { .flowid, .act} = v;
         BRAMRequest#(Bit#(depthSz), Bit#(actionSz)) req_ram = BRAMRequest{write: True, responseOnWrite: False, address: flowid, datain: pack(act)};
         ram.portA.request.put(req_ram);
      endmethod
   endinterface
endmodule

module mkMatchTableBluesim#(String name)(MatchTable#(id, depth, keySz, actionSz))
   provisos (MatchTable::MatchTableSim#(id, keySz, actionSz),
             Log#(depth, depthSz));
   let verbose = True;

   Integer idv = valueOf(id);
   Integer dpv = valueOf(depth);
   FIFO#(Tuple2#(Bit#(keySz), Bit#(actionSz))) writeReqFifo <- mkFIFO;
   FIFO#(Bit#(keySz)) readReqFifo <- mkFIFO;
   FIFO#(Maybe#(Bit#(actionSz))) readDataFifo <- mkFIFO;

   Reg#(Bool)      isInitialized   <- mkReg(False);

   Handle fp <- openFile(name, ReadMode);
   List#(Tuple2#(Bit#(keySz), Bit#(actionSz))) entryList = tagged Nil;
   let readable <- hIsReadable(fp);
   if (readable) begin
      Bool isEOF <- hIsEOF(fp);
      while (!isEOF) begin
         let line <- hGetLine(fp);
         List#(String) parsedEntries = parseCSV(line);
         while (parsedEntries != tagged Nil) begin
            Bit#(keySz) key = fromInteger(hexStringToInteger(parsedEntries[0]));
            Bit#(actionSz) v = fromInteger(hexStringToInteger(parsedEntries[1]));
            Bit#(id) tid = 0;
            parsedEntries = List::drop(2, parsedEntries);
            entryList = List::cons(tuple2(key, v), entryList);
         end
         isEOF <- hIsEOF(fp);
      end
   end
   hClose(fp);

   rule do_read (isInitialized);
      let v <- toGet(readReqFifo).get;
      $display("(%0d) MatchTable %s: do_read %h", $time, name, v);
      Bit#(id) tid = 0;
      let ret <- matchtable_read(tid, pack(v));
      $display("(%0d) MatchTable %s: read %h", $time, name, ret);
      if (ret != 0)
         readDataFifo.enq(tagged Valid ret);
      else
         readDataFifo.enq(tagged Invalid);
   endrule

   Reg#(Bit#(8)) fsmIndex <- mkReg(0);

   rule do_init (fsmIndex < fromInteger(List::length(entryList)));
      $display("insert entry ", fromInteger(List::length(entryList)));
      Bit#(keySz) key = tpl_1(entryList[fsmIndex]);
      Bit#(actionSz) v = tpl_2(entryList[fsmIndex]);
      Bit#(id) tid = 0;
      matchtable_write(tid, key, v);
      fsmIndex <= fsmIndex + 1;
      $display("finished insert entry ", fromInteger(List::length(entryList)));
   endrule

   rule finish_init(fsmIndex == fromInteger(List::length(entryList)));
      isInitialized <= True;
   endrule

   interface Server lookupPort;
      interface Put request = toPut(readReqFifo);
      interface Get response = toGet(readDataFifo);
   endinterface
   interface Put add_entry;
      method Action put (Tuple2#(Bit#(keySz), Bit#(actionSz)) v);
         $display("(%0d) MatchTable: insert %h %h", $time, tpl_1(v), tpl_2(v));
         Bit#(id) tid = 0;
         matchtable_write(tid, tpl_1(v), tpl_2(v));
      endmethod
   endinterface
   interface Put delete_entry;
      method Action put (Bit#(depthSz) id);

      endmethod
   endinterface
   interface Put modify_entry;
      method Action put (Tuple2#(Bit#(depthSz), Bit#(actionSz)) v);

      endmethod
   endinterface
endmodule

// Copyright (c) 2016 Cornell University.

// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use, copy,
// modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import FIFO::*;
import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import StmtFSM::*;
import Vector::*;
import DefaultValue::*;
import BRAM::*;
import FShow::*;
import Pipe::*;
import StringUtils::*;
import List::*;
import Bcam::*;
import BcamTypes::*;

interface MatchTable#(numeric type id, numeric type depth, numeric type keySz, numeric type actionSz);
   interface Server#(Bit#(keySz), Maybe#(Bit#(actionSz))) lookupPort;
   interface Put#(Tuple2#(Bit#(keySz), Bit#(actionSz))) add_entry;
   interface Put#(Bit#(TLog#(depth))) delete_entry;
   interface Put#(Tuple2#(Bit#(TLog#(depth)), Bit#(actionSz))) modify_entry;
endinterface

typeclass MatchTableSim#(numeric type id, numeric type ksz, numeric type vsz);
   function ActionValue#(Bit#(vsz)) matchtable_read(Bit#(id) v, Bit#(ksz) key);
   function Action matchtable_write(Bit#(id) v, Bit#(ksz) key, Bit#(vsz) data);
endtypeclass

module mkMatchTable#(String name)(MatchTable#(id, depth, keySz, actionSz))
   provisos(Mul#(c__, 256, d__),
            Add#(c__, 7, TLog#(depth)),
            Log#(d__, TLog#(depth)),
            Mul#(e__, 9, keySz),
            Add#(TAdd#(TLog#(c__), 4), 2, TLog#(TDiv#(depth, 4))),
            Log#(TDiv#(depth, 16), TAdd#(TLog#(c__), 4)),
            Add#(9, f__, keySz),
            PriorityEncoder::PEncoder#(d__),
            Add#(2, g__, TLog#(depth)),
            Add#(4, h__, TLog#(depth)),
`ifdef SIMULATION
            MatchTableSim#(id, keySz, actionSz),
`endif
            Add#(TAdd#(TLog#(c__), 4), i__, TLog#(depth)));

   MatchTable#(id, depth, keySz, actionSz) ret_ifc;
`ifdef SIMULATION
   ret_ifc <- mkMatchTableBluesim(name);
`else
   ret_ifc <- mkMatchTableSynth();
`endif
   return ret_ifc;
endmodule

module mkMatchTableSynth(MatchTable#(id, depth, keySz, actionSz))
   provisos (NumAlias#(depthSz, TLog#(depth)),
             Mul#(a__, 256, b__),
             Add#(a__, 7, depthSz),
             Log#(b__, depthSz),
             Mul#(c__, 9, keySz),
             Add#(TAdd#(TLog#(a__), 4), 2, TLog#(TDiv#(depth, 4))),
             Log#(TDiv#(depth, 16), TAdd#(TLog#(a__), 4)),
             Add#(9, d__, keySz),
             PriorityEncoder::PEncoder#(b__),
             Add#(2, e__, TLog#(depth)),
             Add#(4, f__, TLog#(depth)),
             Add#(TAdd#(TLog#(a__), 4), g__, TLog#(depth))
            );
   let verbose = True;
   Reg#(Bit#(32)) cycle <- mkReg(0);

   rule every1 (verbose);
      cycle <= cycle + 1;
   endrule

   BinaryCam#(depth, keySz) bcam <- mkBinaryCam();
   FIFO#(Bool) bcamMatchFifo <- mkFIFO();

   BRAM_Configure cfg = defaultValue;
   cfg.latency = 2;
   BRAM2Port#(Bit#(depthSz), Bit#(actionSz)) ram <- mkBRAM2Server(cfg);

   Reg#(Bit#(depthSz)) addrIdx <- mkReg(0);

   rule handle_bcam_response;
      let v <- bcam.readServer.response.get;
      if (verbose) $display("(%0d) matchTable recv bcam response ", $time, fshow(v));
      if (isValid(v)) begin // if match
         let address = fromMaybe(?, v);
         ram.portA.request.put(BRAMRequest{write:False, responseOnWrite: False, address: address, datain:?});
         bcamMatchFifo.enq(True);
      end
      else begin // if miss
         ram.portA.request.put(BRAMRequest{write:False, responseOnWrite: False, address: 0, datain: ?});
         bcamMatchFifo.enq(False);
      end
   endrule

   // Interface for lookup from data-plane modules
   interface Server lookupPort;
      interface Put request;
         method Action put (Bit#(keySz) v);
            BcamReadReq#(Bit#(keySz)) req_bcam = BcamReadReq{data: v};
            bcam.readServer.request.put(pack(req_bcam));
            //if (verbose) $display("matchTable %d: lookup ", cycle, fshow(req_bcam));
         endmethod
      endinterface
      interface Get response;
         method ActionValue#(Maybe#(Bit#(actionSz))) get();
            let m <- toGet(bcamMatchFifo).get;
            let act <- ram.portA.response.get;
            if (verbose) $display("(%0d) matchTable: recv ram response ", $time, fshow(act));
            case (m) matches
               True: return tagged Valid act;
               False: return tagged Invalid;
            endcase
         endmethod
      endinterface
   endinterface

   // Interface for write from control-plane
   interface Put add_entry;
      method Action put (Tuple2#(Bit#(keySz), Bit#(actionSz)) v);
         BcamWriteReq#(Bit#(depthSz), Bit#(keySz)) req_bcam = BcamWriteReq{addr: addrIdx, data: pack(tpl_1(v))};
         BRAMRequest#(Bit#(depthSz), Bit#(actionSz)) req_ram = BRAMRequest{write: True, responseOnWrite: False, address: addrIdx, datain: pack(tpl_2(v))};
         bcam.writeServer.put(req_bcam);
         ram.portA.request.put(req_ram);
         $display("(%0d) match_table: add flow %x %x %x", $time, addrIdx, tpl_1(v), tpl_2(v));
         addrIdx <= addrIdx + 1; //FIXME: currently no reuse of address.
      endmethod
   endinterface
   interface Put delete_entry;
      method Action put (Bit#(depthSz) id);
         BcamWriteReq#(Bit#(depthSz), Bit#(keySz)) req_bcam = BcamWriteReq{addr: id, data: 0};
         BRAMRequest#(Bit#(depthSz), Bit#(actionSz)) req_ram = BRAMRequest{write: True, responseOnWrite: False, address: id, datain: 0};
         bcam.writeServer.put(req_bcam);
         ram.portA.request.put(req_ram);
         $display("(%0d) match_table: delete flow %x", $time, id);
      endmethod
   endinterface
   interface Put modify_entry;
      method Action put (Tuple2#(Bit#(depthSz), Bit#(actionSz)) v);
         match { .flowid, .act} = v;
         BRAMRequest#(Bit#(depthSz), Bit#(actionSz)) req_ram = BRAMRequest{write: True, responseOnWrite: False, address: flowid, datain: pack(act)};
         ram.portA.request.put(req_ram);
      endmethod
   endinterface
endmodule

module mkMatchTableBluesim#(String name)(MatchTable#(id, depth, keySz, actionSz))
   provisos (MatchTable::MatchTableSim#(id, keySz, actionSz),
             Log#(depth, depthSz));
   let verbose = True;

   Integer idv = valueOf(id);
   Integer dpv = valueOf(depth);
   FIFO#(Tuple2#(Bit#(keySz), Bit#(actionSz))) writeReqFifo <- mkFIFO;
   FIFO#(Bit#(keySz)) readReqFifo <- mkFIFO;
   FIFO#(Maybe#(Bit#(actionSz))) readDataFifo <- mkFIFO;

   Reg#(Bool)      isInitialized   <- mkReg(False);

   Handle fp <- openFile(name, ReadMode);
   List#(Tuple2#(Bit#(keySz), Bit#(actionSz))) entryList = tagged Nil;
   let readable <- hIsReadable(fp);
   if (readable) begin
      Bool isEOF <- hIsEOF(fp);
      while (!isEOF) begin
         let line <- hGetLine(fp);
         List#(String) parsedEntries = parseCSV(line);
         while (parsedEntries != tagged Nil) begin
            Bit#(keySz) key = fromInteger(hexStringToInteger(parsedEntries[0]));
            Bit#(actionSz) v = fromInteger(hexStringToInteger(parsedEntries[1]));
            Bit#(id) tid = 0;
            parsedEntries = List::drop(2, parsedEntries);
            entryList = List::cons(tuple2(key, v), entryList);
         end
         isEOF <- hIsEOF(fp);
      end
   end
   hClose(fp);

   rule do_read (isInitialized);
      let v <- toGet(readReqFifo).get;
      $display("(%0d) MatchTable: do_read %h", $time, v);
      Bit#(id) tid = 0;
      let ret <- matchtable_read(tid, pack(v));
      $display("(%0d) MatchTable: read %h", $time, ret);
      if (ret != 0)
         readDataFifo.enq(tagged Valid ret);
      else
         readDataFifo.enq(tagged Invalid);
   endrule

   Reg#(Bit#(8)) fsmIndex <- mkReg(0);

   rule do_init (fsmIndex < fromInteger(List::length(entryList)));
      $display("insert entry ", fromInteger(List::length(entryList)));
      Bit#(keySz) key = tpl_1(entryList[fsmIndex]);
      Bit#(actionSz) v = tpl_2(entryList[fsmIndex]);
      Bit#(id) tid = 0;
      matchtable_write(tid, key, v);
      fsmIndex <= fsmIndex + 1;
      $display("finished insert entry ", fromInteger(List::length(entryList)));
   endrule

   rule finish_init(fsmIndex == fromInteger(List::length(entryList)));
      isInitialized <= True;
   endrule

   interface Server lookupPort;
      interface Put request = toPut(readReqFifo);
      interface Get response = toGet(readDataFifo);
   endinterface
   interface Put add_entry;
      method Action put (Tuple2#(Bit#(keySz), Bit#(actionSz)) v);
         $display("(%0d) MatchTable: insert %h %h", $time, tpl_1(v), tpl_2(v));
         Bit#(id) tid = 0;
         matchtable_write(tid, tpl_1(v), tpl_2(v));
      endmethod
   endinterface
   interface Put delete_entry;
      method Action put (Bit#(depthSz) id);

      endmethod
   endinterface
   interface Put modify_entry;
      method Action put (Tuple2#(Bit#(depthSz), Bit#(actionSz)) v);

      endmethod
   endinterface
endmodule