should use tournament predictor; it improves accuracy on dir prediction

// Copyright (c) 2017 Massachusetts Institute of Technology
//
// 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.

//
// ==== common parameters ====
//

`define rv64 True
`define m True
`define a True
`define f True
`define d True

//`define NUM_CORES 1 // defined in make file

//`define PERF_COUNT // defined in makefile

`define REUSE_FMA // use FMA for add and mul

`define sizeSup 2 // 2 way superscalar

`define LOG_BOOT_ROM_BYTES 12 // 4KB boot rom

`define DIR_PRED_TOUR // branch predictor, other options are: BHT, TOUR

`define LOG_DEADLOCK_CYCLES 26 // 64M cycles for deadlock detection

// Be lazy in reservation station wake and phy reg file, and enqs. LSQ is by
// default lazy. 1-elem spec FIFOs (pipeline stage regs) are by default not
// lazy.
`define LAZY_RS_RF True
`define RS_LAZY_ENQ True
`define ROB_LAZY_ENQ True

`define TLB_SIZE 32 // L1 TLB size

`define BOOKKEEPING_MEM_SIZE 2 // TLB has 1 cycle latency

// FMA bookkeeping FIFO: add 1 to allow simultaneous enq/deq
`define BOOKKEEPING_FP_FMA_SIZE TAdd#(`XILINX_FP_FMA_LATENCY, 1)
// INT MUL bookkeeping FIFO: add 1 to allow simultaneous enq/deq, another 1
// because of internal flow control in MUL unit
`define BOOKKEEPING_INT_MUL_SIZE TAdd#(`XILINX_INT_MUL_LATENCY, 2)

`define LOG_L1_WAYS 3 // 8 ways
`define LOG_LLC_WAYS 4 // 16 ways

`define DRAMLLC_MAX_READS TExp#(`LOG_LLC_WAYS) // max reads in DRAM, match LLC ways

//
// ==== CORE SIZE ====
//

`ifdef CORE_TINY

    // ROB
    `define ROB_SIZE 48

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 16

    // LSQ
    `define LDQ_SIZE 18
    `define STQ_SIZE 11
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 12
    `define RS_MEM_SIZE 12
    `define RS_FPUMULDIV_SIZE 12

`endif

`ifdef CORE_SMALL

    // ROB
    `define ROB_SIZE 64

    // speculation
    `define NUM_EPOCHS 24
    `define NUM_SPEC_TAGS 24

    // LSQ
    `define LDQ_SIZE 24
    `define STQ_SIZE 14
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 16
    `define RS_MEM_SIZE 16
    `define RS_FPUMULDIV_SIZE 16

`endif

`ifdef CORE_MEDIUM

    // ROB
    `define ROB_SIZE 96

    // speculation
    `define NUM_EPOCHS 32
    `define NUM_SPEC_TAGS 32

    // LSQ
    `define LDQ_SIZE 36
    `define STQ_SIZE 21
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 24
    `define RS_MEM_SIZE 24
    `define RS_FPUMULDIV_SIZE 24

`endif

`ifdef CORE_LARGE

    // ROB
    `define ROB_SIZE 128

    // speculation
    `define NUM_EPOCHS 32
    `define NUM_SPEC_TAGS 32

    // LSQ
    `define LDQ_SIZE 48
    `define STQ_SIZE 28
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 32
    `define RS_MEM_SIZE 32
    `define RS_FPUMULDIV_SIZE 32

`endif

//
// ==== derived parameters ====
//

// Copyright (c) 2017 Massachusetts Institute of Technology
//
// 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.

//
// ==== common parameters ====
//

`define rv64 True
`define m True
`define a True
`define f True
`define d True

//`define NUM_CORES 1 // defined in make file

//`define PERF_COUNT // defined in makefile

`define REUSE_FMA // use FMA for add and mul

`define sizeSup 2 // 2 way superscalar

`define LOG_BOOT_ROM_BYTES 12 // 4KB boot rom

`define DIR_PRED_GSELECT // branch predictor, other options are: BHT, TOUR

`define LOG_DEADLOCK_CYCLES 26 // 64M cycles for deadlock detection

// Be lazy in reservation station wake and phy reg file, and enqs. LSQ is by
// default lazy. 1-elem spec FIFOs (pipeline stage regs) are by default not
// lazy.
`define LAZY_RS_RF True
`define RS_LAZY_ENQ True
`define ROB_LAZY_ENQ True

`define TLB_SIZE 32 // L1 TLB size

`define BOOKKEEPING_MEM_SIZE 2 // TLB has 1 cycle latency

// FMA bookkeeping FIFO: add 1 to allow simultaneous enq/deq
`define BOOKKEEPING_FP_FMA_SIZE TAdd#(`XILINX_FP_FMA_LATENCY, 1)
// INT MUL bookkeeping FIFO: add 1 to allow simultaneous enq/deq, another 1
// because of internal flow control in MUL unit
`define BOOKKEEPING_INT_MUL_SIZE TAdd#(`XILINX_INT_MUL_LATENCY, 2)

`define LOG_L1_WAYS 3 // 8 ways
`define LOG_LLC_WAYS 4 // 16 ways

`define DRAMLLC_MAX_READS TExp#(`LOG_LLC_WAYS) // max reads in DRAM, match LLC ways

//
// ==== CORE SIZE ====
//

`ifdef CORE_TINY

    // ROB
    `define ROB_SIZE 48

    // speculation
    `define NUM_EPOCHS 16
    `define NUM_SPEC_TAGS 16

    // LSQ
    `define LDQ_SIZE 18
    `define STQ_SIZE 11
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 12
    `define RS_MEM_SIZE 12
    `define RS_FPUMULDIV_SIZE 12

`endif

`ifdef CORE_SMALL

    // ROB
    `define ROB_SIZE 64

    // speculation
    `define NUM_EPOCHS 24
    `define NUM_SPEC_TAGS 24

    // LSQ
    `define LDQ_SIZE 24
    `define STQ_SIZE 14
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 16
    `define RS_MEM_SIZE 16
    `define RS_FPUMULDIV_SIZE 16

`endif

`ifdef CORE_MEDIUM

    // ROB
    `define ROB_SIZE 96

    // speculation
    `define NUM_EPOCHS 32
    `define NUM_SPEC_TAGS 32

    // LSQ
    `define LDQ_SIZE 36
    `define STQ_SIZE 21
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 24
    `define RS_MEM_SIZE 24
    `define RS_FPUMULDIV_SIZE 24

`endif

`ifdef CORE_LARGE

    // ROB
    `define ROB_SIZE 128

    // speculation
    `define NUM_EPOCHS 32
    `define NUM_SPEC_TAGS 32

    // LSQ
    `define LDQ_SIZE 48
    `define STQ_SIZE 28
    `define SB_SIZE 4

    // reservation station sizes
    `define RS_ALU_SIZE 32
    `define RS_MEM_SIZE 32
    `define RS_FPUMULDIV_SIZE 32

`endif

//
// ==== derived parameters ====
//


Improved transformReq and transformResp functions in CleintServerUtil

These functions can now change the type of request and response.

// Copyright (c) 2016, 2017 Massachusetts Institute of Technology

// 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.

package ClientServerUtil;

import ClientServer::*;
import GetPut::*;

/**
 * This package contains functions to modify the request and responses of a
 * Client or a Server interface. For each type of interface, there are three
 * types of functions: one transforms reqeusts, one transforms responses, and
 * one transforms both. In addition there are typeclasses to simplify the
 * naming of the Client and Server versions of each function by giving them
 * the same name.
 *
 * Client functions:
 *   newClient transformClientReq(reqF, client)
 *   newClient transformClientResp(respF, client)
 *   newClient transformClientReqResp(reqF, respF, client)
 * Server functions:
 *   newServer transformServerReq(reqF, server)
 *   newServer transformServerResp(respF, server)
 *   newServer transformServerReqResp(reqF, respF, server)
 * Unified typeclass functions:
 *   newClientOrServer transformReq(reqF, clientOrServer)
 *   newClientOrServer transformResp(respF, clientOrServer)
 *   newClientOrServer transformReqResp(reqF, respF, clientOrServer)
 */

function Client#(newReqT, respT) transformClientReqResp(function newReqT reqF(reqT x),
                                                        function newRespT respF(respT x),
                                                        Client#(reqT, newRespT) client);
    return (interface Client;
                interface Get request;
                    method ActionValue#(newReqT) get;
                        let x <- client.request.get;
                        return reqF(x);
                    endmethod
                endinterface
                interface Put response;
                    method Action put(respT x);
                        client.response.put(respF(x));
                    endmethod
                endinterface
            endinterface);
endfunction

function Server#(reqT, newRespT) transformServerReqResp(function newReqT reqF(reqT x),
                                                        function newRespT respF(respT x),
                                                        Server#(newReqT, respT) server );
    return (interface Server;
                interface Put request;
                    method Action put(reqT x);
                        server.request.put(reqF(x));
                    endmethod
                endinterface
                interface Get response;
                    method ActionValue#(newRespT) get;
                        let x <- server.response.get;
                        return respF(x);
                    endmethod
                endinterface
            endinterface);
endfunction

function Client#(newReqT, respT) transformClientReq(function newReqT reqF(reqT x),
                                                    Client#(reqT, respT) client);
    return transformClientReqResp(reqF, id, client);
endfunction

function Client#(reqT, respT) transformClientResp(function newRespT respF(respT x),
                                                  Client#(reqT, newRespT) client);
    return transformClientReqResp(id, respF, client);
endfunction

function Server#(reqT, respT) transformServerReq(function newReqT reqF(reqT x),
                                                 Server#(newReqT, respT) client);
    return transformServerReqResp(reqF, id, client);
endfunction

function Server#(reqT, newRespT) transformServerResp(function newRespT respF(respT x),
                                                     Server#(reqT, respT) client);
    return transformServerReqResp(id, respF, client);
endfunction

// typeclasses

typeclass TransformReqHelper#(type clientOrServer, type reqT, type newReqT, type newClientOrServer)
        dependencies ((clientOrServer, newClientOrServer) determines (reqT, newReqT));
    function newClientOrServer transformReq(function newReqT f(reqT x),
                                            clientOrServer ifc);
endtypeclass

typeclass TransformRespHelper#(type clientOrServer, type respT, type newRespT, type newClientOrServer)
        dependencies ((clientOrServer, newClientOrServer) determines (respT, newRespT));
    function newClientOrServer transformResp(function newRespT f(respT x),
                                             clientOrServer ifc);
endtypeclass

typeclass TransformReqRespHelper#(type clientOrServer, type reqT, type respT, type newReqT, type newRespT, type newClientOrServer)
        dependencies ((clientOrServer, newClientOrServer) determines (reqT, respT, newReqT, newRespT));
    function newClientOrServer transformReqResp(function newReqT reqF(reqT x),
                                                function newRespT respF(respT x),
                                                clientOrServer ifc);
