TestBench: Support DCT32 pipeline test

TestBench: Support DCT32 pipeline test

// Copyright (c) 2016 Min Chen
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import Vector::*;
import GetPut::*;
import Connectable::*;
import ConfigReg::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BUtils::*;
import BRAMCore::*;
import SMul::*;

Integer g_t32[32][16] =
{
    { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
    { 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13,  4 },
    { 90, 87, 80, 70, 57, 43, 25,  9, -9,-25,-43,-57,-70,-80,-87,-90 },
    { 90, 82, 67, 46, 22, -4,-31,-54,-73,-85,-90,-88,-78,-61,-38,-13 },
    { 89, 75, 50, 18,-18,-50,-75,-89,-89,-75,-50,-18, 18, 50, 75, 89 },
    { 88, 67, 31,-13,-54,-82,-90,-78,-46, -4, 38, 73, 90, 85, 61, 22 },
    { 87, 57,  9,-43,-80,-90,-70,-25, 25, 70, 90, 80, 43, -9,-57,-87 },
    { 85, 46,-13,-67,-90,-73,-22, 38, 82, 88, 54, -4,-61,-90,-78,-31 },
    { 83, 36,-36,-83,-83,-36, 36, 83, 83, 36,-36,-83,-83,-36, 36, 83 },
    { 82, 22,-54,-90,-61, 13, 78, 85, 31,-46,-90,-67,  4, 73, 88, 38 },
    { 80,  9,-70,-87,-25, 57, 90, 43,-43,-90,-57, 25, 87, 70, -9,-80 },
    { 78, -4,-82,-73, 13, 85, 67,-22,-88,-61, 31, 90, 54,-38,-90,-46 },
    { 75,-18,-89,-50, 50, 89, 18,-75,-75, 18, 89, 50,-50,-89,-18, 75 },
    { 73,-31,-90,-22, 78, 67,-38,-90,-13, 82, 61,-46,-88, -4, 85, 54 },
    { 70,-43,-87,  9, 90, 25,-80,-57, 57, 80,-25,-90, -9, 87, 43,-70 },
    { 67,-54,-78, 38, 85,-22,-90,  4, 90, 13,-88,-31, 82, 46,-73,-61 },
    { 64,-64,-64, 64, 64,-64,-64, 64, 64,-64,-64, 64, 64,-64,-64, 64 },
    { 61,-73,-46, 82, 31,-88,-13, 90, -4,-90, 22, 85,-38,-78, 54, 67 },
    { 57,-80,-25, 90, -9,-87, 43, 70,-70,-43, 87,  9,-90, 25, 80,-57 },
    { 54,-85, -4, 88,-46,-61, 82, 13,-90, 38, 67,-78,-22, 90,-31,-73 },
    { 50,-89, 18, 75,-75,-18, 89,-50,-50, 89,-18,-75, 75, 18,-89, 50 },
    { 46,-90, 38, 54,-90, 31, 61,-88, 22, 67,-85, 13, 73,-82,  4, 78 },
    { 43,-90, 57, 25,-87, 70,  9,-80, 80, -9,-70, 87,-25,-57, 90,-43 },
    { 38,-88, 73, -4,-67, 90,-46,-31, 85,-78, 13, 61,-90, 54, 22,-82 },
    { 36,-83, 83,-36,-36, 83,-83, 36, 36,-83, 83,-36,-36, 83,-83, 36 },
    { 31,-78, 90,-61,  4, 54,-88, 82,-38,-22, 73,-90, 67,-13,-46, 85 },
    { 25,-70, 90,-80, 43,  9,-57, 87,-87, 57, -9,-43, 80,-90, 70,-25 },
    { 22,-61, 85,-90, 73,-38, -4, 46,-78, 90,-82, 54,-13,-31, 67,-88 },
    { 18,-50, 75,-89, 89,-75, 50,-18,-18, 50,-75, 89,-89, 75,-50, 18 },
    { 13,-38, 61,-78, 88,-90, 85,-73, 54,-31,  4, 22,-46, 67,-82, 90 },
    {  9,-25, 43,-57, 70,-80, 87,-90, 90,-87, 80,-70, 57,-43, 25, -9 },
    {  4,-13, 22,-31, 38,-46, 54,-61, 67,-73, 78,-82, 85,-88, 90,-90 }
};

interface IDct32;
   interface Put#(Vector#(2, Vector#(32, Bit#(9)))) io_in;
   interface Get#(Vector#(4, Bit#(16))) io_out;
endinterface

interface IDct32Core#(numeric type a);
   method Bit#(16) dct(Vector#(16, Bit#(a)) x, Bit#(5) idx);
endinterface

module mkDct32Core(IDct32Core#(a))
   provisos(
      Add#(_x, 9, a),
      Add#(0, 8, b),
      Add#(1, c, TAdd#(a, b)),
      Add#(c, 1, c1),
      Add#(c, 2, c2),
      Add#(a, 10/*(5-1+6)*/, bs),
      Add#(shift, 16, bs),
      Add#(0, TExp#(TSub#(shift, 1)), round)
   );

   Vector#(16, SMUL#(a,b)) smul <- replicateM(mkSMUL);

   method Bit#(16) dct(Vector#(16, Bit#(a)) x, Bit#(5) idx);
      Bit#(c) x0[16];
      for(Integer i = 0; i < 16; i = i + 1)
         x0[i] = smul[i].c(x[i], fromInteger(g_t32[idx][i]));

      Bit#(c1) x1[8];
      for(Integer i = 0; i < 8; i = i + 1)
         x1[i] = sExtend(x0[2 * i + 0]) + sExtend(x0[2 * i + 1]);

      Bit#(c2) x2[4];
      for(Integer i = 0; i < 4; i = i + 1)
         x2[i] = sExtend(x1[2 * i + 0]) + sExtend(x1[2 * i + 1]);

      Bit#(bs) x3[2];
      for(Integer i = 0; i < 2; i = i + 1)
         x3[i] = sExtend(x2[2 * i + 0]) + sExtend(x2[2 * i + 1]);

      Bit#(bs) sum = sExtend(x3[0]) + sExtend(x3[1]) + fromInteger(valueOf(round));

      return truncate(sum >> valueOf(shift));
   endmethod
endmodule

(* synthesize *)
module mkDct32(IDct32);
   FIFOF#(Vector#(2, Vector#(32, Bit#(10)))) fifo_in <- mkPipelineFIFOF;         // [E[0..15] O[0..15]]
   FIFOF#(Vector#(4, Bit#(16))) fifo_out <- mkPipelineFIFOF;

   Reg#(Bit#(16)) cycles <- mkReg(0);
   rule do_cycles;
      cycles <= cycles + 1;
   endrule

   // Internal
   Vector#(16, FIFOF#(Bit#(64)))  mem;
   for(Integer i = 0; i < 15; i = i + 1)
      mem[i] <- mkUGSizedFIFOF(16);
   mem[15] <- mkSizedFIFOF(16);

   Reg#(Bit#(8)) rowIdx <- mkConfigReg(0);
   Reg#(Bit#(4)) colCnt <- mkConfigReg(0);
   Reg#(Bit#(3)) colIdx <- mkConfigReg(0);

   Vector#(4, IDct32Core#(10)) dct_1D <- replicateM(mkDct32Core);
   Vector#(4, IDct32Core#(17)) dct_2D <- replicateM(mkDct32Core);
   FIFOF#(Vector#(32, Bit#(17))) fifo_col <- mkPipelineFIFOF;        // [E[0..15] O[0..15]]

   rule do_1D(fifo_in.notEmpty);
      let x = fifo_in.first;

      /*
      if (rowIdx == 0) begin
         $write("E: ");
         for(Integer i = 0; i < 32 / 2; i = i + 1) begin
            Bit#(16) tmp = sExtend(x[0][i]);
            $write("%04X, ", tmp);
         end
         $write("\n");
      end
      */

      let y0 = dct_1D[0].dct(take    (x[0]), {rowIdx[3:0], 1'd0});
      let y1 = dct_1D[1].dct(take    (x[1]), {rowIdx[3:0], 1'd0});
      let y2 = dct_1D[2].dct(takeTail(x[0]), {rowIdx[3:0], 1'd1});
      let y3 = dct_1D[3].dct(takeTail(x[1]), {rowIdx[3:0], 1'd1});

      mem[rowIdx[7:4]].enq({y3,y2,y1,y0});
      $display("[%6d] (%2d,%2d) %04X, %04X, %04X, %04X", cycles, rowIdx[7:4], rowIdx[3:0], y0, y1, y2, y3);

      rowIdx <= rowIdx + 1;
      if (rowIdx[3:0] == '1) begin
         fifo_in.deq;
      end
   endrule

   //(* no_implicit_conditions *)
   rule pre_col(mem[15].notEmpty);
      Vector#(32, Bit#(16)) x;
      Vector#(32, Bit#(17)) y;

      for(Integer i = 0; i < 32 / 2; i = i + 1) begin
         Vector#(4,Bit#(16)) t = unpack(mem[i].first());
         x[i*2+0] = t[{colCnt[0], 1'd0}];
         x[i*2+1] = t[{colCnt[0], 1'd1}];
      end

      if (True) begin
         $write("[%6d] INP-2D: ", cycles);
         for(Integer i = 0; i < 32; i = i + 1) begin
            $write("%04X, ", x[i]);
         end
         $write("\n");
         //$write("             -O: ");
         //for(Integer i = 0; i < 16; i = i + 1) begin
         //   $write("%04X, ", x[16+i]);
         //end
         $write("\n");
      end

      for(Integer i = 0; i < 32 / 2; i = i + 1) begin
         y[ 0 + i] = sExtend(x[i]) + sExtend(x[31 - i]);
         y[16 + i] = sExtend(x[i]) - sExtend(x[31 - i]);
      end

      fifo_col.enq(y);
      colCnt <= colCnt + 1;
      if (colCnt[0] == 1) begin
         for(Integer i = 0; i < 16; i = i + 1) begin
            mem[i].deq;
         end
      end
   endrule

   rule do_2D;
      let x = fifo_col.first;

      if (True) begin
         $write("[%6d] EO-2D: ", cycles);
         for(Integer i = 0; i < 32; i = i + 1) begin
            Bit#(16) t = truncate(x[i]);
            $write("%04X, ", t);
         end
         $write("\n");
      end

      let y0 = dct_2D[0].dct(take    (x), {colIdx, 2'd0});
      let y1 = dct_2D[1].dct(takeTail(x), {colIdx, 2'd1});
      let y2 = dct_2D[2].dct(take    (x), {colIdx, 2'd2});
      let y3 = dct_2D[3].dct(takeTail(x), {colIdx, 2'd3});

      fifo_out.enq(unpack({y3,y2,y1,y0}));
      $display("[%6d] %3d: %04X, %04X, %04X, %04X", cycles, colIdx, y0, y1, y2, y3);

      colIdx <= colIdx + 1;
      if (colIdx == '1) begin
         fifo_col.deq;
      end
   endrule

   interface Put io_in = interface Put;
                            method Action put(Vector#(2, Vector#(32, Bit#(9))) x);
                               Vector#(2, Vector#(32, Bit#(10))) y = ?;

                               for(Integer i = 0; i < 32 / 2; i = i + 1) begin
                                  y[0][ 0 + i] = sExtend(x[0][i]) + sExtend(x[0][31 - i]);
                                  y[0][16 + i] = sExtend(x[0][i]) - sExtend(x[0][31 - i]);
                                  y[1][ 0 + i] = sExtend(x[1][i]) + sExtend(x[1][31 - i]);
                                  y[1][16 + i] = sExtend(x[1][i]) - sExtend(x[1][31 - i]);
                               end
                               fifo_in.enq(y);
                            endmethod
                         endinterface;
   interface Get io_out = toGet(fifo_out);

endmodule : mkDct32

`ifdef TEST_BENCH_mkDct32
import "BDPI" function Action dct32_genNew();
import "BDPI" function ActionValue#(Vector#(2, Vector#(32, Bit#(16)))) dct32_getDiff();
import "BDPI" function ActionValue#(Vector#(4, Bit#(16))) dct32_getDct();

(* synthesize *)
module mkTb(Empty);
   FIFOF#(Vector#(2, Vector#(32, Bit#(9)))) fifo_in <- mkPipelineFIFOF;
   FIFOF#(Vector#(4, Bit#(16))) fifo_out <- mkPipelineFIFOF;
   Reg#(Bit#(16)) cycles <- mkReg(0);
   Reg#(Bit#(9))  states <- mkReg(0);
   Reg#(Bit#(8))  passed <- mkReg(0);

   IDct32 dct32 <- mkDct32;

   mkConnection(toGet(fifo_in), dct32.io_in);
   mkConnection(dct32.io_out, toPut(fifo_out));

   rule do_cycles;
      cycles <= cycles + 1;
   endrule

   rule do_init(states == 0);
        dct32_genNew();
        $display("[%6d] Init DCT test data", cycles);
        states <= 1;
   endrule

   rule do_input(states >= 1 && states <= 16);
         let x <- dct32_getDiff;
         Vector#(2, Vector#(32, Bit#(9))) y;
         y[0] = map(truncate, x[0]);
         y[1] = map(truncate, x[1]);

         fifo_in.enq( y );

         $write("[%6d] ", cycles);
         for(Integer i = 0; i < 32; i = i + 1) begin
            $write("%04X, ", x[0][i]);
         end
         $write("\n         ");
         for(Integer i = 0; i < 32; i = i + 1) begin
            $write("%04X, ", x[1][i]);
         end
         $write("\n");
         states <= states + 1;
   endrule

   rule do_check(states >= 17 && states < 17+32*8);
      let x <- dct32_getDct;
      let y = fifo_out.first;

      if (x != y) begin
         $display("Verify failed: %X -> %X", x, y);
         $finish;
      end
      else begin
         $display("[%6d] (%3d) %X pass", cycles, states-17, x);
      end

      fifo_out.deq;
      states <= states + 1;
   endrule

   rule do_end(states >= 17+32*8);
      $display("[%d] All test passed!", passed);
      states <= 0;
      passed <= passed + 1;
      if (passed >= 10)
         $finish;
   endrule

      //states <= (states == 17+32*8) ? 0 : states + 1;
endmodule
`endif

// Copyright (c) 2016 Min Chen
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

import Vector::*;
import GetPut::*;
import Connectable::*;
import ConfigReg::*;
import FIFOF::*;
import SpecialFIFOs::*;
import BUtils::*;
import BRAMCore::*;
import SMul::*;

Integer g_t32[32][16] =
{
    { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 },
    { 90, 90, 88, 85, 82, 78, 73, 67, 61, 54, 46, 38, 31, 22, 13,  4 },
    { 90, 87, 80, 70, 57, 43, 25,  9, -9,-25,-43,-57,-70,-80,-87,-90 },
    { 90, 82, 67, 46, 22, -4,-31,-54,-73,-85,-90,-88,-78,-61,-38,-13 },
    { 89, 75, 50, 18,-18,-50,-75,-89,-89,-75,-50,-18, 18, 50, 75, 89 },
    { 88, 67, 31,-13,-54,-82,-90,-78,-46, -4, 38, 73, 90, 85, 61, 22 },
    { 87, 57,  9,-43,-80,-90,-70,-25, 25, 70, 90, 80, 43, -9,-57,-87 },
    { 85, 46,-13,-67,-90,-73,-22, 38, 82, 88, 54, -4,-61,-90,-78,-31 },
    { 83, 36,-36,-83,-83,-36, 36, 83, 83, 36,-36,-83,-83,-36, 36, 83 },
    { 82, 22,-54,-90,-61, 13, 78, 85, 31,-46,-90,-67,  4, 73, 88, 38 },
    { 80,  9,-70,-87,-25, 57, 90, 43,-43,-90,-57, 25, 87, 70, -9,-80 },
    { 78, -4,-82,-73, 13, 85, 67,-22,-88,-61, 31, 90, 54,-38,-90,-46 },
    { 75,-18,-89,-50, 50, 89, 18,-75,-75, 18, 89, 50,-50,-89,-18, 75 },
    { 73,-31,-90,-22, 78, 67,-38,-90,-13, 82, 61,-46,-88, -4, 85, 54 },
    { 70,-43,-87,  9, 90, 25,-80,-57, 57, 80,-25,-90, -9, 87, 43,-70 },
    { 67,-54,-78, 38, 85,-22,-90,  4, 90, 13,-88,-31, 82, 46,-73,-61 },
    { 64,-64,-64, 64, 64,-64,-64, 64, 64,-64,-64, 64, 64,-64,-64, 64 },
    { 61,-73,-46, 82, 31,-88,-13, 90, -4,-90, 22, 85,-38,-78, 54, 67 },
    { 57,-80,-25, 90, -9,-87, 43, 70,-70,-43, 87,  9,-90, 25, 80,-57 },
    { 54,-85, -4, 88,-46,-61, 82, 13,-90, 38, 67,-78,-22, 90,-31,-73 },
    { 50,-89, 18, 75,-75,-18, 89,-50,-50, 89,-18,-75, 75, 18,-89, 50 },
    { 46,-90, 38, 54,-90, 31, 61,-88, 22, 67,-85, 13, 73,-82,  4, 78 },
    { 43,-90, 57, 25,-87, 70,  9,-80, 80, -9,-70, 87,-25,-57, 90,-43 },
    { 38,-88, 73, -4,-67, 90,-46,-31, 85,-78, 13, 61,-90, 54, 22,-82 },
    { 36,-83, 83,-36,-36, 83,-83, 36, 36,-83, 83,-36,-36, 83,-83, 36 },
    { 31,-78, 90,-61,  4, 54,-88, 82,-38,-22, 73,-90, 67,-13,-46, 85 },
    { 25,-70, 90,-80, 43,  9,-57, 87,-87, 57, -9,-43, 80,-90, 70,-25 },
    { 22,-61, 85,-90, 73,-38, -4, 46,-78, 90,-82, 54,-13,-31, 67,-88 },
    { 18,-50, 75,-89, 89,-75, 50,-18,-18, 50,-75, 89,-89, 75,-50, 18 },
    { 13,-38, 61,-78, 88,-90, 85,-73, 54,-31,  4, 22,-46, 67,-82, 90 },
    {  9,-25, 43,-57, 70,-80, 87,-90, 90,-87, 80,-70, 57,-43, 25, -9 },
    {  4,-13, 22,-31, 38,-46, 54,-61, 67,-73, 78,-82, 85,-88, 90,-90 }
};

interface IDct32;
   interface Put#(Vector#(2, Vector#(32, Bit#(9)))) io_in;
   interface Get#(Vector#(4, Bit#(16))) io_out;
endinterface

interface IDct32Core#(numeric type a);
   method Bit#(16) dct(Vector#(16, Bit#(a)) x, Bit#(5) idx);
endinterface

module mkDct32Core(IDct32Core#(a))
   provisos(
      Add#(_x, 9, a),
      Add#(0, 8, b),
      Add#(1, c, TAdd#(a, b)),
      Add#(c, 1, c1),
      Add#(c, 2, c2),
      Add#(a, 10/*(5-1+6)*/, bs),
      Add#(shift, 16, bs),
      Add#(0, TExp#(TSub#(shift, 1)), round)
   );

   Vector#(16, SMUL#(a,b)) smul <- replicateM(mkSMUL);

   method Bit#(16) dct(Vector#(16, Bit#(a)) x, Bit#(5) idx);
      Bit#(c) x0[16];
      for(Integer i = 0; i < 16; i = i + 1)
         x0[i] = smul[i].c(x[i], fromInteger(g_t32[idx][i]));

      Bit#(c1) x1[8];
      for(Integer i = 0; i < 8; i = i + 1)
         x1[i] = sExtend(x0[2 * i + 0]) + sExtend(x0[2 * i + 1]);

      Bit#(c2) x2[4];
      for(Integer i = 0; i < 4; i = i + 1)
         x2[i] = sExtend(x1[2 * i + 0]) + sExtend(x1[2 * i + 1]);

      Bit#(bs) x3[2];
      for(Integer i = 0; i < 2; i = i + 1)
         x3[i] = sExtend(x2[2 * i + 0]) + sExtend(x2[2 * i + 1]);

      Bit#(bs) sum = sExtend(x3[0]) + sExtend(x3[1]) + fromInteger(valueOf(round));

      return truncate(sum >> valueOf(shift));
   endmethod
endmodule

(* synthesize *)
module mkDct32(IDct32);
   FIFOF#(Vector#(2, Vector#(32, Bit#(10)))) fifo_in <- mkPipelineFIFOF;         // [E[0..15] O[0..15]]
   FIFOF#(Vector#(4, Bit#(16))) fifo_out <- mkPipelineFIFOF;

   Reg#(Bit#(16)) cycles <- mkReg(0);
   rule do_cycles;
      cycles <= cycles + 1;
   endrule

   // Internal
   Vector#(16, FIFOF#(Bit#(64)))  mem;
   for(Integer i = 0; i < 15; i = i + 1)
      mem[i] <- mkUGSizedFIFOF(16);
   mem[15] <- mkSizedFIFOF(16);

   Reg#(Bit#(8)) rowIdx <- mkConfigReg(0);
   Reg#(Bit#(4)) colCnt <- mkConfigReg(0);
   Reg#(Bit#(3)) colIdx <- mkConfigReg(0);

   Vector#(4, IDct32Core#(10)) dct_1D <- replicateM(mkDct32Core);
   Vector#(4, IDct32Core#(17)) dct_2D <- replicateM(mkDct32Core);
   FIFOF#(Vector#(32, Bit#(17))) fifo_col <- mkPipelineFIFOF;        // [E[0..15] O[0..15]]

   rule do_1D(fifo_in.notEmpty);
      let x = fifo_in.first;

      /*
      if (rowIdx == 0) begin
         $write("E: ");
         for(Integer i = 0; i < 32 / 2; i = i + 1) begin
            Bit#(16) tmp = sExtend(x[0][i]);
            $write("%04X, ", tmp);
         end
         $write("\n");
      end
      */

      let y0 = dct_1D[0].dct(take    (x[0]), {rowIdx[3:0], 1'd0});
      let y1 = dct_1D[1].dct(take    (x[1]), {rowIdx[3:0], 1'd0});
      let y2 = dct_1D[2].dct(takeTail(x[0]), {rowIdx[3:0], 1'd1});
      let y3 = dct_1D[3].dct(takeTail(x[1]), {rowIdx[3:0], 1'd1});

      mem[rowIdx[7:4]].enq({y3,y2,y1,y0});
      $display("[%6d] (%2d,%2d) %04X, %04X, %04X, %04X", cycles, rowIdx[7:4], rowIdx[3:0], y0, y1, y2, y3);

      rowIdx <= rowIdx + 1;
      if (rowIdx[3:0] == '1) begin
         fifo_in.deq;
      end
   endrule

   //(* no_implicit_conditions *)
   rule pre_col(mem[15].notEmpty);
      Vector#(32, Bit#(16)) x;
      Vector#(32, Bit#(17)) y;

      for(Integer i = 0; i < 32 / 2; i = i + 1) begin
         Vector#(4,Bit#(16)) t = unpack(mem[i].first());
         x[i*2+0] = t[{colCnt[0], 1'd0}];
         x[i*2+1] = t[{colCnt[0], 1'd1}];
      end

      if (True) begin
         $write("[%6d] INP-2D: ", cycles);
         for(Integer i = 0; i < 32; i = i + 1) begin
            $write("%04X, ", x[i]);
         end
         $write("\n");
         //$write("             -O: ");
         //for(Integer i = 0; i < 16; i = i + 1) begin
         //   $write("%04X, ", x[16+i]);
         //end
         $write("\n");
      end

      for(Integer i = 0; i < 32 / 2; i = i + 1) begin
         y[ 0 + i] = sExtend(x[i]) + sExtend(x[31 - i]);
         y[16 + i] = sExtend(x[i]) - sExtend(x[31 - i]);
      end

      fifo_col.enq(y);
      colCnt <= colCnt + 1;
      if (colCnt[0] == 1) begin
         for(Integer i = 0; i < 16; i = i + 1) begin
            mem[i].deq;
         end
      end
   endrule

   rule do_2D;
      let x = fifo_col.first;

      if (True) begin
         $write("[%6d] EO-2D: ", cycles);
         for(Integer i = 0; i < 32; i = i + 1) begin
            Bit#(16) t = truncate(x[i]);
            $write("%04X, ", t);
         end
         $write("\n");
      end

      let y0 = dct_2D[0].dct(take    (x), {colIdx, 2'd0});
      let y1 = dct_2D[1].dct(takeTail(x), {colIdx, 2'd1});
      let y2 = dct_2D[2].dct(take    (x), {colIdx, 2'd2});
      let y3 = dct_2D[3].dct(takeTail(x), {colIdx, 2'd3});

      fifo_out.enq(unpack({y3,y2,y1,y0}));
      $display("[%6d] %3d: %04X, %04X, %04X, %04X", cycles, colIdx, y0, y1, y2, y3);

      colIdx <= colIdx + 1;
      if (colIdx == '1) begin
         fifo_col.deq;
      end
   endrule

   interface Put io_in = interface Put;
                            method Action put(Vector#(2, Vector#(32, Bit#(9))) x);
                               Vector#(2, Vector#(32, Bit#(10))) y = ?;

                               for(Integer i = 0; i < 32 / 2; i = i + 1) begin
                                  y[0][ 0 + i] = sExtend(x[0][i]) + sExtend(x[0][31 - i]);
                                  y[0][16 + i] = sExtend(x[0][i]) - sExtend(x[0][31 - i]);
                                  y[1][ 0 + i] = sExtend(x[1][i]) + sExtend(x[1][31 - i]);
                                  y[1][16 + i] = sExtend(x[1][i]) - sExtend(x[1][31 - i]);
                               end
                               fifo_in.enq(y);
                            endmethod
                         endinterface;
   interface Get io_out = toGet(fifo_out);

endmodule : mkDct32

`ifdef TEST_BENCH_mkDct32
import "BDPI" function Action dct32_genNew();
import "BDPI" function ActionValue#(Vector#(2, Vector#(32, Bit#(16)))) dct32_getDiff();
import "BDPI" function ActionValue#(Vector#(4, Bit#(16))) dct32_getDct();

(* synthesize *)
module mkTb(Empty);
   FIFOF#(Vector#(2, Vector#(32, Bit#(9)))) fifo_in <- mkPipelineFIFOF;
   FIFOF#(Vector#(4, Bit#(16))) fifo_out <- mkPipelineFIFOF;
   Reg#(Bit#(16)) cycles <- mkReg(0);
   Reg#(Bit#(9))  states <- mkReg(0);

   IDct32 dct32 <- mkDct32;

   mkConnection(toGet(fifo_in), dct32.io_in);
   mkConnection(dct32.io_out, toPut(fifo_out));

   rule do_cycles;
      cycles <= cycles + 1;
   endrule

   rule do_init(states == 0);
        dct32_genNew();
        $display("[%6d] Init DCT test data", cycles);
        states <= 1;
   endrule

   rule do_input(states >= 1 && states <= 16);
         let x <- dct32_getDiff;
         Vector#(2, Vector#(32, Bit#(9))) y;
         y[0] = map(truncate, x[0]);
         y[1] = map(truncate, x[1]);

         fifo_in.enq( y );

         $write("[%6d] ", cycles);
         for(Integer i = 0; i < 32; i = i + 1) begin
            $write("%04X, ", x[0][i]);
         end
         $write("\n         ");
         for(Integer i = 0; i < 32; i = i + 1) begin
            $write("%04X, ", x[1][i]);
         end
         $write("\n");
         states <= states + 1;
   endrule

   rule do_check(states >= 17 && states < 17+32*8);
      let x <- dct32_getDct;
      let y = fifo_out.first;

      if (x != y) begin
         $display("Verify failed: %X -> %X", x, y);
         $finish;
      end
      else begin
         $display("[%6d] (%3d) %X pass", cycles, states-17, x);
      end

      fifo_out.deq;
      states <= states + 1;
   endrule

   rule do_end(states >= 17+32*8);
      $display("All test passed!");
      $finish;
   endrule

      //states <= (states == 17+32*8) ? 0 : states + 1;
endmodule
`endif


more jtag debug

more jtag debug

// 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 FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

interface Bscan#(numeric type width);
   interface Put#(Bit#(width)) capture;
   interface Get#(Bit#(width)) update;
endinterface

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

module mkBscan#(Integer bus)(Bscan#(width));
   let width = valueOf(width);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
       // SEL := (IR == 'USERx')
       // CAPTURE, RESET, RUNTEST, SHIFT, UPDATE: <name> := (TAP_state == <name>-DR)
       // TCK, TDI, TDO := corresponding JTAG pins
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);

   Reg#(Bit#(width)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   SyncFIFOIfc#(Bit#(width)) infifo <- mkSyncFIFO(2, defaultClock, defaultReset, tck);
   SyncFIFOIfc#(Bit#(width)) outfifo <- mkSyncFIFO(2, tck, rst, defaultClock);

   rule captureRule if (bscan.capture() == 1 && bscan.sel() == 1);
      if (infifo.notEmpty()) begin
	 //shiftReg <= tagged Valid infifo.first();
	 infifo.deq();
      end
      //else
      //shiftReg <= 0;
   endrule
   rule shift if (bscan.shift() == 1 && bscan.sel() == 1);
      bscan.tdo(shiftReg[0]);
      let v = (shiftReg >> 1);
      v[width-1] = bscan.tdi();
      shiftReg <= v;
   endrule
   rule updateRule if (bscan.update() == 1 && bscan.sel() == 1);
      //if (outfifo.notFull()) begin
      //outfifo.enq(shiftReg);
      //end
   endrule

   interface Put capture = toPut(infifo);
   interface Get update = toGet(outfifo);
endmodule

interface BscanBram#(numeric type asz, numeric type dsz);
    interface BRAMServer#(Bit#(asz), Bit#(dsz)) server;
    method Bit#(asz) addr();
    method Bit#(4) debug;
endinterface

module mkBscanBram#(Integer bus, Integer memorySize)(BscanBram#(asz, dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan2 <- mkBscanE2(bus+1);
   Clock tck2 <- mkClockBUFG(clocked_by bscan2.tck);
   Reset rst2 <- mkAsyncReset(2, defaultReset, tck2);
   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);
   SyncBitIfc#(Bool) resetAddr <-  mkSyncBits(False, tck2, rst2, tck, rst);
   Reg#(Bool) doincrement <- mkReg(False, clocked_by tck, reset_by rst);

   BRAM_Configure bramCfg = defaultValue;
   bramCfg.memorySize = memorySize;
   bramCfg.latency = 1;
   BRAM2Port#(Bit#(asz), Bit#(dsz)) bram <- mkSyncBRAM2Server(bramCfg, defaultClock, defaultReset, tck, rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(asz)) addrReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bool) captured <- mkReg(False, clocked_by tck, reset_by rst);

   rule reset_signal;
       resetAddr.send(bscan2.capture() == 1 && bscan2.sel() == 1);
   endrule
   rule reset_addr if (resetAddr.read());
       addrReg <= 0;  // if we read USER2, reset address
   endrule

   rule captureRule if (bscan.capture() == 1 && bscan.sel() == 1);
       bram.portB.request.put(BRAMRequest {write:False, responseOnWrite:False, address:addrReg, datain:?});
       captured <= True;
       doincrement <= True;
   endrule

   Wire#(Maybe#(Bit#(dsz))) dataWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);
   rule captureResultRule if (captured);
      let shift <- bram.portB.response.get();
      dataWire <= tagged Valid shift;
      captured <= False;
   endrule

   rule shift2 if (bscan.shift() == 1 && bscan.sel() == 1);
      Bit#(dsz) shift;
      if (dataWire matches tagged Valid .data)
	 shift = data;
      else
	 shift = shiftReg;
      bscan.tdo(shift[0]);
      let v = (shift >> 1);
      v[dsz-1] = bscan.tdi();
      shiftReg <= v;
   endrule

   rule updateRule2 if (bscan.update() == 1 && bscan.sel() == 1 && doincrement);
      bram.portB.request.put(BRAMRequest {write:True, responseOnWrite:False, address:addrReg, datain:shiftReg});
      addrReg <= addrReg + 1;
      doincrement <= False;
   endrule

   interface server = bram.portA;
   method Bit#(4) debug;
       return {bscan.sel(), bscan.capture(), bscan.shift(), bscan.update()};
   endmethod
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 FIFOF::*;
import Clocks::*;
import BRAM::*;
import BscanE2::*;
import GetPut::*;
import XilinxCells::*;
import SyncBits::*;

interface Bscan#(numeric type width);
   interface Put#(Bit#(width)) capture;
   interface Get#(Bit#(width)) update;
endinterface

// From: http://siliconexposed.blogspot.com/2013/10/soc-framework-part-5.html
// Example usage: http://www.pld.ttu.ee/~vadim/tty/IAY0570/video_pipeline/psram_app/program_rom.v
// Example usage: http://ohm.bu.edu/~dean/G-2TrackerWORKING/uart_test.vhd

module mkBscan#(Integer bus)(Bscan#(width));
   let width = valueOf(width);
   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
       // SEL := (IR == 'USERx')
       // CAPTURE, RESET, RUNTEST, SHIFT, UPDATE: <name> := (TAP_state == <name>-DR)
       // TCK, TDI, TDO := corresponding JTAG pins
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);

   Reg#(Bit#(width)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   SyncFIFOIfc#(Bit#(width)) infifo <- mkSyncFIFO(2, defaultClock, defaultReset, tck);
   SyncFIFOIfc#(Bit#(width)) outfifo <- mkSyncFIFO(2, tck, rst, defaultClock);

   rule captureRule if (bscan.capture() == 1 && bscan.sel() == 1);
      if (infifo.notEmpty()) begin
	 //shiftReg <= tagged Valid infifo.first();
	 infifo.deq();
      end
      //else
      //shiftReg <= 0;
   endrule
   rule shift if (bscan.shift() == 1 && bscan.sel() == 1);
      bscan.tdo(shiftReg[0]);
      let v = (shiftReg >> 1);
      v[width-1] = bscan.tdi();
      shiftReg <= v;
   endrule
   rule updateRule if (bscan.update() == 1 && bscan.sel() == 1);
      //if (outfifo.notFull()) begin
      //outfifo.enq(shiftReg);
      //end
   endrule

   interface Put capture = toPut(infifo);
   interface Get update = toGet(outfifo);
endmodule

interface BscanBram#(numeric type asz, numeric type dsz);
    interface BRAMServer#(Bit#(asz), Bit#(dsz)) server;
    method Bit#(asz) addr();
    method Bit#(4) debug;
endinterface

module mkBscanBram#(Integer bus, Integer memorySize)(BscanBram#(asz, dsz));
   let asz = valueOf(asz);
   let dsz = valueOf(dsz);

   Clock defaultClock <- exposeCurrentClock();
   Reset defaultReset <- exposeCurrentReset();

   BscanE2 bscan <- mkBscanE2(bus);
   Clock tck <- mkClockBUFG(clocked_by bscan.tck);
   Reset rst <- mkAsyncReset(2, defaultReset, tck);
   SyncBitIfc#(Bit#(4)) debugReg <-  mkSyncBits(0, tck, rst, defaultClock, defaultReset);

   BRAM_Configure bramCfg = defaultValue;
   bramCfg.memorySize = memorySize;
   bramCfg.latency = 1;
   BRAM2Port#(Bit#(asz), Bit#(dsz)) bram <- mkSyncBRAM2Server(bramCfg, defaultClock, defaultReset, tck, rst);

   Reg#(Bit#(dsz)) shiftReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bit#(asz)) addrReg <- mkReg(0, clocked_by tck, reset_by rst);
   Reg#(Bool) captured <- mkReg(False, clocked_by tck, reset_by rst);

   SyncBitIfc#(Bit#(asz)) syncAddr <-  mkSyncBits(0, tck, rst, defaultClock, defaultReset);

   rule reset_addr if (bscan.capture() == 1 && bscan.sel() == 0);  // if we read a different reg, reset address
       addrReg <= 0;
   endrule

   rule captureRule if (bscan.capture() == 1 && bscan.sel() == 1);
       bram.portB.request.put(BRAMRequest {write:False, responseOnWrite:False, address:addrReg, datain:?});
       captured <= True;
   endrule

   Wire#(Maybe#(Bit#(dsz))) dataWire <- mkDWire(tagged Invalid, clocked_by tck, reset_by rst);
   rule captureResultRule if (captured);
      let shift <- bram.portB.response.get();
      dataWire <= tagged Valid shift;
      captured <= False;
   endrule

   rule shift2 if (bscan.shift() == 1 && bscan.sel() == 1);
      Bit#(dsz) shift;
      if (dataWire matches tagged Valid .data)
	 shift = data;
      else
	 shift = shiftReg;
      bscan.tdo(shift[0]);
      let v = (shift >> 1);
      v[dsz-1] = bscan.tdi();
      shiftReg <= v;
   endrule

   rule updateRule2 if (bscan.update() == 1 && bscan.sel() == 1);
//      bram.portB.request.put(BRAMRequest {write:True, responseOnWrite:False, address:addrReg, datain:shiftReg});
      addrReg <= addrReg + 1;
   endrule

   rule debug_rule;
       debugReg.send({bscan.sel(), bscan.capture(), bscan.shift(), 0});
   endrule
   rule addr_rule;
      syncAddr.send(addrReg);
   endrule

   interface server = bram.portA;
   method Bit#(asz) addr();
      return syncAddr.read();
   endmethod
   method Bit#(4) debug;
       return debugReg.read();
   endmethod
endmodule


fix type of io signal

fix type of io signal

// 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 XilinxCells::*;
import XbsvXilinxCells::*;
import Gearbox::*;
import Pipe::*;
import FIFO::*;
import BRAMFIFO::*;
import Vector::*;
import Clocks::*;
import DefaultValue::*;

import extraXilinxCells::*;

(* always_enabled *)
interface FMComms1DACPins;
   method Bit#(14) io_dac_data_p();
   method Bit#(14) io_dac_data_n();
   method Action io_dac_dco_p(Bit#(1) v);
   method Action io_dac_dco_n(Bit#(1) v);
   method Bit#(1) io_dac_dci_p();
   method Bit#(1) io_dac_dci_n();
   method Clock deleteme_unused_clock;
   method Reset deleteme_unused_reset;
endinterface

typedef struct {
   Bit#(16) data_i;
   Bit#(16) data_q;
   } OIQ deriving (Bits);

interface FMComms1DAC;
   interface FMComms1DACPins pins;
   interface PipeIn#(Bit#(64)) dac;
endinterface

/* This module drives an Analog Devices FMComms1
 * evaluation board Digital to Analog Converter, it accepts
 * the data as a PipeIn type on the default clock.
 * The FMComms1 supplies the DAC clock as a differential pair
 *
 * Output is double data rate, with clock supplied by the FMComms1
 * Output data is 14 bits twos-complement or offset binary
 *
 * Differential outputs are converted from single ended by using Xilinx OBUFDS
 * cells. The clock is converted to single ended by an IBUFGDS cell
 *
 * DDR data is convered from SDR using ODDR cells
 * At this point, the data is a 14 bit in-phase data signal,
 * plus a 14 bit quadrature signal, interleaved
 *
 * The SDR data is a 32-bit OIQ datatype
 *
 * The 32-bit data is converted from 64-bits by a Gearbox
 *
 * Clock conversion happens 64-bits wide using a SyncBRAMFIFO, which
 * presents a PipeIn channel to the rest of the logic.
 */

module mkFMComms1DAC(FMComms1DAC);

   Clock def_clock <- exposeCurrentClock;
   Reset def_reset <- exposeCurrentReset;
   Clock dac_dco;
   Wire#(Bit#(1)) dac_dco_p <- mkDWire(0);
   Wire#(Bit#(1)) dac_dco_n <- mkDWire(0);

   dac_dco <- mkClockIBUFDS(dac_dco_p, dac_dco_n);
   Reset dac_reset <- mkAsyncReset(3, def_reset, dac_dco);

   SyncFIFOIfc#(Vector#(2, OIQ)) outfifo <- mkSyncBRAMFIFO(128, def_clock, def_reset, dac_dco, dac_reset);

   Gearbox#(2, 1, OIQ) gb <- mkNto1Gearbox(dac_dco, dac_reset, dac_dco, dac_reset);
   ODDRParams#(Bit#(14)) oddrparams = defaultValue;
//   oddrparams.ddr_clk_edge = "SAME_EDGE_PIPELINED";
      oddrparams.ddr_clk_edge = "SAME_EDGE";

   ODDR#(Bit#(14)) dac_ddr <- mkODDR(oddrparams, clocked_by (dac_dco));

   Vector#(14, Wire#(Bit#(1))) dac_ddr_data <- replicateM(mkDWire(0));

   Vector#(14, DiffOut) dac_out = newVector;

   for (Integer i = 0; i < 14; i = i + 1)
      dac_out[i] <- mkxOBUFDS(dac_ddr_data[i]);

   C2B dac_dco_as_bit <- mkC2B(dac_dco);
   Wire#(Bit#(1)) dac_dci_wire <- mkDWire(0);

   rule senddown_clk;
      dac_dci_wire <= dac_dco_as_bit.o();
   endrule

   DiffOut dac_dci <- mkxOBUFDS(dac_dci_wire);

   rule senddown_gb;
      outfifo.deq();
      gb.enq(outfifo.first());
   endrule

   rule senddown_oddr;
      let d = gb.first;
      gb.deq();
      dac_ddr.d1(d[0].data_i[15:2]);
      dac_ddr.d2(d[0].data_q[15:2]);
   endrule

   function Bit#(1) foo_p(DiffOut v);
      return (v.read_p());
   endfunction

   function Bit#(1) foo_n(DiffOut v);
      return (v.read_n());
   endfunction

   function Bit#(14) get_p(Vector#(14, DiffOut) v);
      return(pack(map(foo_p, v)));
   endfunction

   function Bit#(14) get_n(Vector#(14, DiffOut) v);
      return(pack(map(foo_n, v)));
   endfunction

   interface FMComms1DACPins pins;

      method Bit#(14) io_dac_data_p();
         return(get_p(dac_out));
      endmethod

      method Bit#(14) io_dac_data_n();
         return(get_n(dac_out));
      endmethod

      method Bit#(1) io_dac_dci_p();
         return(dac_dci.read_p());
      endmethod

      method Bit#(1) io_dac_dci_n();
         return(dac_dci.read_n());
      endmethod

      method Action io_dac_dco_p(Bit#(1) v);
	 dac_dco_p <= v;
      endmethod

      method Action io_dac_dco_n(Bit#(1) v);
	 dac_dco_n <= v;
      endmethod
      interface deleteme_unused_clock = dac_dco;
      interface deleteme_unused_reset = dac_reset;

   endinterface

   interface PipeIn dac;

      method Action enq(Bit#(64) v);
	 outfifo.enq(unpack(pack(v)));
      endmethod

      method Bool notFull() = outfifo.notFull;

   endinterface

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 XilinxCells::*;
import XbsvXilinxCells::*;
import Gearbox::*;
import Pipe::*;
import FIFO::*;
import BRAMFIFO::*;
import Vector::*;
import Clocks::*;
import DefaultValue::*;

import extraXilinxCells::*;

(* always_enabled *)
interface FMComms1DACPins;
   method Bit#(14) io_dac_data_p();
   method Bit#(14) io_dac_data_n();
   method Action io_dac_dco_p(Bit#(1) v);
   method Action io_dac_dco_n(Bit#(1) v);
   method Bit#(1) io_dac_dci_p();
   method Bit#(2) io_dac_dci_n();
   method Clock deleteme_unused_clock;
   method Reset deleteme_unused_reset;
endinterface

typedef struct {
   Bit#(16) data_i;
   Bit#(16) data_q;
   } OIQ deriving (Bits);

interface FMComms1DAC;
   interface FMComms1DACPins pins;
   interface PipeIn#(Bit#(64)) dac;
endinterface

/* This module drives an Analog Devices FMComms1
 * evaluation board Digital to Analog Converter, it accepts
 * the data as a PipeIn type on the default clock.
 * The FMComms1 supplies the DAC clock as a differential pair
 *
 * Output is double data rate, with clock supplied by the FMComms1
 * Output data is 14 bits twos-complement or offset binary
 *
 * Differential outputs are converted from single ended by using Xilinx OBUFDS
 * cells. The clock is converted to single ended by an IBUFGDS cell
 *
 * DDR data is convered from SDR using ODDR cells
 * At this point, the data is a 14 bit in-phase data signal,
 * plus a 14 bit quadrature signal, interleaved
 *
 * The SDR data is a 32-bit OIQ datatype
 *
 * The 32-bit data is converted from 64-bits by a Gearbox
 *
 * Clock conversion happens 64-bits wide using a SyncBRAMFIFO, which
 * presents a PipeIn channel to the rest of the logic.
 */

module mkFMComms1DAC(FMComms1DAC);

   Clock def_clock <- exposeCurrentClock;
   Reset def_reset <- exposeCurrentReset;
   Clock dac_dco;
   Wire#(Bit#(1)) dac_dco_p <- mkDWire(0);
   Wire#(Bit#(1)) dac_dco_n <- mkDWire(0);

   dac_dco <- mkClockIBUFDS(dac_dco_p, dac_dco_n);
   Reset dac_reset <- mkAsyncReset(3, def_reset, dac_dco);

   SyncFIFOIfc#(Vector#(2, OIQ)) outfifo <- mkSyncBRAMFIFO(128, def_clock, def_reset, dac_dco, dac_reset);

   Gearbox#(2, 1, OIQ) gb <- mkNto1Gearbox(dac_dco, dac_reset, dac_dco, dac_reset);
   ODDRParams#(Bit#(14)) oddrparams = defaultValue;
//   oddrparams.ddr_clk_edge = "SAME_EDGE_PIPELINED";
      oddrparams.ddr_clk_edge = "SAME_EDGE";

   ODDR#(Bit#(14)) dac_ddr <- mkODDR(oddrparams, clocked_by (dac_dco));

   Vector#(14, Wire#(Bit#(1))) dac_ddr_data <- replicateM(mkDWire(0));

   Vector#(14, DiffOut) dac_out = newVector;

   for (Integer i = 0; i < 14; i = i + 1)
      dac_out[i] <- mkxOBUFDS(dac_ddr_data[i]);

   C2B dac_dco_as_bit <- mkC2B(dac_dco);
   Wire#(Bit#(1)) dac_dci_wire <- mkDWire(0);

   rule senddown_clk;
      dac_dci_wire <= dac_dco_as_bit.o();
   endrule

   DiffOut dac_dci <- mkxOBUFDS(dac_dci_wire);

   rule senddown_gb;
      outfifo.deq();
      gb.enq(outfifo.first());
   endrule

   rule senddown_oddr;
      let d = gb.first;
      gb.deq();
      dac_ddr.d1(d[0].data_i[15:2]);
      dac_ddr.d2(d[0].data_q[15:2]);
   endrule

   function Bit#(1) foo_p(DiffOut v);
      return (v.read_p());
   endfunction

   function Bit#(1) foo_n(DiffOut v);
      return (v.read_n());
   endfunction

   function Bit#(14) get_p(Vector#(14, DiffOut) v);
      return(pack(map(foo_p, v)));
   endfunction

   function Bit#(14) get_n(Vector#(14, DiffOut) v);
      return(pack(map(foo_n, v)));
   endfunction

   interface FMComms1DACPins pins;

      method Bit#(14) io_dac_data_p();
         return(get_p(dac_out));
      endmethod

      method Bit#(14) io_dac_data_n();
         return(get_n(dac_out));
      endmethod

      method Bit#(1) io_dac_dci_p();
         return(dac_dci.read_p());
      endmethod

      method Bit#(1) io_dac_dci_n();
         return(dac_dci.read_n());
      endmethod

      method Action io_dac_dco_p(Bit#(1) v);
	 dac_dco_p <= v;
      endmethod

      method Action io_dac_dco_n(Bit#(1) v);
	 dac_dco_n <= v;
      endmethod
      interface deleteme_unused_clock = dac_dco;
      interface deleteme_unused_reset = dac_reset;

   endinterface

   interface PipeIn dac;

      method Action enq(Bit#(64) v);
	 outfifo.enq(unpack(pack(v)));
      endmethod

      method Bool notFull() = outfifo.notFull;

   endinterface

endmodule


move cc,dd,rr,ss reads into a single cycle

// 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
	    action
	       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: ?});
	    endaction
	    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) || (t2 < minsofar))
		  action
		     if (t1 < t2)
			action
			   fr.vars <= CVars{midi: fr.vars.midi, minj: jj, mintype: 1};
			   minsofar <= t1;
			endaction
		     else
			action
			   fr.vars <= CVars{midi: fr.vars.midi, minj: jj, mintype: 2};
			   minsofar <= t2;
			endaction
		  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, tb: initialG, te: initialG}, CVars {midi: 0, minj: 0, mintype: 1});
      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) || (t2 < minsofar))
		  action
		     fr.vars.minj <= jj;
		     if (t1 < t2)
			action
			   fr.vars.mintype <= 1;
			   minsofar <= t1;
			endaction
		     else
			action
			   fr.vars.mintype <= 2;
			   minsofar <= t2;
			endaction
		  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, tb: initialG, te: initialG}, CVars {midi: 0, minj: 0, mintype: 1});
      endmethod
      method Bool done();
	 return(fr.pc == GCSIdle);
      endmethod
      method Action waitTillDone();
      endmethod
      method Action abort();
      endmethod
   endinterface: fsm

endmodule


trivial cleanup

trivial cleanup

// 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 Vector::*;
import GetPut::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import CtrlMux::*;

import MIFO::*;
import Pipe::*;
import Portal::*;
import MemTypes::*;
import AddressGenerator::*;
import MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import ConnectalMemory::*;
import HostInterface::*;

typedef struct {
    Bit#(1) select;
    Bit#(6) tag;
} ReadReqInfo deriving (Bits);

interface PortalCtrlMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemSlave#(addrWidth, dataWidth) memSlave;
   interface ReadOnly#(Bool) interrupt;
   interface WriteOnly#(Bit#(dataWidth)) num_portals;
endinterface

module mkPortalCtrlMemSlave#(Bit#(dataWidth) ifcId,
			     Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indicationPipes)
   (PortalCtrlMemSlave#(addrWidth, dataWidth))
   provisos( Add#(a__, 1, dataWidth)
	    ,Div#(dataWidth, 8, b__)
	    ,Bits#(MemData#(dataWidth), c__)
	    ,Add#(d__, dataWidth, TMul#(dataWidth, 2))
	    );

   AddressGenerator#(addrWidth,dataWidth) ctrlReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) ctrlWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(MemData#(dataWidth))        ctrlWriteDataFifo <- mkFIFO();
   FIFO#(Bit#(MemTagSize))        ctrlWriteDoneFifo <- mkFIFO();
   Reg#(Bit#(dataWidth)) num_portals_reg <- mkReg(0);

   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, indicationPipes);

   Reg#(Bool) interruptEnableReg <- mkReg(False);
   Bool      interruptStatus = False;
   Reg#(Bit#(TMul#(dataWidth,2))) cycle_count <- mkReg(0);
   Reg#(Bit#(dataWidth))    snapshot <- mkReg(0);

   Bit#(dataWidth)  readyChannel = -1;
   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule count;
      cycle_count <= cycle_count+1;
   endrule
   let verbose = False;

   rule writeDataRule;
      let d <- toGet(ctrlWriteDataFifo).get();
      let b <- ctrlWriteAddrGenerator.addrBeat.get();
      if (verbose) $display("mkCtrl.writeData addr=%h data=%h last=%d", b.addr, d.data, b.last);
      let v = d.data;
      let addr = b.addr;
      if (addr == 'h000)
	 noAction;
      if (addr == 'h004)
	 interruptEnableReg <= v[0] == 1'd1;
      if (b.last)
	 ctrlWriteDoneFifo.enq(b.tag);
   endrule

   interface PhysMemSlave memSlave;
      interface PhysMemReadServer read_server;
	 interface Put readReq = ctrlReadAddrGenerator.request;
	 interface Get readData;
	    method ActionValue#(MemData#(dataWidth)) get();
	       let b <- ctrlReadAddrGenerator.addrBeat.get();
	       let addr = b.addr;
	       let v = 'h05a05a0;
	       if (addr == 'h000)
		  v = interruptStatus ? 1 : 0;
	       if (addr == 'h004)
		  v = interruptEnableReg ? 1 : 0;
	       if (addr == 'h008)
		  v = fromInteger(valueOf(NumberOfTiles));
               if (addr == 'h00C) begin
		  if (interruptStatus)
		     v = readyChannel+1;
		  else
		     v = 0;
               end
	       if (addr == 'h010)
		  v = ifcId;
	       if (addr == 'h014)
		  v = num_portals_reg;
	       if (addr == 'h018) begin
		  snapshot <= truncate(cycle_count);
		  v = truncate(cycle_count>>valueOf(dataWidth));
	       end
	       if (addr == 'h01C)
		  v = snapshot;
	       if (verbose) $display("mkCtrl.readData addr=%h data=%h", b.addr, v);
	       return MemData { data: v, tag: b.tag, last: b.last };
	    endmethod
	 endinterface
      endinterface: read_server
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = ctrlWriteAddrGenerator.request;
	 interface Put writeData;
	    method Action put(MemData#(dataWidth) d);
	       ctrlWriteDataFifo.enq(d);
	    endmethod
	 endinterface
	 interface Get writeDone;
	    method ActionValue#(Bit#(MemTagSize)) get();
	       let tag <- toGet(ctrlWriteDoneFifo).get();
	       return tag;
	    endmethod
	 endinterface
      endinterface: write_server
   endinterface: memSlave
   interface ReadOnly interrupt;
      method Bool _read();
	 return interruptStatus && interruptEnableReg;
      endmethod
   endinterface
   interface WriteOnly num_portals;
      method Action _write(Bit#(dataWidth) v);
	 num_portals_reg <= v;
      endmethod
   endinterface
endmodule

module mkPipeInMemSlave#(PipeIn#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));

   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))        fifoWriteDoneFifo <- mkFIFO();

   interface PhysMemReadServer read_server;
      interface Put readReq = fifoReadAddrGenerator.request;
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let b <- fifoReadAddrGenerator.addrBeat.get();
	    let v = 0;
	    if (b.addr == 4)
	       v = extend(pack(methodPipe.notFull()));
	    return MemData { data: v, tag: b.tag, last: b.last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeInMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	    methodPipe.enq(d.data);
	    // this used to be where we triggered putFailed
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkPipeOutMemSlave#(PipeOut#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));
   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                  fifoWriteDoneFifo <- mkFIFO();
   FIFO#(MemData#(dataWidth))                   fifoReadDataFifo <- mkFIFO();
   rule readDataRule;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      let v = 0;
      if (b.addr == 0)
	 v <- toGet(methodPipe).get();
      else if (b.addr == 4)
	 v = extend(pack(methodPipe.notEmpty()));
      //$display("mkPipeOutMemSlave.readData.get addr=%h data=%h", b.addr, data);
      fifoReadDataFifo.enq(MemData { data: v, tag: b.tag, last: b.last });
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(addrWidth) req);
	    fifoReadAddrGenerator.request.put(req);
	    if (!methodPipe.notEmpty())
	       $display("***\n\n mkPipeOutMemSlave.read_server.underflow! \n\n****");
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let d <- toGet(fifoReadDataFifo).get();
	    return d;
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeOutMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkMemPortal#(Bit#(slaveDataWidth) ifcId,
		    PipePortal#(numRequests, numIndications, slaveDataWidth) portal)(MemPortal#(slaveAddrWidth, slaveDataWidth))
   provisos ( Add#(1, i__, slaveDataWidth)
	     ,Add#(c__, 5, slaveAddrWidth)
	     ,Add#(d__, 1, c__)
	     ,Add#(a__, TLog#(TAdd#(1, TAdd#(numRequests, numIndications))), c__)
	     ,Add#(b__, slaveDataWidth, TMul#(slaveDataWidth, 2))
	     );

   let requestMemSlaves <- mapM(mkPipeInMemSlave, portal.requests);
   let indicationMemSlaves <- mapM(mkPipeOutMemSlave, portal.indications);
   PortalCtrlMemSlave#(5,slaveDataWidth) ctrlPort <- mkPortalCtrlMemSlave(ifcId, portal.indications);
   let memslave  <- mkMemSlaveMux(cons(ctrlPort.memSlave,append(requestMemSlaves, indicationMemSlaves)));
   interface PhysMemSlave slave = memslave;
   interface ReadOnly interrupt = ctrlPort.interrupt;
   interface WriteOnly num_portals = ctrlPort.num_portals;
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 Vector::*;
import GetPut::*;
import FIFO::*;
import FIFOF::*;
import GetPut::*;
import ClientServer::*;
import CtrlMux::*;

import MIFO::*;
import Pipe::*;
import Portal::*;
import MemTypes::*;
import AddressGenerator::*;
import MemTypes::*;
import MemreadEngine::*;
import MemwriteEngine::*;
import ConnectalMemory::*;
import HostInterface::*;

typedef struct {
    Bit#(1) select;
    Bit#(6) tag;
} ReadReqInfo deriving (Bits);

interface PortalCtrlMemSlave#(numeric type addrWidth, numeric type dataWidth);
   interface PhysMemSlave#(addrWidth, dataWidth) memSlave;
   interface ReadOnly#(Bool) interrupt;
   interface WriteOnly#(Bit#(dataWidth)) num_portals;
endinterface

module mkPortalCtrlMemSlave#(Bit#(dataWidth) ifcId,
			     Vector#(numIndications, PipeOut#(Bit#(dataWidth))) indicationPipes)
   (PortalCtrlMemSlave#(addrWidth, dataWidth))
   provisos( Add#(a__, 1, dataWidth)
	    ,Div#(dataWidth, 8, b__)
	    ,Bits#(MemData#(dataWidth), c__)
	    ,Add#(d__, dataWidth, TMul#(dataWidth, 2))
	    );

   AddressGenerator#(addrWidth,dataWidth) ctrlReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) ctrlWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(MemData#(dataWidth))        ctrlWriteDataFifo <- mkFIFO();
   FIFO#(Bit#(MemTagSize))        ctrlWriteDoneFifo <- mkFIFO();
   Reg#(Bit#(dataWidth)) num_portals_reg <- mkReg(0);

   function Bool pipeOutNotEmpty(PipeOut#(a) po); return po.notEmpty(); endfunction
   Vector#(numIndications, Bool) readyBits = map(pipeOutNotEmpty, indicationPipes);

   Reg#(Bool) interruptEnableReg <- mkReg(False);
   Bool      interruptStatus = False;
   Reg#(Bit#(TMul#(dataWidth,2))) cycle_count <- mkReg(0);
   Reg#(Bit#(dataWidth))    snapshot <- mkReg(0);

   Bit#(dataWidth)  readyChannel = -1;
   for (Integer i = valueOf(numIndications) - 1; i >= 0; i = i - 1) begin
      if (readyBits[i]) begin
         interruptStatus = True;
         readyChannel = fromInteger(i);
      end
   end

   rule count;
      cycle_count <= cycle_count+1;
   endrule
   let verbose = False;

   rule writeDataRule;
      let d <- toGet(ctrlWriteDataFifo).get();
      let b <- ctrlWriteAddrGenerator.addrBeat.get();
      if (verbose) $display("mkCtrl.writeData addr=%h data=%h last=%d", b.addr, d.data, b.last);
      let v = d.data;
      let addr = b.addr;
      if (addr == 'h000)
	 noAction;
      if (addr == 'h004)
	 interruptEnableReg <= v[0] == 1'd1;
      if (b.last)
	 ctrlWriteDoneFifo.enq(b.tag);
   endrule

   interface PhysMemSlave memSlave;
      interface PhysMemReadServer read_server;
	 interface Put readReq = ctrlReadAddrGenerator.request;
	 interface Get readData;
	    method ActionValue#(MemData#(dataWidth)) get();
	       let b <- ctrlReadAddrGenerator.addrBeat.get();
	       let addr = b.addr;
	       let v = 'h05a05a0;
	       if (addr == 'h000)
		  v = interruptStatus ? 1 : 0;
	       if (addr == 'h004)
		  v = interruptEnableReg ? 1 : 0;
	       if (addr == 'h008)
		  v = fromInteger(valueOf(NumberOfTiles));
               if (addr == 'h00C) begin
		  if (interruptStatus)
		     v = readyChannel+1;
		  else
		     v = 0;
               end
	       if (addr == 'h010)
		  v = ifcId;
	       if (addr == 'h014)
		  v = num_portals_reg;
	       if (addr == 'h018) begin
		  snapshot <= truncate(cycle_count);
		  v = truncate(cycle_count>>valueOf(dataWidth));
	       end
	       if (addr == 'h01C)
		  v = snapshot;
	       if (verbose) $display("mkCtrl.readData addr=%h data=%h", b.addr, v);
	       return MemData { data: v, tag: b.tag, last: b.last };
	    endmethod
	 endinterface
      endinterface: read_server
      interface PhysMemWriteServer write_server;
	 interface Put writeReq = ctrlWriteAddrGenerator.request;
	 interface Put writeData;
	    method Action put(MemData#(dataWidth) d);
	       ctrlWriteDataFifo.enq(d);
	    endmethod
	 endinterface
	 interface Get writeDone;
	    method ActionValue#(Bit#(MemTagSize)) get();
	       let tag <- toGet(ctrlWriteDoneFifo).get();
	       return tag;
	    endmethod
	 endinterface
      endinterface: write_server
   endinterface: memSlave
   interface ReadOnly interrupt;
      method Bool _read();
	 return interruptStatus && interruptEnableReg;
      endmethod
   endinterface
   interface WriteOnly num_portals;
      method Action _write(Bit#(dataWidth) v);
	 num_portals_reg <= v;
      endmethod
   endinterface
endmodule

module mkPipeInMemSlave#(PipeIn#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));

   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator  <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))        fifoWriteDoneFifo <- mkFIFO();

   interface PhysMemReadServer read_server;
      interface Put readReq = fifoReadAddrGenerator.request;
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let b <- fifoReadAddrGenerator.addrBeat.get();
	    let v = 0;
	    if (b.addr == 4)
	       v = extend(pack(methodPipe.notFull()));
	    return MemData { data: v, tag: b.tag, last: b.last };
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeInMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	    methodPipe.enq(d.data);
	    // this used to be where we triggered putFailed
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkPipeOutMemSlave#(PipeOut#(Bit#(dataWidth)) methodPipe)(PhysMemSlave#(addrWidth, dataWidth))
   provisos (Add#(1,a__,dataWidth));
   AddressGenerator#(addrWidth,dataWidth) fifoReadAddrGenerator <- mkAddressGenerator();
   AddressGenerator#(addrWidth,dataWidth) fifoWriteAddrGenerator <- mkAddressGenerator();
   FIFO#(Bit#(MemTagSize))                  fifoWriteDoneFifo <- mkFIFO();
   FIFO#(MemData#(dataWidth))                   fifoReadDataFifo <- mkFIFO();
   rule readDataRule;
      let b <- fifoReadAddrGenerator.addrBeat.get();
      let v = 0;
      if (b.addr == 0)
	 v <- toGet(methodPipe).get();
      else if (b.addr == 4)
	 v = extend(pack(methodPipe.notEmpty()));
      //$display("mkPipeOutMemSlave.readData.get addr=%h data=%h", b.addr, data);
      fifoReadDataFifo.enq(MemData { data: v, tag: b.tag, last: b.last });
   endrule

   interface PhysMemReadServer read_server;
      interface Put readReq;
	 method Action put(PhysMemRequest#(addrWidth) req);
	    fifoReadAddrGenerator.request.put(req);
	    if (!methodPipe.notEmpty())
	       $display("***\n\n mkPipeOutMemSlave.read_server.underflow! \n\n****");
	 endmethod
      endinterface
      interface Get readData;
	 method ActionValue#(MemData#(dataWidth)) get();
	    let d <- toGet(fifoReadDataFifo).get();
	    return d;
	 endmethod
      endinterface
   endinterface
   interface PhysMemWriteServer write_server;
      interface Put writeReq = fifoWriteAddrGenerator.request;
      interface Put writeData;
	 method Action put((MemData#(dataWidth)) d);
	    let b <- fifoWriteAddrGenerator.addrBeat.get();
	    //$display("mkPipeOutMemSlave.writeData.put addr=%h data=%h", b.addr, d.data);
	    if (b.last)
	       fifoWriteDoneFifo.enq(b.tag);
	 endmethod
      endinterface
      interface Get writeDone = toGet(fifoWriteDoneFifo);
   endinterface
endmodule

module mkMemPortal#(Bit#(slaveDataWidth) ifcId,
		    PipePortal#(numRequests, numIndications, slaveDataWidth) portal)(MemPortal#(slaveAddrWidth, slaveDataWidth))
   provisos ( Add#(1, i__, slaveDataWidth)
	     ,Add#(c__, 5, slaveAddrWidth)
	     ,Add#(d__, 1, c__)
	     ,Add#(a__, TLog#(TAdd#(1, TAdd#(numRequests, numIndications))), c__)
	     ,Add#(b__, slaveDataWidth, TMul#(slaveDataWidth, 2))
	     );

   Vector#(numRequests,    PipeIn#(Bit#(slaveDataWidth)))     requestPipes = portal.requests;
   Vector#(numIndications, PipeOut#(Bit#(slaveDataWidth))) indicationPipes = portal.indications;
   Vector#(numRequests,    PhysMemSlave#(5, slaveDataWidth))    requestMemSlaves <- mapM(mkPipeInMemSlave, requestPipes);
   Vector#(numIndications, PhysMemSlave#(5, slaveDataWidth)) indicationMemSlaves <- mapM(mkPipeOutMemSlave, indicationPipes);

   PortalCtrlMemSlave#(5,slaveDataWidth) ctrlPort <- mkPortalCtrlMemSlave(ifcId, indicationPipes);
   PhysMemSlave#(slaveAddrWidth,slaveDataWidth) memslave  <- mkMemSlaveMux(cons(ctrlPort.memSlave,append(requestMemSlaves, indicationMemSlaves)));
   interface PhysMemSlave slave = memslave;
   interface ReadOnly interrupt = ctrlPort.interrupt;
   interface WriteOnly num_portals = ctrlPort.num_portals;
endmodule