endtypeclass

// instances

instance TransformReqHelper#(Client#(reqT, respT), reqT, newReqT, Client#(newReqT, respT));
    function Client#(newReqT, respT) transformReq(function newReqT f(reqT x),
                                                  Client#(reqT, respT) ifc);
        return transformClientReq(f, ifc);
    endfunction
endinstance

instance TransformReqHelper#(Server#(newReqT, respT), reqT, newReqT, Server#(reqT, respT));
    function Server#(reqT, respT) transformReq(function newReqT f(reqT x),
                                               Server#(newReqT, respT) ifc);
        return transformServerReq(f, ifc);
    endfunction
endinstance

instance TransformRespHelper#(Client#(reqT, newRespT), respT, newRespT, Client#(reqT, respT));
    function Client#(reqT, respT) transformResp(function newRespT f(respT x),
                                                Client#(reqT, newRespT) ifc);
        return transformClientResp(f, ifc);
    endfunction
endinstance

instance TransformRespHelper#(Server#(reqT, respT), respT, newRespT, Server#(reqT, newRespT));
    function Server#(reqT, newRespT) transformResp(function newRespT f(respT x),
                                                   Server#(reqT, respT) ifc);
        return transformServerResp(f, ifc);
    endfunction
endinstance

instance TransformReqRespHelper#(Client#(reqT, newRespT), reqT, respT, newReqT, newRespT, Client#(newReqT, respT));
    function Client#(newReqT, respT) transformReqResp(function newReqT reqF(reqT x),
                                                      function newRespT respF(respT x),
                                                      Client#(reqT, newRespT) ifc);
        return transformClientReqResp(reqF, respF, ifc);
    endfunction
endinstance

instance TransformReqRespHelper#(Server#(newReqT, respT), reqT, respT, newReqT, newRespT, Server#(reqT, newRespT));
    function Server#(reqT, newRespT) transformReqResp(function newReqT reqF(reqT x),
                                                      function newRespT respF(respT x),
                                                      Server#(newReqT, respT) ifc);
        return transformServerReqResp(reqF, respF, ifc);
    endfunction
endinstance

endpackage

// Copyright (c) 2016 Massachusetts Institute of Technology

// 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.

package ClientServerUtil;

import ClientServer::*;
import GetPut::*;

typeclass ClientServerUtilHelper#(type clientOrServer, type reqT, type respT) dependencies (clientOrServer determines (reqT, respT));
    function clientOrServer transformReqResp(   function reqT reqF(reqT x),
                                                function respT respFunc(respT x),
                                                clientOrServer ifc );
    function clientOrServer transformReq(function reqT f(reqT x), clientOrServer ifc);
        return transformReqResp( f, id, ifc );
    endfunction
    function clientOrServer transformResp(function respT f(respT x), clientOrServer ifc);
        return transformReqResp( id, f, ifc );
    endfunction
endtypeclass

instance ClientServerUtilHelper#(Client#(reqT, respT), reqT, respT);
    function Client#(reqT, respT) transformReqResp( function reqT reqF(reqT x),
                                                    function respT respF(respT x),
                                                    Client#(reqT, respT) client );
        return (interface Client;
                    interface Get request;
                        method ActionValue#(reqT) get;
                            let x <- client.request.get;
                            return reqF(x);
                        endmethod
                    endinterface
                    interface Put response;
                        method Action put(respT x);
                            client.response.put(respF(x));
                        endmethod
                    endinterface
                endinterface);
    endfunction
endinstance

instance ClientServerUtilHelper#(Server#(reqT, respT), reqT, respT);
    function Server#(reqT, respT) transformReqResp( function reqT reqF(reqT x),
                                                    function respT respF(respT x),
                                                    Server#(reqT, respT) server );
        return (interface Server;
                    interface Put request;
                        method Action put(reqT x);
                            server.request.put(reqF(x));
                        endmethod
                    endinterface
                    interface Get response;
                        method ActionValue#(respT) get;
                            let x <- server.response.get;
                            return respF(x);
                        endmethod
                    endinterface
                endinterface);
    endfunction
endinstance

endpackage


reorder Rgb888

reorder Rgb888

Change-Id: I86c1fb61b0d51e03d90a2cb869a701a99415c686

// Copyright (c) 2013 Nokia, Inc.
// 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.

// little endian RGB
typedef struct {
    Bit#(8) r;
    Bit#(8) g;
    Bit#(8) b;
} Rgb888 deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bit#(1) de;
    pixelType pixel;
} VideoData#(type pixelType) deriving (Bits);

typedef struct {
    Bit#(8) y;
    Bit#(8) u;
    Bit#(8) v;
} Yuv444 deriving (Bits);

typedef struct {
    Bit#(8) y1;
    Bit#(8) u;
    Bit#(8) y2;
    Bit#(8) v;
} Yuv422 deriving (Bits);

typedef struct {
    Bit#(8) uv;
    Bit#(8) yy;
} Yyuv deriving (Bits);

interface Rgb888ToYuv422;
    method Action putRgb888(Rgb888 rgb888);
    method ActionValue#(Yuv422) getYuv422();
endinterface

function Yuv444 rgbtoyuv(Rgb888 rgb);
    Bit#(16) y = 77*extend(rgb.r) + 150 * extend(rgb.g) + 29 * extend(rgb.b) + 0;
    Bit#(16) u = -43*extend(rgb.r) - 85*extend(rgb.g) + 128*extend(rgb.b) + 128;
    Bit#(16) v = 128*extend(rgb.r) - 107*extend(rgb.g) - 21*extend(rgb.b) + 128;
    return Yuv444 { y: truncate(y>>8), u: truncate(u >> 8), v: truncate(v >> 8) };
endfunction

typedef struct {
    Bit#(16) y1;
    Bit#(16) y2;
    Bit#(16) y3;
    Bit#(16) u1;
    Bit#(16) u2;
    Bit#(16) u3;
    Bit#(16) v1;
    Bit#(16) v2;
    Bit#(16) v3;
} Yuv444Intermediates deriving (Bits);

function Yuv444Intermediates rgbToYuvIntermediates(Rgb888 rgb);
    return Yuv444Intermediates {
               y1: 77*extend(rgb.r), y2: 150 * extend(rgb.g), y3: 29 * extend(rgb.b),
               u1: 43*extend(rgb.r), u2: 85*extend(rgb.g), u3: 128*extend(rgb.b),
               v1: 128*extend(rgb.r), v2: 107*extend(rgb.g), v3: 21*extend(rgb.b) };
endfunction

function Yuv444 yuvIntermediatesToYuv444(Yuv444Intermediates w);
    let y = 0 + w.y1 + w.y2 + w.y3;
    let u = (128<<8) - w.u1 -w.u2 + w.u3;
    let v = (128<<8) + w.v1 - w.v2 - w.v3;
    return Yuv444 { y: truncate(y>>8), u: truncate(u >> 8), v: truncate(v >> 8) };
endfunction

function Yuv422 yuv444toyuv422(Yuv444 yuv0, Yuv444 yuv1);
    Bit#(9) u = (extend(yuv0.u) + extend(yuv1.u)) >> 1;
    Bit#(9) v = (extend(yuv0.u) + extend(yuv1.v)) >> 1;
    return Yuv422 { y1: yuv0.y, u: truncate(u), y2: yuv1.y, v: truncate(v) };
endfunction

// module mkRgb888ToYuv422(Rgb888ToYuv422);
//     FIFOF#(Yuv444) yuvFifo <- mkBypassFIFOF();
//     Reg#(Maybe#(Yuv444)) yuvReg1 <- mkReg(tagged Invalid);

//     rule alternating if (yuvReg1 matches tagged Invalid);
//         yuvReg1 <= tagged Valid yuv0;
//     endrule

//     method Action putRgb888(Rgb888 rgb888) if (yuvReg0 matches tagged Invalid);
//         yuvFifo.enq(rgbtoyub(rgb888));
//     endmethod

//     method ActionValue#(Yuv422) getYuv422() if (yuvReg1 matches tagged Valid .yuv1);
//         let yuv0 = yuvFifo.first;
//         yuvFifo.deq;
//         let yuv1 = yuvReg1;
//         yuvReg1 <= tagged Invalid;
//         let yuv422 = yuv444toyuv422(yuv0, yuv1);
//         return yuv422;
//     endmethod

// endmodule

// Copyright (c) 2013 Nokia, Inc.
// 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.

// little endian RGB
typedef struct {
    Bit#(8) b;
    Bit#(8) g;
    Bit#(8) r;
} Rgb888 deriving (Bits);

typedef struct {
    Bit#(1) vsync;
    Bit#(1) hsync;
    Bit#(1) de;
    pixelType pixel;
} VideoData#(type pixelType) deriving (Bits);

typedef struct {
    Bit#(8) y;
    Bit#(8) u;
    Bit#(8) v;
} Yuv444 deriving (Bits);

typedef struct {
    Bit#(8) y1;
    Bit#(8) u;
    Bit#(8) y2;
    Bit#(8) v;
} Yuv422 deriving (Bits);

typedef struct {
    Bit#(8) uv;
    Bit#(8) yy;
} Yyuv deriving (Bits);

interface Rgb888ToYuv422;
    method Action putRgb888(Rgb888 rgb888);
    method ActionValue#(Yuv422) getYuv422();
endinterface

function Yuv444 rgbtoyuv(Rgb888 rgb);
    Bit#(16) y = 77*extend(rgb.r) + 150 * extend(rgb.g) + 29 * extend(rgb.b) + 0;
    Bit#(16) u = -43*extend(rgb.r) - 85*extend(rgb.g) + 128*extend(rgb.b) + 128;
    Bit#(16) v = 128*extend(rgb.r) - 107*extend(rgb.g) - 21*extend(rgb.b) + 128;
    return Yuv444 { y: truncate(y>>8), u: truncate(u >> 8), v: truncate(v >> 8) };
endfunction

typedef struct {
    Bit#(16) y1;
    Bit#(16) y2;
    Bit#(16) y3;
    Bit#(16) u1;
    Bit#(16) u2;
    Bit#(16) u3;
    Bit#(16) v1;
    Bit#(16) v2;
    Bit#(16) v3;
} Yuv444Intermediates deriving (Bits);

function Yuv444Intermediates rgbToYuvIntermediates(Rgb888 rgb);
    return Yuv444Intermediates {
               y1: 77*extend(rgb.r), y2: 150 * extend(rgb.g), y3: 29 * extend(rgb.b),
               u1: 43*extend(rgb.r), u2: 85*extend(rgb.g), u3: 128*extend(rgb.b),
               v1: 128*extend(rgb.r), v2: 107*extend(rgb.g), v3: 21*extend(rgb.b) };
endfunction

function Yuv444 yuvIntermediatesToYuv444(Yuv444Intermediates w);
    let y = 0 + w.y1 + w.y2 + w.y3;
    let u = (128<<8) - w.u1 -w.u2 + w.u3;
    let v = (128<<8) + w.v1 - w.v2 - w.v3;
    return Yuv444 { y: truncate(y>>8), u: truncate(u >> 8), v: truncate(v >> 8) };
endfunction

function Yuv422 yuv444toyuv422(Yuv444 yuv0, Yuv444 yuv1);
    Bit#(9) u = (extend(yuv0.u) + extend(yuv1.u)) >> 1;
    Bit#(9) v = (extend(yuv0.u) + extend(yuv1.v)) >> 1;
    return Yuv422 { y1: yuv0.y, u: truncate(u), y2: yuv1.y, v: truncate(v) };
endfunction

// module mkRgb888ToYuv422(Rgb888ToYuv422);
//     FIFOF#(Yuv444) yuvFifo <- mkBypassFIFOF();
//     Reg#(Maybe#(Yuv444)) yuvReg1 <- mkReg(tagged Invalid);

//     rule alternating if (yuvReg1 matches tagged Invalid);
//         yuvReg1 <= tagged Valid yuv0;
//     endrule

//     method Action putRgb888(Rgb888 rgb888) if (yuvReg0 matches tagged Invalid);
//         yuvFifo.enq(rgbtoyub(rgb888));
//     endmethod

//     method ActionValue#(Yuv422) getYuv422() if (yuvReg1 matches tagged Valid .yuv1);
//         let yuv0 = yuvFifo.first;
//         yuvFifo.deq;
//         let yuv1 = yuvReg1;
//         yuvReg1 <= tagged Invalid;
//         let yuv422 = yuv444toyuv422(yuv0, yuv1);
//         return yuv422;
//     endmethod

// endmodule


add correct values of tb and te to second recursive calls

// Copyright (c) 2014 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 StmtFSM::*;
import BRAM::*;
import GotohB::*;
import StackReg::*;

interface SWAlgorithm;
   method Action setupA (Bit#(14) start, Bit#(14) length);
   method Action setupB (Bit#(14) start, Bit#(14) length);
   method Bit#(14) result();
   interface FSM fsm;
endinterface

/* frame arguments */
typedef struct {
   Bit#(14) aStart;
   Bit#(14) bStart;
   Bit#(14) aLen;
   Bit#(14) bLen;
   Bit#(16) tb; /* tb, te only need to be 1 bit, to represent 0 or g */
   Bit#(16) te;
   } CArgs deriving(Bits);

typedef struct {
   Bit#(14) midi;
   Bit#(14) minj;
   Bit#(2) mintype;
   } CVars deriving(Bits);

typedef enum {GCSIdle, GCS1, GCS2, GCS3, GCS4, GCS5, GCS6,
   GCSComplete} GCState deriving (Bits, Eq);

module mkGotohC#(
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA,
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB,
   GotohAlgorithm cgotohB0,
   GotohAlgorithm cgotohB1,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) cc,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) dd,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) rr,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) ss)(SWAlgorithm)
   provisos(Add#(0, 14, strIndexWidth),
	    Add#(0, 14, lIndexWidth));

   Bit#(16) initialH = 1;
   Bit#(16) initialG = 4;
      /* pc, args, vars */
   StackReg#(128, GCState, CArgs, CVars) fr <- mkStackReg(128, GCSIdle);

   Reg#(Bit#(14)) aStartReg <- mkReg(0);
   Reg#(Bit#(14)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(14)) aLenReg <- mkReg(0);
   Reg#(Bit#(14)) bLenReg <- mkReg(0);
   Reg#(Bit#(14)) ii <- mkReg(0);
   Reg#(Bit#(14)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(14)) outcounter <- mkReg(0);
   Reg#(Bit#(16)) alt1 <- mkReg(0);
   Reg#(Bit#(16)) alt2 <- mkReg(0);
   Reg#(Bit#(16)) minsofar <- mkReg(0);
   Reg#(Bit#(1)) minfound <- mkReg(0);

/*
 * GotohC(Astart, Alen, Bstart, Blen, tb, te, output fifo)
 * implicit A storage, B storage
 *
 */
   function Bit#(16) gap (Bit#(16) i);

      if (i == 0) gap = 0;
      else gap = (initialG + (initialH * i));
      endfunction: gap

  // This FSM searches string B looking for the first char of string A
   Stmt gotohC2Stmt =
   seq
      $display("gotohC2Stmt running ");
      // read A[0]
      strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.aStart, datain: ?});
      action
	 let tmp <- strA.response.get();
	 aData <= tmp;
      endaction
      alt1 <= min(fr.args.tb, fr.args.te) + gap(zeroExtend(fr.args.bLen));
      minsofar <= alt1;
      fr.vars.minj <= 1;
      // scan B
      for (jj <= 1; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.bStart + jj - 1, datain: ?});
	    action
	       let tmp <- strB.response.get();
	       bData <= tmp;
	    endaction
	    if (aData == bData)
	       alt2 <= 0;
	    else
	       alt2 <= 2;
	    alt2 <= alt2 + gap(zeroExtend(jj - 1)) + gap(zeroExtend(fr.args.bLen - jj));
	    if (min(alt1, alt2) < minsofar)
	       par
		  minsofar <= min(alt1, alt2);
		  fr.vars.minj <= jj;
	       endpar
	 endseq
      if (fr.vars.minj > 1)
	 $display("delete B[%d] through B[%d]",
	    fr.args.bStart, fr.args.bStart + fr.vars.minj - 1);
      $display("convert A[%d] (%s) to B[%d] (%s)",
	       fr.args.aStart, aData, fr.args.bStart + fr.vars.minj - 1, bData);
      if (fr.vars.minj < fr.args.bLen)
	 $display("delete B[%d] through B[%d]",
		  fr.args.bStart + fr.vars.minj, fr.args.bStart + fr.args.bLen - 1);
      fr.doreturn();
   endseq;

   FSM gC2fsm <- mkFSM(gotohC2Stmt);

   // AlgC step 1, 2, and 3
   rule gc1 (fr.pc == GCS1);
      $display("GCS1 aStart %d aLen %d bStart %d bLen %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen);
      if (fr.args.bLen == 0)
	 begin
	    $display("delete A[%d] through A[%d]",
	       fr.args.aStart, fr.args.aStart + fr.args.aLen - 1);
	    fr.doreturn();
	 end
     else if (fr.args.bLen == 0)
	begin
	   $display("insert B[%d] through B[%d]",
	      fr.args.bStart, fr.args.bStart + fr.args.bLen - 1);
	end
     else if (fr.args.aLen == 1)
	begin
	   gC2fsm.start();
	   fr.nextpc(GCS2);
	end
     else
	action
	   let midi = fr.args.aLen >> 1;
	   fr.vars.midi <= midi;
	   cgotohB1.setupA(fr.args.aStart, midi);
	   cgotohB1.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB1.setupG(fr.args.tb);
	   cgotohB0.setupA(fr.args.aStart+midi, fr.args.aLen - midi);
	   cgotohB0.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB0.setupG(fr.args.te);
	   cgotohB0.fsm.start();
	   cgotohB1.fsm.start();
	   fr.nextpc(GCS3);
	endaction
   endrule

   // This FSM searches the results of the two calls to GotohB
   Stmt gotohC4Stmt =
   seq
      $display ("gotohC4A stmt running");
      action
	 minfound <= 0;
	 minsofar <= 0;
	 fr.vars.minj <= 0;
      endaction
      for (jj <= 0; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    cc.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	    rr.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	    dd.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	    ss.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	    action
	       let tc <- cc.response.get();
	       let td <- dd.response.get();
	       let tr <- rr.response.get();
	       let ts <- ss.response.get();
	       let t1 = tc + tr;
	       let t2 = td + ts;
	       $display(" j %d cc %d dd %d rr %d ss %d",
		  jj, tc, td, tr, ts);
	       if ((minfound == 0) || (t1 < minsofar))
		  action
		     fr.vars.mintype <= 1;
		     fr.vars.minj <= jj;
		     minsofar <= t1;
		  endaction
	       if (t2 < minsofar)
		  action
		     fr.vars.mintype <= 2;
		     fr.vars.minj <= jj;
		     minsofar <= t2;
		  endaction
	       minfound <= 1;
	    endaction
	 endseq
      $display ("midi %d minj %d fr.vars.mintype %d",
	 fr.vars.midi, fr.vars.minj, fr.vars.mintype);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: initialG}, fr.vars);
	 endaction
      else /* fr.vars.mintype == 2 */
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi - 1, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: 0}, fr.vars);
	 endaction
   endseq;

   FSM gc4fsm <- mkFSM(gotohC4Stmt);

   rule gc3 (fr.pc == GCS3 && cgotohB0.fsm.done() && cgotohB1.fsm.done());
      //$display("HSC3");
      gc4fsm.start();
      fr.nextpc(GCS4);
   endrule

   rule gc5 (fr.pc == GCS5);
      $display("GCC5 aStart %d aLen %d bStart %d bLen %d midi %d maj %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen,
	 fr.vars.midi, fr.vars.minj);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi, aLen: fr.args.aLen - fr.vars.midi, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj, tb: initialG, te: fr.args.te}, fr.vars);
	 endaction
      else
	 action
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi + 1, aLen: fr.args.aLen - fr.vars.midi- 1, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj, tb: 0, te: fr.args.te}, fr.vars);
	 endaction
   endrule

   rule gc6 (fr.pc == GCS6);
      $display("GSC6");
      fr.doreturn();
   endrule

   rule hccomplete (fr.pc == GCSComplete);
      $display("GSCComplete, result size %d", outcounter);
      fr.nextpc(GCSIdle);
   endrule

   method Action setupA(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupA %d %d", start, length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupB %d %d", start, length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Bit#(14) result();
      return(outcounter);
   endmethod

   interface FSM fsm;
      method Action start();
         $display("GotohC running aLen %d bLen %d", aLenReg, bLenReg);
	 fr.docall(GCS1, GCSComplete, CArgs{aStart: 0, aLen: aLenReg,
	    bStart: 0, bLen: bLenReg}, CVars {midi: 0, minj: 0});
      endmethod
      method Bool done();
	 return(fr.pc == GCSIdle);
      endmethod
      method Action waitTillDone();
      endmethod
      method Action abort();
      endmethod
   endinterface: fsm

endmodule

// Copyright (c) 2014 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 StmtFSM::*;
import BRAM::*;
import GotohB::*;
import StackReg::*;

interface SWAlgorithm;
   method Action setupA (Bit#(14) start, Bit#(14) length);
   method Action setupB (Bit#(14) start, Bit#(14) length);
   method Bit#(14) result();
   interface FSM fsm;
endinterface

/* frame arguments */
typedef struct {
   Bit#(14) aStart;
   Bit#(14) bStart;
   Bit#(14) aLen;
   Bit#(14) bLen;
   Bit#(16) tb; /* tb, te only need to be 1 bit, to represent 0 or g */
   Bit#(16) te;
   } CArgs deriving(Bits);

typedef struct {
   Bit#(14) midi;
   Bit#(14) minj;
   Bit#(2) mintype;
   } CVars deriving(Bits);

typedef enum {GCSIdle, GCS1, GCS2, GCS3, GCS4, GCS5, GCS6,
   GCSComplete} GCState deriving (Bits, Eq);

module mkGotohC#(
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strA,
   BRAMServer#(Bit#(strIndexWidth), Bit#(8)) strB,
   GotohAlgorithm cgotohB0,
   GotohAlgorithm cgotohB1,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) cc,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) dd,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) rr,
   BRAMServer#(Bit#(lIndexWidth), Bit#(16)) ss)(SWAlgorithm)
   provisos(Add#(0, 14, strIndexWidth),
	    Add#(0, 14, lIndexWidth));

   Bit#(16) initialH = 1;
   Bit#(16) initialG = 4;
      /* pc, args, vars */
   StackReg#(128, GCState, CArgs, CVars) fr <- mkStackReg(128, GCSIdle);

   Reg#(Bit#(14)) aStartReg <- mkReg(0);
   Reg#(Bit#(14)) bStartReg <- mkReg(0);
   Reg#(Bit#(14)) rStartReg <- mkReg(0);
   Reg#(Bit#(14)) aLenReg <- mkReg(0);
   Reg#(Bit#(14)) bLenReg <- mkReg(0);
   Reg#(Bit#(14)) ii <- mkReg(0);
   Reg#(Bit#(14)) jj <- mkReg(0);
   Reg#(Bit#(8)) aData <- mkReg(0);
   Reg#(Bit#(8)) bData <- mkReg(0);
   Reg#(Bit#(14)) outcounter <- mkReg(0);
   Reg#(Bit#(16)) alt1 <- mkReg(0);
   Reg#(Bit#(16)) alt2 <- mkReg(0);
   Reg#(Bit#(16)) minsofar <- mkReg(0);
   Reg#(Bit#(1)) minfound <- mkReg(0);

/*
 * GotohC(Astart, Alen, Bstart, Blen, tb, te, output fifo)
 * implicit A storage, B storage
 *
 */
   function Bit#(16) gap (Bit#(16) i);

      if (i == 0) gap = 0;
      else gap = (initialG + (initialH * i));
      endfunction: gap

  // This FSM searches string B looking for the first char of string A
   Stmt gotohC2Stmt =
   seq
      $display("gotohC2Stmt running ");
      // read A[0]
      strA.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.aStart, datain: ?});
      action
	 let tmp <- strA.response.get();
	 aData <= tmp;
      endaction
      alt1 <= min(fr.args.tb, fr.args.te) + gap(zeroExtend(fr.args.bLen));
      minsofar <= alt1;
      fr.vars.minj <= 1;
      // scan B
      for (jj <= 1; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    strB.request.put(BRAMRequest{write: False, responseOnWrite: False, address: fr.args.bStart + jj - 1, datain: ?});
	    action
	       let tmp <- strB.response.get();
	       bData <= tmp;
	    endaction
	    if (aData == bData)
	       alt2 <= 0;
	    else
	       alt2 <= 2;
	    alt2 <= alt2 + gap(zeroExtend(jj - 1)) + gap(zeroExtend(fr.args.bLen - jj));
	    if (min(alt1, alt2) < minsofar)
	       par
		  minsofar <= min(alt1, alt2);
		  fr.vars.minj <= jj;
	       endpar
	 endseq
      if (fr.vars.minj > 1)
	 $display("delete B[%d] through B[%d]",
	    fr.args.bStart, fr.args.bStart + fr.vars.minj - 1);
      $display("convert A[%d] (%s) to B[%d] (%s)",
	       fr.args.aStart, aData, fr.args.bStart + fr.vars.minj - 1, bData);
      if (fr.vars.minj < fr.args.bLen)
	 $display("delete B[%d] through B[%d]",
		  fr.args.bStart + fr.vars.minj, fr.args.bStart + fr.args.bLen - 1);
      fr.doreturn();
   endseq;

   FSM gC2fsm <- mkFSM(gotohC2Stmt);

   // AlgC step 1, 2, and 3
   rule gc1 (fr.pc == GCS1);
      $display("GCS1 aStart %d aLen %d bStart %d bLen %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen);
      if (fr.args.bLen == 0)
	 begin
	    $display("delete A[%d] through A[%d]",
	       fr.args.aStart, fr.args.aStart + fr.args.aLen - 1);
	    fr.doreturn();
	 end
     else if (fr.args.bLen == 0)
	begin
	   $display("insert B[%d] through B[%d]",
	      fr.args.bStart, fr.args.bStart + fr.args.bLen - 1);
	end
     else if (fr.args.aLen == 1)
	begin
	   gC2fsm.start();
	   fr.nextpc(GCS2);
	end
     else
	action
	   let midi = fr.args.aLen >> 1;
	   fr.vars.midi <= midi;
	   cgotohB1.setupA(fr.args.aStart, midi);
	   cgotohB1.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB1.setupG(fr.args.tb);
	   cgotohB0.setupA(fr.args.aStart+midi, fr.args.aLen - midi);
	   cgotohB0.setupB(fr.args.bStart, fr.args.bLen);
	   cgotohB0.setupG(fr.args.te);
	   cgotohB0.fsm.start();
	   cgotohB1.fsm.start();
	   fr.nextpc(GCS3);
	endaction
   endrule

   // This FSM searches the results of the two calls to GotohB
   Stmt gotohC4Stmt =
   seq
      $display ("gotohC4A stmt running");
      action
	 minfound <= 0;
	 minsofar <= 0;
	 fr.vars.minj <= 0;
      endaction
      for (jj <= 0; jj <= fr.args.bLen; jj <= jj + 1)
	 seq
	    cc.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	    rr.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	    dd.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(jj), datain: ?});
	    ss.request.put(BRAMRequest{write: False, responseOnWrite: False, address: zeroExtend(fr.args.bLen - jj), datain: ?});
	    action
	       let tc <- cc.response.get();
	       let td <- dd.response.get();
	       let tr <- rr.response.get();
	       let ts <- ss.response.get();
	       let t1 = tc + tr;
	       let t2 = td + ts;
	       $display(" j %d cc %d dd %d rr %d ss %d",
		  jj, tc, td, tr, ts);
	       if ((minfound == 0) || (t1 < minsofar))
		  action
		     fr.vars.mintype <= 1;
		     fr.vars.minj <= jj;
		     minsofar <= t1;
		  endaction
	       if (t2 < minsofar)
		  action
		     fr.vars.mintype <= 2;
		     fr.vars.minj <= jj;
		     minsofar <= t2;
		  endaction
	       minfound <= 1;
	    endaction
	 endseq
      $display ("midi %d minj %d fr.vars.mintype %d",
	 fr.vars.midi, fr.vars.minj, fr.vars.mintype);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: initialG}, fr.vars);
	 endaction
      else /* fr.vars.mintype == 2 */
	 action
	    fr.docall(GCS1, GCS5, CArgs {aStart: fr.args.aStart, aLen: fr.vars.midi - 1, bStart: fr.args.bStart, bLen: fr.vars.minj, tb: fr.args.tb, te: initialG}, fr.vars);
	 endaction
   endseq;

   FSM gc4fsm <- mkFSM(gotohC4Stmt);

   rule gc3 (fr.pc == GCS3 && cgotohB0.fsm.done() && cgotohB1.fsm.done());
      //$display("HSC3");
      gc4fsm.start();
      fr.nextpc(GCS4);
   endrule

   rule gc5 (fr.pc == GCS5);
      $display("GCC5 aStart %d aLen %d bStart %d bLen %d midi %d maj %d",
	 fr.args.aStart, fr.args.aLen, fr.args.bStart, fr.args.bLen,
	 fr.vars.midi, fr.vars.minj);
      if (fr.vars.mintype == 1)
	 action
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi, aLen: fr.args.aLen - fr.vars.midi, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj}, fr.vars);
	 endaction
      else
	 action
	    fr.docall(GCS1, GCS6, CArgs{aStart: fr.args.aStart + fr.vars.midi + 1, aLen: fr.args.aLen - fr.vars.midi- 1, bStart: fr.args.bStart + fr.vars.minj, bLen: fr.args.bLen - fr.vars.minj}, fr.vars);
	 endaction
   endrule

   rule gc6 (fr.pc == GCS6);
      $display("GSC6");
      fr.doreturn();
   endrule

   rule hccomplete (fr.pc == GCSComplete);
      $display("GSCComplete, result size %d", outcounter);
      fr.nextpc(GCSIdle);
   endrule

   method Action setupA(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupA %d %d", start, length);
      aStartReg <= start;
      aLenReg <= length;
   endmethod

   method Action setupB(Bit#(14) start, Bit#(14) length);
      $display("GotohC setupB %d %d", start, length);
      bStartReg <= start;
      bLenReg <= length;
   endmethod

   method Bit#(14) result();
      return(outcounter);
   endmethod

   interface FSM fsm;
      method Action start();
         $display("GotohC running aLen %d bLen %d", aLenReg, bLenReg);
	 fr.docall(GCS1, GCSComplete, CArgs{aStart: 0, aLen: aLenReg,
	    bStart: 0, bLen: bLenReg}, CVars {midi: 0, minj: 0});
      endmethod
      method Bool done();
	 return(fr.pc == GCSIdle);
      endmethod
      method Action waitTillDone();
      endmethod
      method Action abort();
      endmethod
   endinterface: fsm

endmodule


use FIFO_DUALCLOCK_MACRO on Xilinx FPGAs and xsim

// Copyright (c) 2015 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 Clocks::*;
import Vector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import CBus::*; // extendNP and truncateNP

`include "ConnectalProjectConfig.bsv"
import Arith::*;
import ConnectalClocks::*;

`ifdef SIMULATION
`ifdef BOARD_xsim
`define USE_XILINX_MACRO
`endif // xsim
`else // not SIMULATION
`ifdef XILINX
`define USE_XILINX_MACRO
`endif // XILINX
`endif // not SIMULATION

`ifdef USE_XILINX_MACRO
(* always_ready, always_enabled *)
interface X7FifoSyncMacro#(numeric type data_width);
   method Bit#(1) empty();
   method Bit#(1) full();
   method Action din(Bit#(data_width) v);
   method Action wren(Bit#(1) wren);
   method Bit#(data_width) dout();
   method Action rden(Bit#(1) rden);
   method Bit#(9) wrcount();
   method Bit#(9) rdcount();
endinterface

import "BVI" FIFO_DUALCLOCK_MACRO =
module  vmkBramFifo#(String fifo_size, Clock wrClock, Reset wrReset, Clock rdClock, Reset rdReset)(X7FifoSyncMacro#(data_width));
`ifndef BSV_POSITIVE_RESET
   let positiveReset <- mkPositiveReset(10, wrReset, wrClock);
   let fifoReset = positiveReset.positiveReset;
`else
   let fifoReset = wrReset;
`endif
   parameter DEVICE = "7SERIES";
   parameter DATA_WIDTH = valueOf(data_width);
   parameter FIFO_SIZE = fifo_size;
   parameter FIRST_WORD_FALL_THROUGH = 1;
   default_clock wrClock(WRCLK) = wrClock;
   no_reset;
   input_reset wrReset(RST) = fifoReset;
   input_clock rdClock(RDCLK) = rdClock;
   method EMPTY empty() clocked_by (rdClock) reset_by (wrReset);
   method FULL full() clocked_by (wrClock) reset_by (wrReset);
   method din(DI) enable ((*inhigh*)EN_di) clocked_by (wrClock) reset_by (wrReset);
   method wren(WREN) enable ((*inhigh*)EN_wren) clocked_by (wrClock) reset_by (wrReset);
   method DO dout() clocked_by (rdClock) reset_by (wrReset);
   method rden(RDEN) enable ((*inhigh*)EN_rden) clocked_by (rdClock) reset_by (wrReset);
   // wrcount and rdcount ports are needed for xsim
   method WRCOUNT wrcount() clocked_by (wrClock) reset_by (wrReset);
   method RDCOUNT rdcount() clocked_by (rdClock) reset_by (wrReset);
   schedule (empty, full, dout, din, wren, rden, wrcount, rdcount) CF (empty, full, dout, din, wren, rden, wrcount, rdcount);
endmodule

module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   String fifo_size = "18Kb";
   Vector#(TDiv#(sizet,36),X7FifoSyncMacro#(36)) fifos <- replicateM(vmkBramFifo(fifo_size, srcClock, srcReset, dstClock, dstReset));
   Wire#(Bit#(1)) rdenWire <- mkDWire(0, clocked_by dstClock, reset_by dstReset);
   Wire#(Bit#(1)) wrenWire <- mkDWire(0, clocked_by srcClock, reset_by srcReset);
   Vector#(TDiv#(sizet,36),Wire#(Bit#(36))) dinWires <- replicateM(mkDWire(0, clocked_by srcClock, reset_by srcReset));

   for (Integer i = 0; i < valueOf(TDiv#(sizet,36)); i = i+1) begin
      Reg#(Bit#(9)) rdcount <- mkReg(0, clocked_by dstClock, reset_by dstReset);
      Reg#(Bit#(9)) wrcount <- mkReg(0, clocked_by srcClock, reset_by srcReset);
      rule rdenRule;
	 fifos[i].rden(rdenWire);
      endrule
      rule wrenRule;
	 fifos[i].wren(wrenWire);
      endrule
      rule inputs;
	 fifos[i].din(dinWires[i]);
      endrule
      rule countrds;
	 rdcount <= fifos[i].rdcount();
      endrule
      rule countwrs;
	 wrcount <= fifos[i].wrcount();
      endrule
   end

   method t first() if (fifos[0].empty == 0);
      function Bit#(36) fifoFirst(Integer i); return fifos[i].dout(); endfunction
      Vector#(TDiv#(sizet,36), Bit#(36)) v = genWith(fifoFirst);
      return unpack(truncateNP(pack(v)));
   endmethod
   method Action deq() if (fifos[0].empty == 0);
      rdenWire <= 1;
   endmethod
   method notEmpty = (fifos[0].empty == 0);
   method Action enq(t v) if (fifos[0].full == 0);
      Vector#(TDiv#(sizet,36), Bit#(36)) vs = unpack(extendNP(pack(v)));
      Vector#(TDiv#(sizet,36), Integer) indices = genVector();
      function Action fifoEnq(Integer i); action dinWires[i] <= vs[i]; endaction endfunction
      mapM_(fifoEnq, indices);
      wrenWire <= 1;
   endmethod
   method notFull = (fifos[0].full == 0);
endmodule

module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkDualClockBramFIFOF(srcClock, srcReset, dstClock, dstReset);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule

`else // compatibility mode
module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
   method notFull = syncFifo.notFull;
   method notEmpty = syncFifo.notEmpty;
endmodule
module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule
`endif

// Copyright (c) 2015 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 Clocks::*;
import Vector::*;
import FIFO::*;
import FIFOF::*;
import BRAMFIFO::*;
import CBus::*; // extendNP and truncateNP

`include "ConnectalProjectConfig.bsv"
import Arith::*;
import ConnectalClocks::*;

`ifndef BSIM
(* always_ready, always_enabled *)
interface X7FifoSyncMacro#(numeric type data_width);
   method Bit#(1) empty();
   method Bit#(1) full();
   method Action din(Bit#(data_width) v);
   method Action wren(Bit#(1) wren);
   method Bit#(data_width) dout();
   method Action rden(Bit#(1) rden);
   method Bit#(9) wrcount();
   method Bit#(9) rdcount();
endinterface

import "BVI" FIFO_DUALCLOCK_MACRO =
module  vmkBramFifo#(String fifo_size, Clock wrClock, Reset wrReset, Clock rdClock, Reset rdReset)(X7FifoSyncMacro#(data_width));
`ifndef BSV_POSITIVE_RESET
   let positiveReset <- mkPositiveReset(10, wrReset, wrClock);
   let fifoReset = positiveReset.positiveReset;
`else
   let fifoReset = wrReset;
`endif
   parameter DEVICE = "7SERIES";
   parameter DATA_WIDTH = valueOf(data_width);
   parameter FIFO_SIZE = fifo_size;
   parameter FIRST_WORD_FALL_THROUGH = 1;
   default_clock wrClock(WRCLK) = wrClock;
   no_reset;
   input_reset wrReset(RST) = fifoReset;
   input_clock rdClock(RDCLK) = rdClock;
   method EMPTY empty() clocked_by (rdClock) reset_by (wrReset);
   method FULL full() clocked_by (wrClock) reset_by (wrReset);
   method din(DI) enable ((*inhigh*)EN_di) clocked_by (wrClock) reset_by (wrReset);
   method wren(WREN) enable ((*inhigh*)EN_wren) clocked_by (wrClock) reset_by (wrReset);
   method DO dout() clocked_by (rdClock) reset_by (wrReset);
   method rden(RDEN) enable ((*inhigh*)EN_rden) clocked_by (rdClock) reset_by (wrReset);
   // wrcount and rdcount ports are needed for xsim
   method WRCOUNT wrcount() clocked_by (wrClock) reset_by (wrReset);
   method RDCOUNT rdcount() clocked_by (rdClock) reset_by (wrReset);
   schedule (empty, full, dout, din, wren, rden, wrcount, rdcount) CF (empty, full, dout, din, wren, rden, wrcount, rdcount);
endmodule

module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   String fifo_size = "18Kb";
   Vector#(TDiv#(sizet,36),X7FifoSyncMacro#(36)) fifos <- replicateM(vmkBramFifo(fifo_size, srcClock, srcReset, dstClock, dstReset));
   Wire#(Bit#(1)) rdenWire <- mkDWire(0, clocked_by dstClock, reset_by dstReset);
   Wire#(Bit#(1)) wrenWire <- mkDWire(0, clocked_by srcClock, reset_by srcReset);
   Vector#(TDiv#(sizet,36),Wire#(Bit#(36))) dinWires <- replicateM(mkDWire(0, clocked_by srcClock, reset_by srcReset));

   for (Integer i = 0; i < valueOf(TDiv#(sizet,36)); i = i+1) begin
      Reg#(Bit#(9)) rdcount <- mkReg(0, clocked_by dstClock, reset_by dstReset);
      Reg#(Bit#(9)) wrcount <- mkReg(0, clocked_by srcClock, reset_by srcReset);
      rule rdenRule;
	 fifos[i].rden(rdenWire);
      endrule
      rule wrenRule;
	 fifos[i].wren(wrenWire);
      endrule
      rule inputs;
	 fifos[i].din(dinWires[i]);
      endrule
      rule countrds;
	 rdcount <= fifos[i].rdcount();
      endrule
      rule countwrs;
	 wrcount <= fifos[i].wrcount();
      endrule
   end

   method t first() if (fifos[0].empty == 0);
      function Bit#(36) fifoFirst(Integer i); return fifos[i].dout(); endfunction
      Vector#(TDiv#(sizet,36), Bit#(36)) v = genWith(fifoFirst);
      return unpack(truncateNP(pack(v)));
   endmethod
   method Action deq() if (fifos[0].empty == 0);
      rdenWire <= 1;
   endmethod
   method notEmpty = (fifos[0].empty == 0);
   method Action enq(t v) if (fifos[0].full == 0);
      Vector#(TDiv#(sizet,36), Bit#(36)) vs = unpack(extendNP(pack(v)));
      Vector#(TDiv#(sizet,36), Integer) indices = genVector();
      function Action fifoEnq(Integer i); action dinWires[i] <= vs[i]; endaction endfunction
      mapM_(fifoEnq, indices);
      wrenWire <= 1;
   endmethod
   method notFull = (fifos[0].full == 0);
endmodule

module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkDualClockBramFIFOF(srcClock, srcReset, dstClock, dstReset);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule

`endif // not BSIM

`ifdef BSIM
module mkDualClockBramFIFOF#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFOF#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));
   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
   method notFull = syncFifo.notFull;
   method notEmpty = syncFifo.notEmpty;
endmodule
module mkDualClockBramFIFO#(Clock srcClock, Reset srcReset, Clock dstClock, Reset dstReset)(FIFO#(t))
   provisos (Bits#(t,sizet),
	     Add#(1,a__,sizet));

   let syncFifo <- mkSyncFIFO(512, srcClock, srcReset, dstClock);
   method enq = syncFifo.enq;
   method deq = syncFifo.deq;
   method first = syncFifo.first;
endmodule
`endif


experimenting with different lwrite and lread fifo size

// Copyright (c) 2015 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::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
import GetPut::*;
import Probe::*;

typedef struct {
   Bit#(8) port_no;
   Bit#(64) data;
} BufData deriving (Bits, Eq);

interface DtpIfc;
   interface PipeIn#(Bit#(128)) timestamp; // streaming time counter from NetTop.
   interface Vector#(4, PipeOut#(Bit#(53))) fromHost;
   interface Vector#(4, PipeIn#(Bit#(53)))  toHost;
   interface Vector#(4, PipeIn#(Bit#(32)))  delay;
   interface Vector#(4, PipeIn#(Bit#(32)))  state;
   interface Vector#(4, PipeIn#(Bit#(64)))  jumpCount;
   interface Vector#(4, PipeIn#(Bit#(53)))  cLocal;
   interface PipeIn#(Bit#(53)) globalOut;
   interface Vector#(4, PipeOut#(Bit#(32))) interval;
   interface Reset rst;
   interface PipeIn#(Bit#(1)) isSwitch;
endinterface

interface SonicUserRequest;
   method Action dtp_read_version();
   method Action dtp_reset(Bit#(32) len);
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
   method Action dtp_read_delay(Bit#(8) port_no);
   method Action dtp_read_state(Bit#(8) port_no);
   method Action dtp_read_error(Bit#(8) port_no);
   method Action dtp_read_cnt(Bit#(8) cmd);
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) local_cnt);
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
   method Action dtp_read_local_cnt(Bit#(8) port_no);
   method Action dtp_read_global_cnt();
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
/* NOT IMPLEMENTED YET.
   method Action dtp_ctrl_disable();
   method Action dtp_ctrl_enable();
*/
endinterface

interface SonicUserIndication;
   method Action dtp_read_version_resp(Bit#(32) version);
   method Action dtp_read_delay_resp(Bit#(8) port_no, Bit#(32) delay);
   method Action dtp_read_state_resp(Bit#(8) port_no, Bit#(32) state);
   method Action dtp_read_error_resp(Bit#(8) port_no, Bit#(64) jumpc);
   method Action dtp_read_cnt_resp(Bit#(64) val);
   method Action dtp_logger_read_cnt_resp(Bit#(8) port_no, Bit#(64) localc, Bit#(64) msg1, Bit#(64) msg2);
   method Action dtp_read_local_cnt_resp(Bit#(8) port_no, Bit#(64) val);
   method Action dtp_read_global_cnt_resp(Bit#(64) val);
   method Action dtp_read_beacon_interval_resp(Bit#(8) port_no, Bit#(32) interval);
endinterface

interface SonicUser;
   interface SonicUserRequest request;
   interface DtpIfc           dtp;
endinterface

module mkSonicUser#(SonicUserIndication indication)(SonicUser);
   let verbose = False;
   Clock defaultClock <- exposeCurrentClock();

   Reg#(Bit#(64))  cycle_count <- mkReg(0);
   Reg#(Bit#(64))  last_count  <- mkReg(0);

   FIFOF#(Bit#(128)) cntFifo <- mkFIFOF();
   Reg#(Bit#(128))   cycle_reg <- mkReg(0);
   Reg#(Bit#(1))     isSwitch_reg <- mkReg(0);
   Vector#(4, Reg#(Bit#(32))) beacon_interval <- replicateM(mkReg(1000)); //default beacon interval is 1000.

   Vector#(4, FIFOF#(Bit#(53))) fromHostFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) toHostFifo   <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) delayFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) stateFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(64))) jumpCountFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) cLocalFifo   <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(53)) cGlobalFifo <- mkSizedFIFOF(4);
   Vector#(4, FIFOF#(Bit#(32))) intervalFifo <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(1)) isSwitchFifo <- mkFIFOF();

   Reg#(Bit#(8))  lwrite_port <- mkReg(0);
   FIFOF#(BufData) lwrite_data_cycle1 <- mkSizedFIFOF(2);
   FIFOF#(BufData) lwrite_data_cycle2 <- mkSizedFIFOF(2);
   FIFOF#(void) log_write_cf <- mkFIFOF;

   Vector#(4, FIFOF#(BufData)) lread_data_cycle1 <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(BufData)) lread_data_cycle2 <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) lread_data_timestamp <- replicateM(mkSizedFIFOF(4));

   Reg#(Bit#(28)) dtp_rst_cntr <- mkReg(0);
   MakeResetIfc dtpResetOut <- mkResetSync(0, False, defaultClock);

   rule count;
      cycle_count <= cycle_count + 1;
   endrule

   // clear all fifo on reset
   rule clearOnReset(dtpResetOut.isAsserted);
      for (Integer i=0; i<4; i=i+1) begin
         fromHostFifo[i].clear();
         toHostFifo[i].clear();
         delayFifo[i].clear();
         stateFifo[i].clear();
         jumpCountFifo[i].clear();
         cLocalFifo[i].clear();
         intervalFifo[i].clear();
         lread_data_cycle1[i].clear();
         lread_data_cycle2[i].clear();
         lread_data_timestamp[i].clear();
      end
      cGlobalFifo.clear();
      cntFifo.clear();
      lwrite_data_cycle1.clear();
      lwrite_data_cycle2.clear();
      log_write_cf.clear();
   endrule

   // dtp_read_cnt
   rule snapshot_dtp_timestamp;
      let v <- toGet(cntFifo).get;
      cycle_reg <= v;
   endrule

   // dtp_read_delay
   Vector#(4, Reg#(Bit#(32))) delay_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_delay;
         let v <- toGet(delayFifo[i]).get;
         delay_reg[i] <= v;
      endrule
   end

   // dtp_read_state
   Vector#(4, Reg#(Bit#(32))) state_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_state;
         let v <- toGet(stateFifo[i]).get;
         state_reg[i] <= v;
      endrule
   end

   // dtp_read_error
   Vector#(4, Reg#(Bit#(64))) jumpc_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_jumpc;
         let v <- toGet(jumpCountFifo[i]).get;
         jumpc_reg[i] <= v;
      endrule
   end

   // dtp_read_local_cnt
   Vector#(4, Reg#(Bit#(53))) clocal_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_clocal;
         let v <- toGet(cLocalFifo[i]).get;
         clocal_reg[i] <= v;
      endrule
   end

   // dtp_read_global_cnt
   Reg#(Bit#(53)) cglobal_reg <- mkReg(0);
   rule snapshot_cglobal;
      let v <- toGet(cGlobalFifo).get;
      cglobal_reg <= v;
   endrule

   // dtp_set_interval
   for (Integer i=0; i<4; i=i+1) begin
      rule set_interval;
         let v = beacon_interval[i];
         intervalFifo[i].enq(v);
      endrule
   end

   Integer chunk_a = 0;
   Integer chunk_b = 1;
   function Bit#(2) toState(Integer st);
      return (1<<st);
   endfunction

   Reg#(Bit#(2)) lwstate <- mkReg(toState(chunk_a));
   // dtp_logger_write_cnt
   rule log_from_host_cycle;
      if ((lwstate[chunk_a] == 1) && lwrite_data_cycle1.notEmpty) begin
         let v1 = lwrite_data_cycle1.first;
         if (fromHostFifo[v1.port_no].notFull) begin
            fromHostFifo[v1.port_no].enq({1'b0, truncate(v1.data)});
            lwrite_data_cycle1.deq;
            lwstate <= toState(chunk_b);
         end
      end
      else if((lwstate[chunk_b] == 1) && lwrite_data_cycle2.notEmpty) begin
         let v2 = lwrite_data_cycle2.first;
         if (fromHostFifo[v2.port_no].notFull) begin
            fromHostFifo[v2.port_no].enq({1'b1, truncate(v2.data)});
            lwrite_data_cycle2.deq;
            lwstate <= toState(chunk_a);
         end
      end
   endrule

   for (Integer i=0; i<4; i=i+1) begin
      rule save_host_data (toHostFifo[i].notEmpty);
         Bit#(53) v = toHostFifo[i].first;
         case (v[52]) matches
            0: begin
               lread_data_cycle1[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
            end
            1: begin
               lread_data_cycle2[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
               Bit#(53) timestamp = 0;
               if (isSwitch_reg == 0) begin // 0 for NIC, 1 for Switch
                  timestamp = clocal_reg[i];
               end
               else begin
                  timestamp = cglobal_reg;
               end
               lread_data_timestamp[i].enq(timestamp);
            end
         endcase
         toHostFifo[i].deq;
      endrule
   end

   rule assert_reset (dtp_rst_cntr > 0);
      dtpResetOut.assertReset;
      dtp_rst_cntr <= dtp_rst_cntr - 1;
   endrule

   rule switch_mode;
      let v <- toGet(isSwitchFifo).get;
      isSwitch_reg <= v;
   endrule

   // Interface to external modules.
   interface dtp = (interface DtpIfc;
      interface timestamp = toPipeIn(cntFifo);
      interface delay     = map(toPipeIn, delayFifo);
      interface state     = map(toPipeIn, stateFifo);
      interface jumpCount = map(toPipeIn, jumpCountFifo);
      interface toHost    = map(toPipeIn, toHostFifo);
      interface fromHost  = map(toPipeOut, fromHostFifo);
      interface cLocal    = map(toPipeIn, cLocalFifo);
      interface globalOut = toPipeIn(cGlobalFifo);
      interface interval  = map(toPipeOut, intervalFifo);
      interface rst       = dtpResetOut.new_rst;
      interface isSwitch  = toPipeIn(isSwitchFifo);
   endinterface);

   // API implementation
   interface SonicUserRequest request;
   method Action dtp_read_version();
      let v = `DtpVersion; //Defined in Makefile as time of compilation.
      indication.dtp_read_version_resp(v);
   endmethod
   method Action dtp_reset(Bit#(32) len) if (dtp_rst_cntr == 0);
      Bit#(28) limit = truncate(len) & 28'hFFFFFFF;
      if (limit < 32) begin
         limit = 32;
      end
      dtp_rst_cntr <= limit;
   endmethod
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
      //
   endmethod
   method Action dtp_read_delay(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_delay_resp(port_no, truncate(delay_reg[port_no]));
      end
   endmethod
   method Action dtp_read_state(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_state_resp(port_no, state_reg[port_no]);
      end
   endmethod
   method Action dtp_read_error(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_error_resp(port_no, jumpc_reg[port_no]);
      end
   endmethod
   method Action dtp_read_cnt(Bit#(8) port_no);
      indication.dtp_read_cnt_resp(truncate(cycle_reg));
   endmethod
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) host_timestamp);
      // Check valid port No.
      if (port_no < 4) begin
         lwrite_data_cycle1.enq(BufData{port_no: port_no, data: host_timestamp});
         lwrite_data_cycle2.enq(BufData{port_no: port_no, data: zeroExtend(clocal_reg[port_no])});
      end
   endmethod
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         if (lread_data_cycle1[port_no].notEmpty && lread_data_cycle2[port_no].notEmpty) begin
            Bit#(64) remote_message1 = lread_data_cycle1[port_no].first.data;
            Bit#(64) remote_message2 = lread_data_cycle2[port_no].first.data;
            Bit#(53) timestamp = lread_data_timestamp[port_no].first;
            indication.dtp_logger_read_cnt_resp(port_no,
                                                zeroExtend(timestamp),
                                                zeroExtend(remote_message1),
                                                zeroExtend(remote_message2));
            lread_data_cycle1[port_no].deq;
            lread_data_cycle2[port_no].deq;
            lread_data_timestamp[port_no].deq;
         end
      end
   endmethod
   method Action dtp_read_local_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_local_cnt_resp(port_no, zeroExtend(clocal_reg[port_no]));
      end
   endmethod
   method Action dtp_read_global_cnt();
      indication.dtp_read_global_cnt_resp(zeroExtend(cglobal_reg));
   endmethod
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
      if (port_no < 4) begin
         beacon_interval[port_no] <= interval;
      end
   endmethod
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_beacon_interval_resp(port_no, beacon_interval[port_no]);
      end
   endmethod
   endinterface
endmodule

// Copyright (c) 2015 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::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import Pipe::*;
import GetPut::*;
import Probe::*;

typedef struct {
   Bit#(8) port_no;
   Bit#(64) data;
} BufData deriving (Bits, Eq);

interface DtpIfc;
   interface PipeIn#(Bit#(128)) timestamp; // streaming time counter from NetTop.
   interface Vector#(4, PipeOut#(Bit#(53))) fromHost;
   interface Vector#(4, PipeIn#(Bit#(53)))  toHost;
   interface Vector#(4, PipeIn#(Bit#(32)))  delay;
   interface Vector#(4, PipeIn#(Bit#(32)))  state;
   interface Vector#(4, PipeIn#(Bit#(64)))  jumpCount;
   interface Vector#(4, PipeIn#(Bit#(53)))  cLocal;
   interface PipeIn#(Bit#(53)) globalOut;
   interface Vector#(4, PipeOut#(Bit#(32))) interval;
   interface Reset rst;
   interface PipeIn#(Bit#(1)) isSwitch;
endinterface

interface SonicUserRequest;
   method Action dtp_read_version();
   method Action dtp_reset(Bit#(32) len);
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
   method Action dtp_read_delay(Bit#(8) port_no);
   method Action dtp_read_state(Bit#(8) port_no);
   method Action dtp_read_error(Bit#(8) port_no);
   method Action dtp_read_cnt(Bit#(8) cmd);
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) local_cnt);
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
   method Action dtp_read_local_cnt(Bit#(8) port_no);
   method Action dtp_read_global_cnt();
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
/* NOT IMPLEMENTED YET.
   method Action dtp_ctrl_disable();
   method Action dtp_ctrl_enable();
*/
endinterface

interface SonicUserIndication;
   method Action dtp_read_version_resp(Bit#(32) version);
   method Action dtp_read_delay_resp(Bit#(8) port_no, Bit#(32) delay);
   method Action dtp_read_state_resp(Bit#(8) port_no, Bit#(32) state);
   method Action dtp_read_error_resp(Bit#(8) port_no, Bit#(64) jumpc);
   method Action dtp_read_cnt_resp(Bit#(64) val);
   method Action dtp_logger_read_cnt_resp(Bit#(8) port_no, Bit#(64) localc, Bit#(64) msg1, Bit#(64) msg2);
   method Action dtp_read_local_cnt_resp(Bit#(8) port_no, Bit#(64) val);
   method Action dtp_read_global_cnt_resp(Bit#(64) val);
   method Action dtp_read_beacon_interval_resp(Bit#(8) port_no, Bit#(32) interval);
endinterface

interface SonicUser;
   interface SonicUserRequest request;
   interface DtpIfc           dtp;
endinterface

module mkSonicUser#(SonicUserIndication indication)(SonicUser);
   let verbose = False;
   Clock defaultClock <- exposeCurrentClock();

   Reg#(Bit#(64))  cycle_count <- mkReg(0);
   Reg#(Bit#(64))  last_count  <- mkReg(0);

   FIFOF#(Bit#(128)) cntFifo <- mkFIFOF();
   Reg#(Bit#(128))   cycle_reg <- mkReg(0);
   Reg#(Bit#(1))     isSwitch_reg <- mkReg(0);
   Vector#(4, Reg#(Bit#(32))) beacon_interval <- replicateM(mkReg(1000)); //default beacon interval is 1000.

   Vector#(4, FIFOF#(Bit#(53))) fromHostFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) toHostFifo   <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) delayFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(32))) stateFifo    <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(64))) jumpCountFifo <- replicateM(mkSizedFIFOF(4));
   Vector#(4, FIFOF#(Bit#(53))) cLocalFifo   <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(53)) cGlobalFifo <- mkSizedFIFOF(4);
   Vector#(4, FIFOF#(Bit#(32))) intervalFifo <- replicateM(mkSizedFIFOF(4));
   FIFOF#(Bit#(1)) isSwitchFifo <- mkFIFOF();

   Reg#(Bit#(8))  lwrite_port <- mkReg(0);
   FIFOF#(BufData) lwrite_data_cycle1 <- mkSizedFIFOF(8);
   FIFOF#(BufData) lwrite_data_cycle2 <- mkSizedFIFOF(8);
   FIFOF#(void) log_write_cf <- mkFIFOF;

   Vector#(4, FIFOF#(BufData)) lread_data_cycle1 <- replicateM(mkSizedFIFOF(8));
   Vector#(4, FIFOF#(BufData)) lread_data_cycle2 <- replicateM(mkSizedFIFOF(8));
   Vector#(4, FIFOF#(Bit#(53))) lread_data_timestamp <- replicateM(mkSizedFIFOF(8));

   Reg#(Bit#(28)) dtp_rst_cntr <- mkReg(0);
   MakeResetIfc dtpResetOut <- mkResetSync(0, False, defaultClock);

   rule count;
      cycle_count <= cycle_count + 1;
   endrule

   // clear all fifo on reset
   rule clearOnReset(dtpResetOut.isAsserted);
      for (Integer i=0; i<4; i=i+1) begin
         fromHostFifo[i].clear();
         toHostFifo[i].clear();
         delayFifo[i].clear();
         stateFifo[i].clear();
         jumpCountFifo[i].clear();
         cLocalFifo[i].clear();
         intervalFifo[i].clear();
         lread_data_cycle1[i].clear();
         lread_data_cycle2[i].clear();
         lread_data_timestamp[i].clear();
      end
      cGlobalFifo.clear();
      cntFifo.clear();
      lwrite_data_cycle1.clear();
      lwrite_data_cycle2.clear();
      log_write_cf.clear();
   endrule

   // dtp_read_cnt
   rule snapshot_dtp_timestamp;
      let v <- toGet(cntFifo).get;
      cycle_reg <= v;
   endrule

   // dtp_read_delay
   Vector#(4, Reg#(Bit#(32))) delay_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_delay;
         let v <- toGet(delayFifo[i]).get;
         delay_reg[i] <= v;
      endrule
   end

   // dtp_read_state
   Vector#(4, Reg#(Bit#(32))) state_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_state;
         let v <- toGet(stateFifo[i]).get;
         state_reg[i] <= v;
      endrule
   end

   // dtp_read_error
   Vector#(4, Reg#(Bit#(64))) jumpc_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_jumpc;
         let v <- toGet(jumpCountFifo[i]).get;
         jumpc_reg[i] <= v;
      endrule
   end

   // dtp_read_local_cnt
   Vector#(4, Reg#(Bit#(53))) clocal_reg <- replicateM(mkReg(0));
   for (Integer i=0; i<4; i=i+1) begin
      rule snapshot_clocal;
         let v <- toGet(cLocalFifo[i]).get;
         clocal_reg[i] <= v;
      endrule
   end

   // dtp_read_global_cnt
   Reg#(Bit#(53)) cglobal_reg <- mkReg(0);
   rule snapshot_cglobal;
      let v <- toGet(cGlobalFifo).get;
      cglobal_reg <= v;
   endrule

   // dtp_set_interval
   for (Integer i=0; i<4; i=i+1) begin
      rule set_interval;
         let v = beacon_interval[i];
         intervalFifo[i].enq(v);
      endrule
   end

   Integer chunk_a = 0;
   Integer chunk_b = 1;
   function Bit#(2) toState(Integer st);
      return (1<<st);
   endfunction

   Reg#(Bit#(2)) lwstate <- mkReg(toState(chunk_a));
   // dtp_logger_write_cnt
   rule log_from_host_cycle;
      if ((lwstate[chunk_a] == 1) && lwrite_data_cycle1.notEmpty) begin
         let v1 = lwrite_data_cycle1.first;
         if (fromHostFifo[v1.port_no].notFull) begin
            fromHostFifo[v1.port_no].enq({1'b0, truncate(v1.data)});
            lwrite_data_cycle1.deq;
            lwstate <= toState(chunk_b);
         end
      end
      else if((lwstate[chunk_b] == 1) && lwrite_data_cycle2.notEmpty) begin
         let v2 = lwrite_data_cycle2.first;
         if (fromHostFifo[v2.port_no].notFull) begin
            fromHostFifo[v2.port_no].enq({1'b1, truncate(v2.data)});
            lwrite_data_cycle2.deq;
            lwstate <= toState(chunk_a);
         end
      end
   endrule

   for (Integer i=0; i<4; i=i+1) begin
      rule save_host_data (toHostFifo[i].notEmpty);
         Bit#(53) v = toHostFifo[i].first;
         case (v[52]) matches
            0: begin
               lread_data_cycle1[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
            end
            1: begin
               lread_data_cycle2[i].enq(BufData{port_no:fromInteger(i), data:zeroExtend(v[51:0])});
               Bit#(53) timestamp = 0;
               if (isSwitch_reg == 0) begin // 0 for NIC, 1 for Switch
                  timestamp = clocal_reg[i];
               end
               else begin
                  timestamp = cglobal_reg;
               end
               lread_data_timestamp[i].enq(timestamp);
            end
         endcase
         toHostFifo[i].deq;
      endrule
   end

   rule assert_reset (dtp_rst_cntr > 0);
      dtpResetOut.assertReset;
      dtp_rst_cntr <= dtp_rst_cntr - 1;
   endrule

   rule switch_mode;
      let v <- toGet(isSwitchFifo).get;
      isSwitch_reg <= v;
   endrule

   // Interface to external modules.
   interface dtp = (interface DtpIfc;
      interface timestamp = toPipeIn(cntFifo);
      interface delay     = map(toPipeIn, delayFifo);
      interface state     = map(toPipeIn, stateFifo);
      interface jumpCount = map(toPipeIn, jumpCountFifo);
      interface toHost    = map(toPipeIn, toHostFifo);
      interface fromHost  = map(toPipeOut, fromHostFifo);
      interface cLocal    = map(toPipeIn, cLocalFifo);
      interface globalOut = toPipeIn(cGlobalFifo);
      interface interval  = map(toPipeOut, intervalFifo);
      interface rst       = dtpResetOut.new_rst;
      interface isSwitch  = toPipeIn(isSwitchFifo);
   endinterface);

   // API implementation
   interface SonicUserRequest request;
   method Action dtp_read_version();
      let v = `DtpVersion; //Defined in Makefile as time of compilation.
      indication.dtp_read_version_resp(v);
   endmethod
   method Action dtp_reset(Bit#(32) len) if (dtp_rst_cntr == 0);
      Bit#(28) limit = truncate(len) & 28'hFFFFFFF;
      if (limit < 32) begin
         limit = 32;
      end
      dtp_rst_cntr <= limit;
   endmethod
   method Action dtp_set_cnt(Bit#(8) port_no, Bit#(64) c);
      //
   endmethod
   method Action dtp_read_delay(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_delay_resp(port_no, truncate(delay_reg[port_no]));
      end
   endmethod
   method Action dtp_read_state(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_state_resp(port_no, state_reg[port_no]);
      end
   endmethod
   method Action dtp_read_error(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_error_resp(port_no, jumpc_reg[port_no]);
      end
   endmethod
   method Action dtp_read_cnt(Bit#(8) port_no);
      indication.dtp_read_cnt_resp(truncate(cycle_reg));
   endmethod
   method Action dtp_logger_write_cnt(Bit#(8) port_no, Bit#(64) host_timestamp);
      // Check valid port No.
      if (port_no < 4) begin
         lwrite_data_cycle1.enq(BufData{port_no: port_no, data: host_timestamp});
         lwrite_data_cycle2.enq(BufData{port_no: port_no, data: zeroExtend(clocal_reg[port_no])});
      end
   endmethod
   method Action dtp_logger_read_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         if (lread_data_cycle1[port_no].notEmpty && lread_data_cycle2[port_no].notEmpty) begin
            Bit#(64) remote_message1 = lread_data_cycle1[port_no].first.data;
            Bit#(64) remote_message2 = lread_data_cycle2[port_no].first.data;
            Bit#(53) timestamp = lread_data_timestamp[port_no].first;
            indication.dtp_logger_read_cnt_resp(port_no,
                                                zeroExtend(timestamp),
                                                zeroExtend(remote_message1),
                                                zeroExtend(remote_message2));
            lread_data_cycle1[port_no].deq;
            lread_data_cycle2[port_no].deq;
            lread_data_timestamp[port_no].deq;
         end
      end
   endmethod
   method Action dtp_read_local_cnt(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_local_cnt_resp(port_no, zeroExtend(clocal_reg[port_no]));
      end
   endmethod
   method Action dtp_read_global_cnt();
      indication.dtp_read_global_cnt_resp(zeroExtend(cglobal_reg));
   endmethod
   method Action dtp_set_beacon_interval(Bit#(8) port_no, Bit#(32) interval);
      if (port_no < 4) begin
         beacon_interval[port_no] <= interval;
      end
   endmethod
   method Action dtp_read_beacon_interval(Bit#(8) port_no);
      if (port_no < 4) begin
         indication.dtp_read_beacon_interval_resp(port_no, beacon_interval[port_no]);
      end
   endmethod
   endinterface
endmodule


use an EHR to squash the reg write shadowing warnings

// 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.

// BSV Libraries
import BRAMFIFO::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import BRAM::*;
import RegFile::*;
import EHR::*;

// CONNECTAL Libraries
import MemTypes::*;
import ConnectalMemory::*;
import ConfigCounter::*;

interface TagGen#(numeric type numTags);
   method ActionValue#(Bit#(TLog#(numTags))) getTag;
   method Action returnTag(Bit#(TLog#(numTags)) tag);
   method ActionValue#(Bit#(TLog#(numTags))) complete;
endinterface

//(* synthesize *)
module mkTagEHR (EHR2BSV#(Bit#(numTags)));
   EHR#(2,Bit#(numTags)) ehr <- mkEHR(0);
   interface r1 = ehr[0];
   interface r2 = ehr[1];
endmodule

module mkTagGen(TagGen#(numTags))
   provisos(Log#(numTags,tsz));

   BRAM_Configure cfg = defaultValue;
   cfg.outFIFODepth = 1;
   //BRAM2Port#(Bit#(tsz),Bool) tags <- mkBRAM2Server(cfg);
   //Vector#(numTags, Reg#(Bool)) tags <- replicateM(mkReg(False));
   EHR2BSV#(Bit#(numTags)) tags <- mkTagEHR();
   Reg#(Bit#(tsz))        head_ptr <- mkReg(0);
   Reg#(Bit#(tsz))        tail_ptr <- mkReg(0);
   Reg#(Bool)               inited <- mkReg(False);
   FIFO#(Bit#(tsz))      comp_fifo <- mkFIFO;
   Reg#(Bit#(numTags))  comp_state <- mkReg(0);
   ConfigCounter#(TAdd#(tsz,1)) counter <- mkConfigCounter(fromInteger(valueOf(numTags)));

   let retFifo <- mkFIFO;
   let tagFifo <- mkFIFO;

   //rule complete_rule0 (comp_state[0] != 0);
      //tags.portB.request.put(BRAMRequest{write:False, address:tail_ptr, datain: ?, responseOnWrite: ?});
   //endrule

   rule complete_rule1 (comp_state[0] != 0);
      //let rv <- tags.portB.response.get;
      //let rv = tags[tail_ptr];
      let rv = tags.r2[tail_ptr] == 1;
      if (!rv) begin
	 tail_ptr <= tail_ptr+1;
	 counter.increment(1);
	 comp_state <= comp_state >> 1;
	 comp_fifo.enq(tail_ptr);
      end
   endrule

   // this used to be in the body of returnTag, but form some reason bsc does not
   // consider access to portA and portB to be conflict free **sigh**
   (* descending_urgency = "ret_rule, complete_rule1" *)
   rule ret_rule;
      let tag <- toGet(retFifo).get;
      //tags.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tag, datain:False});
      //tags[tag] <= False;
      begin
	 let t = tags.r1;
	 t[tag] = 0;
	 tags.r1 <= t;
      end
      comp_state <= 1 | (comp_state << 1);
   endrule

   rule init_rule(!inited);
      //tags.portA.request.put(BRAMRequest{write:True,address:head_ptr,responseOnWrite:False,datain:False});
      //Not needed: tags[head_ptr] <= False;
      head_ptr <= head_ptr+1;
      inited <= head_ptr+1==0;
   endrule

   rule tag_rule if (inited && counter.positive);
      //tags.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head_ptr, datain:True});
      //tags[head_ptr] <= True;
      begin
	 let t = tags.r2;
	 t[head_ptr] = 1;
	 tags.r2 <= t;
      end
      head_ptr <= head_ptr+1;
      tagFifo.enq(head_ptr);
      counter.decrement(1);
   endrule

   method ActionValue#(Bit#(tsz)) getTag();
      let tag <- toGet(tagFifo).get();
      return tag;
   endmethod

   method Action returnTag(Bit#(tsz) tag) if (inited);
      retFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(tsz)) complete;
      comp_fifo.deq;
      return comp_fifo.first;
   endmethod

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.

// BSV Libraries
import BRAMFIFO::*;
import FIFO::*;
import FIFOF::*;
import Vector::*;
import GetPut::*;
import ClientServer::*;
import Assert::*;
import BRAM::*;
import RegFile::*;

// CONNECTAL Libraries
import MemTypes::*;
import ConnectalMemory::*;
import ConfigCounter::*;

interface TagGen#(numeric type numTags);
   method ActionValue#(Bit#(TLog#(numTags))) getTag;
   method Action returnTag(Bit#(TLog#(numTags)) tag);
   method ActionValue#(Bit#(TLog#(numTags))) complete;
endinterface

module mkTagGen(TagGen#(numTags))
   provisos(Log#(numTags,tsz));

   BRAM_Configure cfg = defaultValue;
   cfg.outFIFODepth = 1;
   //BRAM2Port#(Bit#(tsz),Bool) tags <- mkBRAM2Server(cfg);
   Vector#(numTags, Reg#(Bool)) tags <- replicateM(mkReg(False));
   //RegFile#(Bit#(tsz),Bool)     tags <- mkRegFile(0, fromInteger(valueOf(numTags)-1));
   Reg#(Bit#(tsz))        head_ptr <- mkReg(0);
   Reg#(Bit#(tsz))        tail_ptr <- mkReg(0);
   Reg#(Bool)               inited <- mkReg(False);
   FIFO#(Bit#(tsz))      comp_fifo <- mkFIFO;
   Reg#(Bit#(numTags))  comp_state <- mkReg(0);
   ConfigCounter#(TAdd#(tsz,1)) counter <- mkConfigCounter(fromInteger(valueOf(numTags)));

   let retFifo <- mkFIFO;
   let tagFifo <- mkFIFO;

   //rule complete_rule0 (comp_state[0] != 0);
      //tags.portB.request.put(BRAMRequest{write:False, address:tail_ptr, datain: ?, responseOnWrite: ?});
   //endrule

   rule complete_rule1 (comp_state[0] != 0);
      //let rv <- tags.portB.response.get;
      //let rv = tags.sub(tail_ptr);
      let rv = tags[tail_ptr];
      if (!rv) begin
	 tail_ptr <= tail_ptr+1;
	 counter.increment(1);
	 comp_state <= comp_state >> 1;
	 comp_fifo.enq(tail_ptr);
      end
   endrule

   // this used to be in the body of returnTag, but form some reason bsc does not
   // consider access to portA and portB to be conflict free **sigh**
   (* descending_urgency = "ret_rule, complete_rule1" *)
   rule ret_rule;
      let tag <- toGet(retFifo).get;
      //tags.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:tag, datain:False});
      //tags.upd(tag, False);
      tags[tag] <= False;
      comp_state <= 1 | (comp_state << 1);
   endrule

   rule init_rule(!inited);
      //tags.portA.request.put(BRAMRequest{write:True,address:head_ptr,responseOnWrite:False,datain:False});
      //tags.upd(head_ptr, False);
      //Not needed: tags[head_ptr] <= False;
      head_ptr <= head_ptr+1;
      inited <= head_ptr+1==0;
   endrule

   rule tag_rule if (inited && counter.positive);
      //tags.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, address:head_ptr, datain:True});
      //tags.upd(head_ptr, True);
      tags[head_ptr] <= True;
      head_ptr <= head_ptr+1;
      tagFifo.enq(head_ptr);
      counter.decrement(1);
   endrule

   method ActionValue#(Bit#(tsz)) getTag();
      let tag <- toGet(tagFifo).get();
      return tag;
   endmethod

   method Action returnTag(Bit#(tsz) tag) if (inited);
      retFifo.enq(tag);
   endmethod

   method ActionValue#(Bit#(tsz)) complete;
      comp_fifo.deq;
      return comp_fifo.first;
   endmethod

endmodule