Cleanup last_mmuResp

Cleanup last_mmuResp

// 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 DefaultValue::*;

// CONNECTAL Libraries
import MemTypes::*;
import ToolMemory::*;
import ToolClocks::*;
import ToolCompletionBuffer::*;
import ToolConfig::*;
`include "ProjectConfig.bsv"

typedef 32 BeatCountSize;

interface DmaDbg;
   method ActionValue#(Bit#(64)) getMemoryTraffic();
   method ActionValue#(DmaDbgRec) dbg();
endinterface

interface MemWriteInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemWriteClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, PhysMemWriteServer#(addrWidth,busWidth)) servers;
endinterface

interface PhysMemReadInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemReadClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, PhysMemReadServer#(addrWidth,busWidth)) servers;
endinterface

import RegFile::*;

typedef struct {PhysMemRequest#(addrWidth,dataWidth) req;
                Bit#(TLog#(TMax#(1,numClients))) client; } LRec#(numeric type numClients, numeric type addrWidth, numeric type dataWidth) deriving(Bits);

typedef struct {PhysMemRequest#(addrWidth,dataWidth) req;
                Bit#(addrWidth) pa;
                Bit#(MemTagSize) rename_tag;
                Bit#(TLog#(TMax#(1,numClients))) client; } RRec#(numeric type numClients, numeric type addrWidth, numeric type dataWidth) deriving(Bits);

typedef struct {Bit#(MemTagSize) req_tag;
                Bit#(BurstLenSize) req_burstLen;
                Bit#(MemTagSize) rename_tag;
                Bit#(TLog#(TMax#(1,numClients))) client;
                Bool last;
   } DRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {Bit#(MemTagSize) orig_tag;
                Bit#(TLog#(TMax#(1,numClients))) client; } RResp#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {DmaErrorType errorType;
                Bit#(32) pref; } DmaError deriving (Bits);

module mkPhysMemReadInternal#(MemServerIndication ind)
   (PhysMemReadInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
            ,Div#(busWidth,8,busWidthBytes)
            ,Add#(beatShift, a__, 8)
            ,Add#(b__, TLog#(numTags), MemTagSize)
            ,Add#(beatShift, c__, BurstLenSize)
            ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
            );

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = 1)
   FIFO#(LRec#(numServers,addrWidth,busWidth)) clientRequest <- mkFIFO;
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth,busWidth)) serverRequest <- mkFIFO;
   // stage 2: read commands
   BRAM_Configure bramConfig = defaultValue;
   if (mainClockPeriod < 8)
      bramConfig.latency = 2;
   BRAM2Port#(Bit#(TLog#(numTags)), DRec#(numServers,addrWidth)) serverProcessing <- mkBRAM2Server(bramConfig);
   BRAM2Port#(Bit#(TAdd#(TLog#(numTags),TSub#(BurstLenSize,beatShift))), MemData#(busWidth)) clientData <- mkBRAM2Server(bramConfig);
   // stage 3: read data
   FIFO#(MemData#(busWidth)) serverData <- mkFIFO;

   let verbose = False;

   RegFile#(Bit#(TLog#(numTags)),Tuple2#(Bool,Bit#(BurstLenSize))) clientBurstLen <- mkRegFileFull();
   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);

   Reg#(Bit#(32))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   TagGen#(numTags) tag_gen <- mkTagGen;

   Reg#(Bit#(BurstLenSize))      compCountReg <- mkReg(0);
   Reg#(Bit#(TLog#(numTags)))    compTagReg <- mkReg(0);
   Reg#(Bit#(TLog#(TMax#(1,numServers)))) compClientReg <- mkReg(0);
   Reg#(Bit#(2))                 compTileReg <- mkReg(0);
   FIFO#(Bit#(TAdd#(1,TLog#(TMax#(1,numServers))))) clientSelect <- mkFIFO;
   FIFO#(Bit#(TLog#(numTags)))   serverTag <- mkFIFO;

   // performance analytics
   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_comp <- mkReg(0);
   Reg#(Bit#(64)) last_readReq <- mkReg(0);
   Reg#(Bit#(64)) last_readData <- mkReg(0);
   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      ind.error(extend(pack(error.errorType)), 0, 0);
   endrule

   rule checkMmuResp;
      let request <- toGet(clientRequest).get();
      let physAddr = request.req.addr;
      let rename_tag <- tag_gen.getTag;
      let burstLenBeats = request.req.burstLen >> beat_shift;
      clientBurstLen.upd(truncate(rename_tag), tuple2(burstLenBeats == 1, burstLenBeats));

      serverRequest.enq(RRec{req:request.req, pa:physAddr, client:request.client, rename_tag:extend(rename_tag)});
      if (verbose) $display("mkMemReadInternal::checkMmuResp: client=%d, tag=%d rename_tag=%d burstLen=%d", request.client, request.req.tag, rename_tag, burstLenBeats);
   endrule

   rule read_data;
      let response <- toGet(serverData).get();
      let drq <- serverProcessing.portA.response.get;
      let tag = drq.req_tag;
      match { .last, .burstLen } = clientBurstLen.sub(truncate(response.tag));
      let first   = firstReg;
      if (first) begin
         dynamicAssert(last == (burstLen==1), "Last incorrect");
      end
      if (last && burstLen != 1)
         $display("rename_tag=%d tag=%d burstLen=%d last=%d", response.tag, tag, burstLen, last);
      Bit#(TLog#(numTags)) tt = truncate(response.tag);
      clientData.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, datain:MemData{data: response.data, tag: tag, last: last},
                                               address:{tt,truncate(burstLen)}});
      if (last) begin
         tag_gen.returnTag(truncate(response.tag));
      end
      last_readData <= cycle_cnt;
      if (verbose) $display("mkMemReadInternal::read_data cyclediff %d", cycle_cnt-last_readData);
      clientBurstLen.upd(truncate(response.tag), tuple2((burstLen-1 == 1),burstLen-1));
      firstReg <= response.last;
   endrule

   rule tag_completed;
      let tag <- tag_gen.complete;
      serverProcessing.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
      serverTag.enq(tag);
      if(verbose) $display("mkMemReadInternal::complete_burst0 %h", tag);
   endrule

   rule complete_burst1a if (compCountReg==0);
      let drq <- serverProcessing.portB.response.get;
      let req_burstLen = drq.req_burstLen;
      let client = drq.client;
      let cnt = req_burstLen >> beat_shift;
      let tag <- toGet(serverTag).get;
      if(killv[drq.req_tag[5:4]] == False) begin
         clientSelect.enq(extend(client));
         clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      compTagReg <= tag;
      compClientReg <= client;
      compTileReg <= drq.req_tag[5:4];
      if(verbose) $display("mkMemReadInternal::complete_burst1a %h", client);
   endrule

   rule burst_remainder if (compCountReg > 0);
      let cnt = compCountReg;
      let tag = compTagReg;
      let client = compClientReg;
      if(killv[compTileReg] == False) begin
         clientSelect.enq(extend(client));
         clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      if(verbose) $display("mkMemReadInternal::complete_burst1b count %h", compCountReg);
   endrule

   Vector#(numServers, PhysMemReadServer#(addrWidth,busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface PhysMemReadServer;
                  interface Put readReq;
                     method Action put(PhysMemRequest#(addrWidth,busWidth) req);
                        last_loadClient <= cycle_cnt;
                        if (verbose) $display("mkMemReadInternal::loadClient server %d burstLen %d tag %d cycle %d",
                                              i, req.burstLen >> beat_shift, req.tag, cycle_cnt-last_loadClient);
                        if (stopv[req.tag[5:4]] == False) begin
                           clientRequest.enq(LRec{req:req, client:fromInteger(i)});
                        end
                     endmethod
                  endinterface
                  interface Get readData;
                     method ActionValue#(MemData#(busWidth)) get if (clientSelect.first == fromInteger(i));
                        clientSelect.deq;
                        let data <- clientData.portB.response.get;
                        if (verbose) $display("mkMemReadInternal::comp server %d data %x cycle %d", i, data.data, cycle_cnt-last_comp);
                        last_comp <= cycle_cnt;
                        return data;
                     endmethod
                  endinterface
               endinterface);

   interface servers = sv;
   interface PhysMemReadClient client;
      interface Get readReq;
         method ActionValue#(PhysMemRequest#(addrWidth,busWidth)) get();
            let request <- toGet(serverRequest).get;
            let req = request.req;
            if (False && request.pa[31:24] != 0)
               $display("mkMemReadInternal::req_ar: funny physAddr physAddr=%h", request.pa);
            serverProcessing.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(request.rename_tag),
                                                   datain:DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:request.client, rename_tag:request.rename_tag, last:(req.burstLen == fromInteger(valueOf(busWidthBytes)))}});
            $display("mkMemReadInternal::readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", request.client,request.rename_tag,request.pa, req.burstLen, beat_shift, req.burstLen == beat_shift);
            if (verbose) $display("mkMemReadInternal::read_client.readReq %d", cycle_cnt-last_readReq);
            last_readReq <= cycle_cnt;
            return PhysMemRequest{addr:request.pa, burstLen:req.burstLen, tag:request.rename_tag
`ifdef BYTE_ENABLES
                                  , firstbe: truncate(request.req.firstbe), lastbe: truncate(request.req.lastbe)
`endif
               };
         endmethod
      endinterface
      interface Put readData;
         method Action put(MemData#(busWidth) response);
            serverData.enq(response);
            serverProcessing.portA.request.put(BRAMRequest{write:False, address:truncate(response.tag), datain: ?, responseOnWrite: ?});
            beatCount <= beatCount+1;
         endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
         let tile = tc.tile;
         killv[tile] <= !(tc.state == Running || tc.state == Stopped);
         stopv[tile] <= !(tc.state == Running);
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
         return DmaDbgRec{x:0, y:0, z:0, w:0};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
         return extend(beatCount);
      endmethod
   endinterface
endmodule

module mkMemWriteInternal#(MemServerIndication ind)
   (MemWriteInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
            ,Div#(busWidth,8,busWidthBytes)
            ,Add#(beatShift, a__, 8)
            ,Add#(b__, TLog#(numTags), MemTagSize)
            ,Add#(beatShift, c__, BurstLenSize)
            ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
            );

   let verbose = False;

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = 1)
   FIFO#(LRec#(numServers,addrWidth,busWidth)) clientRequest <- mkFIFO;
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth,busWidth)) serverRequest <- mkFIFO;
   // stage 2: write commands
   FIFO#(DRec#(numServers, addrWidth)) serverProcessing <- mkSizedFIFO(valueOf(numTags));
   // stage 3: write data
   BRAM2Port#(Bit#(TLog#(numTags)), RResp#(numServers,addrWidth)) respFifos <- mkBRAM2Server(defaultValue);
   TagGen#(numTags) tag_gen <- mkTagGen;
   FIFO#(RResp#(numServers,addrWidth)) clientResponse <- mkFIFO;

   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);
   Reg#(Bool)               lastReg <- mkReg(False);
   Reg#(Bit#(BeatCountSize)) beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);

   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      ind.error(extend(pack(error.errorType)), 0, 0);
   endrule

   rule checkMmuResp;
      let request <- toGet(clientRequest).get;
      let req = request.req;
      let client = request.client;
      let physAddr = req.addr;
      let rename_tag <- tag_gen.getTag;
      serverRequest.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //if (verbose) $display("mkMemWriteInternal::checkMmuResp: client=%d, rename_tag=%d", client,rename_tag);
   endrule

   rule writeDoneComp0;
      let tag <- tag_gen.complete;
      respFifos.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
   endrule

   FIFO#(MemData#(busWidth)) memDataFifo <- mkFIFO();
   Vector#(numServers, FIFO#(MemData#(busWidth))) clientWriteData <- replicateM(mkFIFO);

   if(valueOf(numServers) > 0)
      rule memdata;
         let drq = serverProcessing.first;
         let req_tag = drq.req_tag;
         let req_burstLen = drq.req_burstLen;
         let rename_tag = drq.rename_tag;
         let client = drq.client;
         MemData#(busWidth) tagdata = unpack(0);
         if (killv[req_tag[5:4]] == False) begin
            tagdata = clientWriteData[client].first;
            clientWriteData[client].deq;
         end
         let burstLen = burstReg;
         let first    = firstReg;
         let last     = lastReg;
         if (first) begin
            burstLen = req_burstLen >> beat_shift;
            last     = serverProcessing.first.last;
            respFifos.portA.request.put(BRAMRequest{write:True,responseOnWrite:False, address:truncate(rename_tag), datain:RResp{orig_tag:req_tag, client:client}});
         end
         burstReg <= burstLen-1;
         firstReg <= (burstLen-1 == 0);
         lastReg  <= (burstLen-1 == 1);
         beatCount <= beatCount+1;
         if (last)
            serverProcessing.deq();
         //$display("mkMemWriteInternal::writeData: client=%d, rename_tag=%d", client, rename_tag);
         memDataFifo.enq(MemData { data: tagdata.data,  tag:extend(rename_tag), last: last });
      endrule

   rule fill_clientResponse;
      let rv <- respFifos.portB.response.get;
      clientResponse.enq(rv);
   endrule

   Vector#(numServers, PhysMemWriteServer#(addrWidth,busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface PhysMemWriteServer;
                  interface Put writeReq;
                     method Action put(PhysMemRequest#(addrWidth,busWidth) req);
                        if (verbose) $display("mkMemWriteInternal::loadClient %d %d", i, cycle_cnt-last_loadClient);
                        last_loadClient <= cycle_cnt;
                        if (stopv[req.tag[5:4]] == False) begin
                           clientRequest.enq(LRec{req:req, client:fromInteger(i)});
                        end
                     endmethod
                  endinterface
                  interface Put writeData = toPut(clientWriteData[i]);
                  interface Get writeDone;
                     method ActionValue#(Bit#(MemTagSize)) get if (clientResponse.first.client == fromInteger(i));
                        clientResponse.deq;
                        return clientResponse.first.orig_tag;
                     endmethod
                  endinterface
               endinterface);

   interface servers = sv;
   interface PhysMemWriteClient client;
      interface Get writeReq;
         method ActionValue#(PhysMemRequest#(addrWidth,busWidth)) get();
            let request <- toGet(serverRequest).get();
            let req = request.req;
            let physAddr = request.pa;
            let client = request.client;
            let rename_tag = request.rename_tag;
            serverProcessing.enq(DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:client, rename_tag:rename_tag, last: (req.burstLen == fromInteger(valueOf(busWidthBytes))) });
            //$display("mkMemWriteInternal::writeReq: client=%d, rename_tag=%d", client,rename_tag);
            return PhysMemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)
`ifdef BYTE_ENABLES
                                  , firstbe: truncate(req.firstbe), lastbe: truncate(req.lastbe)
`endif
};
         endmethod
      endinterface
      interface Get writeData = toGet(memDataFifo);
      interface Put writeDone;
         method Action put(Bit#(MemTagSize) resp);
            tag_gen.returnTag(truncate(resp));
            if (verbose) $display("mkMemWriteInternal::writeDone: resp=%d", resp);
         endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
         let tile = tc.tile;
         let kv = True;
         let sv = True;
         if (tc.state == Running || tc.state == Stopped)
            kv = False;
         if (tc.state == Running)
            sv = False;
         killv[tile] <= kv;
         stopv[tile] <= sv;
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
         return DmaDbgRec{x:fromInteger(valueOf(numServers)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
         return extend(beatCount);
      endmethod
   endinterface
endmodule

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

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

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

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

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

// CONNECTAL Libraries
import MemTypes::*;
import ToolMemory::*;
import ToolClocks::*;
import ToolCompletionBuffer::*;
import ToolConfig::*;
`include "ProjectConfig.bsv"

typedef 32 BeatCountSize;

interface DmaDbg;
   method ActionValue#(Bit#(64)) getMemoryTraffic();
   method ActionValue#(DmaDbgRec) dbg();
endinterface

interface MemWriteInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemWriteClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, PhysMemWriteServer#(addrWidth,busWidth)) servers;
endinterface

interface PhysMemReadInternal#(numeric type addrWidth, numeric type busWidth, numeric type numTags, numeric type numServers);
   interface DmaDbg dbg;
   interface Put#(TileControl) tileControl;
   interface PhysMemReadClient#(addrWidth,busWidth) client;
   interface Vector#(numServers, PhysMemReadServer#(addrWidth,busWidth)) servers;
endinterface

import RegFile::*;

typedef struct {PhysMemRequest#(addrWidth,dataWidth) req;
                Bit#(TLog#(TMax#(1,numClients))) client; } LRec#(numeric type numClients, numeric type addrWidth, numeric type dataWidth) deriving(Bits);

typedef struct {PhysMemRequest#(addrWidth,dataWidth) req;
                Bit#(addrWidth) pa;
                Bit#(MemTagSize) rename_tag;
                Bit#(TLog#(TMax#(1,numClients))) client; } RRec#(numeric type numClients, numeric type addrWidth, numeric type dataWidth) deriving(Bits);

typedef struct {Bit#(MemTagSize) req_tag;
                Bit#(BurstLenSize) req_burstLen;
                Bit#(MemTagSize) rename_tag;
                Bit#(TLog#(TMax#(1,numClients))) client;
                Bool last;
   } DRec#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {Bit#(MemTagSize) orig_tag;
                Bit#(TLog#(TMax#(1,numClients))) client; } RResp#(numeric type numClients, numeric type addrWidth) deriving(Bits);

typedef struct {DmaErrorType errorType;
                Bit#(32) pref; } DmaError deriving (Bits);

module mkPhysMemReadInternal#(MemServerIndication ind)
   (PhysMemReadInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
            ,Div#(busWidth,8,busWidthBytes)
            ,Add#(beatShift, a__, 8)
            ,Add#(b__, TLog#(numTags), MemTagSize)
            ,Add#(beatShift, c__, BurstLenSize)
            ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
            );

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = 1)
   FIFO#(LRec#(numServers,addrWidth,busWidth)) clientRequest <- mkFIFO;
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth,busWidth)) serverRequest <- mkFIFO;
   // stage 2: read commands
   BRAM_Configure bramConfig = defaultValue;
   if (mainClockPeriod < 8)
      bramConfig.latency = 2;
   BRAM2Port#(Bit#(TLog#(numTags)), DRec#(numServers,addrWidth)) serverProcessing <- mkBRAM2Server(bramConfig);
   BRAM2Port#(Bit#(TAdd#(TLog#(numTags),TSub#(BurstLenSize,beatShift))), MemData#(busWidth)) clientData <- mkBRAM2Server(bramConfig);
   // stage 3: read data
   FIFO#(MemData#(busWidth)) serverData <- mkFIFO;

   let verbose = False;

   RegFile#(Bit#(TLog#(numTags)),Tuple2#(Bool,Bit#(BurstLenSize))) clientBurstLen <- mkRegFileFull();
   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);

   Reg#(Bit#(32))  beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));
   TagGen#(numTags) tag_gen <- mkTagGen;

   Reg#(Bit#(BurstLenSize))      compCountReg <- mkReg(0);
   Reg#(Bit#(TLog#(numTags)))    compTagReg <- mkReg(0);
   Reg#(Bit#(TLog#(TMax#(1,numServers)))) compClientReg <- mkReg(0);
   Reg#(Bit#(2))                 compTileReg <- mkReg(0);
   FIFO#(Bit#(TAdd#(1,TLog#(TMax#(1,numServers))))) clientSelect <- mkFIFO;
   FIFO#(Bit#(TLog#(numTags)))   serverTag <- mkFIFO;

   // performance analytics
   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_mmuResp <- mkReg(0);
   Reg#(Bit#(64)) last_comp <- mkReg(0);
   Reg#(Bit#(64)) last_readReq <- mkReg(0);
   Reg#(Bit#(64)) last_readData <- mkReg(0);
   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      ind.error(extend(pack(error.errorType)), 0, 0);
   endrule

   rule checkMmuResp;
      let request <- toGet(clientRequest).get();
      let physAddr = request.req.addr;
      let rename_tag <- tag_gen.getTag;
      let burstLenBeats = request.req.burstLen >> beat_shift;
      clientBurstLen.upd(truncate(rename_tag), tuple2(burstLenBeats == 1, burstLenBeats));

      serverRequest.enq(RRec{req:request.req, pa:physAddr, client:request.client, rename_tag:extend(rename_tag)});
      if (verbose) $display("mkMemReadInternal::checkMmuResp: client=%d, tag=%d rename_tag=%d burstLen=%d", request.client, request.req.tag, rename_tag, burstLenBeats);
      if (verbose) $display("mkMemReadInternal::mmuResp %d %d", request.client, cycle_cnt-last_mmuResp);
      last_mmuResp <= cycle_cnt;
   endrule

   rule read_data;
      let response <- toGet(serverData).get();
      let drq <- serverProcessing.portA.response.get;
      let tag = drq.req_tag;
      match { .last, .burstLen } = clientBurstLen.sub(truncate(response.tag));
      let first   = firstReg;
      if (first) begin
         dynamicAssert(last == (burstLen==1), "Last incorrect");
      end
      if (last && burstLen != 1)
         $display("rename_tag=%d tag=%d burstLen=%d last=%d", response.tag, tag, burstLen, last);
      Bit#(TLog#(numTags)) tt = truncate(response.tag);
      clientData.portA.request.put(BRAMRequest{write:True, responseOnWrite:False, datain:MemData{data: response.data, tag: tag, last: last},
                                               address:{tt,truncate(burstLen)}});
      if (last) begin
         tag_gen.returnTag(truncate(response.tag));
      end
      last_readData <= cycle_cnt;
      if (verbose) $display("mkMemReadInternal::read_data cyclediff %d", cycle_cnt-last_readData);
      clientBurstLen.upd(truncate(response.tag), tuple2((burstLen-1 == 1),burstLen-1));
      firstReg <= response.last;
   endrule

   rule tag_completed;
      let tag <- tag_gen.complete;
      serverProcessing.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
      serverTag.enq(tag);
      if(verbose) $display("mkMemReadInternal::complete_burst0 %h", tag);
   endrule

   rule complete_burst1a if (compCountReg==0);
      let drq <- serverProcessing.portB.response.get;
      let req_burstLen = drq.req_burstLen;
      let client = drq.client;
      let cnt = req_burstLen >> beat_shift;
      let tag <- toGet(serverTag).get;
      if(killv[drq.req_tag[5:4]] == False) begin
         clientSelect.enq(extend(client));
         clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      compTagReg <= tag;
      compClientReg <= client;
      compTileReg <= drq.req_tag[5:4];
      if(verbose) $display("mkMemReadInternal::complete_burst1a %h", client);
   endrule

   rule burst_remainder if (compCountReg > 0);
      let cnt = compCountReg;
      let tag = compTagReg;
      let client = compClientReg;
      if(killv[compTileReg] == False) begin
         clientSelect.enq(extend(client));
         clientData.portB.request.put(BRAMRequest{write:False, address:{tag,truncate(cnt)}, datain: ?, responseOnWrite: ?});
      end
      compCountReg <= cnt-1;
      if(verbose) $display("mkMemReadInternal::complete_burst1b count %h", compCountReg);
   endrule

   Vector#(numServers, PhysMemReadServer#(addrWidth,busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface PhysMemReadServer;
                  interface Put readReq;
                     method Action put(PhysMemRequest#(addrWidth,busWidth) req);
                        last_loadClient <= cycle_cnt;
                        if (verbose) $display("mkMemReadInternal::loadClient server %d burstLen %d tag %d cycle %d",
                                              i, req.burstLen >> beat_shift, req.tag, cycle_cnt-last_loadClient);
                        if (stopv[req.tag[5:4]] == False) begin
                           clientRequest.enq(LRec{req:req, client:fromInteger(i)});
                        end
                     endmethod
                  endinterface
                  interface Get readData;
                     method ActionValue#(MemData#(busWidth)) get if (clientSelect.first == fromInteger(i));
                        clientSelect.deq;
                        let data <- clientData.portB.response.get;
                        if (verbose) $display("mkMemReadInternal::comp server %d data %x cycle %d", i, data.data, cycle_cnt-last_comp);
                        last_comp <= cycle_cnt;
                        return data;
                     endmethod
                  endinterface
               endinterface);

   interface servers = sv;
   interface PhysMemReadClient client;
      interface Get readReq;
         method ActionValue#(PhysMemRequest#(addrWidth,busWidth)) get();
            let request <- toGet(serverRequest).get;
            let req = request.req;
            if (False && request.pa[31:24] != 0)
               $display("mkMemReadInternal::req_ar: funny physAddr physAddr=%h", request.pa);
            serverProcessing.portB.request.put(BRAMRequest{write:True, responseOnWrite:False, address:truncate(request.rename_tag),
                                                   datain:DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:request.client, rename_tag:request.rename_tag, last:(req.burstLen == fromInteger(valueOf(busWidthBytes)))}});
            $display("mkMemReadInternal::readReq: client=%d, rename_tag=%d, physAddr=%h req.burstLen=%d beat_shift=%d last=%d", request.client,request.rename_tag,request.pa, req.burstLen, beat_shift, req.burstLen == beat_shift);
            if (verbose) $display("mkMemReadInternal::read_client.readReq %d", cycle_cnt-last_readReq);
            last_readReq <= cycle_cnt;
            return PhysMemRequest{addr:request.pa, burstLen:req.burstLen, tag:request.rename_tag
`ifdef BYTE_ENABLES
                                  , firstbe: truncate(request.req.firstbe), lastbe: truncate(request.req.lastbe)
`endif
               };
         endmethod
      endinterface
      interface Put readData;
         method Action put(MemData#(busWidth) response);
            serverData.enq(response);
            serverProcessing.portA.request.put(BRAMRequest{write:False, address:truncate(response.tag), datain: ?, responseOnWrite: ?});
            beatCount <= beatCount+1;
         endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
         let tile = tc.tile;
         killv[tile] <= !(tc.state == Running || tc.state == Stopped);
         stopv[tile] <= !(tc.state == Running);
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
         return DmaDbgRec{x:0, y:0, z:0, w:0};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
         return extend(beatCount);
      endmethod
   endinterface
endmodule

module mkMemWriteInternal#(MemServerIndication ind)
   (MemWriteInternal#(addrWidth, busWidth, numTags, numServers))
   provisos(Log#(busWidthBytes,beatShift)
            ,Div#(busWidth,8,busWidthBytes)
            ,Add#(beatShift, a__, 8)
            ,Add#(b__, TLog#(numTags), MemTagSize)
            ,Add#(beatShift, c__, BurstLenSize)
            ,Add#(d__, TDiv#(busWidth, 8), ByteEnableSize)
            );

   let verbose = False;

   // stopping/killing infra
   Vector#(4,Reg#(Bool)) killv <- replicateM(mkReg(False));
   Vector#(4,Reg#(Bool)) stopv <- replicateM(mkReg(False));

   // stage 0: address translation (latency = 1)
   FIFO#(LRec#(numServers,addrWidth,busWidth)) clientRequest <- mkFIFO;
   // stage 1: address validation (latency = 1)
   FIFO#(RRec#(numServers,addrWidth,busWidth)) serverRequest <- mkFIFO;
   // stage 2: write commands
   FIFO#(DRec#(numServers, addrWidth)) serverProcessing <- mkSizedFIFO(valueOf(numTags));
   // stage 3: write data
   BRAM2Port#(Bit#(TLog#(numTags)), RResp#(numServers,addrWidth)) respFifos <- mkBRAM2Server(defaultValue);
   TagGen#(numTags) tag_gen <- mkTagGen;
   FIFO#(RResp#(numServers,addrWidth)) clientResponse <- mkFIFO;

   Reg#(Bit#(BurstLenSize)) burstReg <- mkReg(0);
   Reg#(Bool)               firstReg <- mkReg(True);
   Reg#(Bool)               lastReg <- mkReg(False);
   Reg#(Bit#(BeatCountSize)) beatCount <- mkReg(0);
   let beat_shift = fromInteger(valueOf(beatShift));

   Reg#(Bit#(64)) cycle_cnt <- mkReg(0);
   Reg#(Bit#(64)) last_loadClient <- mkReg(0);
   Reg#(Bit#(64)) last_mmuResp <- mkReg(0);

   (* fire_when_enabled *)
   rule cycle;
      cycle_cnt <= cycle_cnt+1;
   endrule

   FIFO#(DmaError) dmaErrorFifo <- mkFIFO();
   rule dmaError;
      let error <- toGet(dmaErrorFifo).get();
      ind.error(extend(pack(error.errorType)), 0, 0);
   endrule

   rule checkMmuResp;
      let request <- toGet(clientRequest).get;
      let req = request.req;
      let client = request.client;
      let physAddr = req.addr;
      let rename_tag <- tag_gen.getTag;
      serverRequest.enq(RRec{req:req, pa:physAddr, client:client, rename_tag:extend(rename_tag)});
      //if (verbose) $display("mkMemWriteInternal::checkMmuResp: client=%d, rename_tag=%d", client,rename_tag);
      if (verbose) $display("mkMemWriteInternal::mmuResp %d %d", client, cycle_cnt-last_mmuResp);
      last_mmuResp <= cycle_cnt;
   endrule

   rule writeDoneComp0;
      let tag <- tag_gen.complete;
      respFifos.portB.request.put(BRAMRequest{write:False, address:tag, datain: ?, responseOnWrite: ?});
   endrule

   FIFO#(MemData#(busWidth)) memDataFifo <- mkFIFO();
   Vector#(numServers, FIFO#(MemData#(busWidth))) clientWriteData <- replicateM(mkFIFO);

   if(valueOf(numServers) > 0)
      rule memdata;
         let drq = serverProcessing.first;
         let req_tag = drq.req_tag;
         let req_burstLen = drq.req_burstLen;
         let rename_tag = drq.rename_tag;
         let client = drq.client;
         MemData#(busWidth) tagdata = unpack(0);
         if (killv[req_tag[5:4]] == False) begin
            tagdata = clientWriteData[client].first;
            clientWriteData[client].deq;
         end
         let burstLen = burstReg;
         let first    = firstReg;
         let last     = lastReg;
         if (first) begin
            burstLen = req_burstLen >> beat_shift;
            last     = serverProcessing.first.last;
            respFifos.portA.request.put(BRAMRequest{write:True,responseOnWrite:False, address:truncate(rename_tag), datain:RResp{orig_tag:req_tag, client:client}});
         end
         burstReg <= burstLen-1;
         firstReg <= (burstLen-1 == 0);
         lastReg  <= (burstLen-1 == 1);
         beatCount <= beatCount+1;
         if (last)
            serverProcessing.deq();
         //$display("mkMemWriteInternal::writeData: client=%d, rename_tag=%d", client, rename_tag);
         memDataFifo.enq(MemData { data: tagdata.data,  tag:extend(rename_tag), last: last });
      endrule

   rule fill_clientResponse;
      let rv <- respFifos.portB.response.get;
      clientResponse.enq(rv);
   endrule

   Vector#(numServers, PhysMemWriteServer#(addrWidth,busWidth)) sv = newVector;
   for(Integer i = 0; i < valueOf(numServers); i=i+1)
      sv[i] = (interface PhysMemWriteServer;
                  interface Put writeReq;
                     method Action put(PhysMemRequest#(addrWidth,busWidth) req);
                        if (verbose) $display("mkMemWriteInternal::loadClient %d %d", i, cycle_cnt-last_loadClient);
                        last_loadClient <= cycle_cnt;
                        if (stopv[req.tag[5:4]] == False) begin
                           clientRequest.enq(LRec{req:req, client:fromInteger(i)});
                        end
                     endmethod
                  endinterface
                  interface Put writeData = toPut(clientWriteData[i]);
                  interface Get writeDone;
                     method ActionValue#(Bit#(MemTagSize)) get if (clientResponse.first.client == fromInteger(i));
                        clientResponse.deq;
                        return clientResponse.first.orig_tag;
                     endmethod
                  endinterface
               endinterface);

   interface servers = sv;
   interface PhysMemWriteClient client;
      interface Get writeReq;
         method ActionValue#(PhysMemRequest#(addrWidth,busWidth)) get();
            let request <- toGet(serverRequest).get();
            let req = request.req;
            let physAddr = request.pa;
            let client = request.client;
            let rename_tag = request.rename_tag;
            serverProcessing.enq(DRec{req_tag:req.tag, req_burstLen: req.burstLen, client:client, rename_tag:rename_tag, last: (req.burstLen == fromInteger(valueOf(busWidthBytes))) });
            //$display("mkMemWriteInternal::writeReq: client=%d, rename_tag=%d", client,rename_tag);
            return PhysMemRequest{addr:physAddr, burstLen:req.burstLen, tag:extend(rename_tag)
`ifdef BYTE_ENABLES
                                  , firstbe: truncate(req.firstbe), lastbe: truncate(req.lastbe)
`endif
};
         endmethod
      endinterface
      interface Get writeData = toGet(memDataFifo);
      interface Put writeDone;
         method Action put(Bit#(MemTagSize) resp);
            tag_gen.returnTag(truncate(resp));
            if (verbose) $display("mkMemWriteInternal::writeDone: resp=%d", resp);
         endmethod
      endinterface
   endinterface
   interface Put tileControl;
      method Action put(TileControl tc);
         let tile = tc.tile;
         let kv = True;
         let sv = True;
         if (tc.state == Running || tc.state == Stopped)
            kv = False;
         if (tc.state == Running)
            sv = False;
         killv[tile] <= kv;
         stopv[tile] <= sv;
      endmethod
   endinterface
   interface DmaDbg dbg;
      method ActionValue#(DmaDbgRec) dbg();
         return DmaDbgRec{x:fromInteger(valueOf(numServers)), y:?, z:?, w:?};
      endmethod
      method ActionValue#(Bit#(64)) getMemoryTraffic();
         return extend(beatCount);
      endmethod
   endinterface
endmodule


match pipeline depth of C input

match pipeline depth of C input

import Clocks::*;

interface Dsp48E1;
   method Bit#(48) p();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action last(Bit#(1) v);
endinterface

(* always_ready, always_enabled *)
interface PRIM_DSP48E1;
   method Bit#(48) p();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action acin(Bit#(30) v);
   method Action bcin(Bit#(18) v);
   method Action carrycascin(Bit#(1) v);
   method Action carryin(Bit#(1) v);
   method Action multsignin(Bit#(1) v);
   method Action pcin(Bit#(48) v);

   method Action cea1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage AREG
   method Action cea2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage AREG
   method Action cead(Bit#(1) en);		// 1-bit input: Clock enable input for ADREG
   method Action ceb1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage BREG
   method Action ceb2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage BREG
   method Action cealumode(Bit#(1) en);		// 1-bit input: Clock enable input for ALUMODE
   method Action cec(Bit#(1) en);		// 1-bit input: Clock enable input for CREG
   method Action cecarryin(Bit#(1) en);		// 1-bit input: Clock enable input for CARRYINREG
   method Action cectrl(Bit#(1) en);		// 1-bit input: Clock enable input for OPMODEREG and CARRYINSELREG
   method Action ced(Bit#(1) en);		// 1-bit input: Clock enable input for DREG
   method Action ceinmode(Bit#(1) en);		// 1-bit input: Clock enable input for INMODEREG
   method Action cem(Bit#(1) en);		// 1-bit input: Clock enable input for MREG
   method Action cep(Bit#(1) en);		// 1-bit input: Clock enable input for PREG
endinterface

import "BVI" DSP48E1 =
module vmkDSP48E1(PRIM_DSP48E1);
   let currentReset <- exposeCurrentReset;
   let invertedReset <- mkResetInverter(currentReset);
   default_clock clk(CLK);

   default_reset rsta(RSTA) = invertedReset;
   input_reset rstb(RSTB) = invertedReset;
   input_reset rstc(RSTC) = invertedReset;
   input_reset rstd(RSTD) = invertedReset;
   input_reset rstallcarryin(RSTALLCARRYIN) = invertedReset;
   input_reset rstalumode(RSTALUMODE) = invertedReset;
   input_reset rstctrl(RSTCTRL) = invertedReset;
   input_reset rstinmode(RSTINMODE) = invertedReset;
   input_reset rstm(RSTM) = invertedReset;
   input_reset rstp(RSTP) = invertedReset;

   method P p();
   method alumode(ALUMODE) enable ((*inhigh*)EN_alumode);
   method carryinsel(CARRYINSEL) enable ((*inhigh*)EN_carryinsel);
   method inmode(INMODE) enable ((*inhigh*)EN_inmode);
   method opmode(OPMODE) enable ((*inhigh*)EN_opmode);
   method a(A) enable ((*inhigh*)EN_a);
   method b(B) enable ((*inhigh*)EN_b);
   method c(C) enable ((*inhigh*)EN_c);
   method d(D) enable ((*inhigh*)EN_d);
   method acin(ACIN) enable ((*inhigh*)EN_acin);
   method bcin(BCIN) enable ((*inhigh*)EN_bcin);
   method carrycascin(CARRYCASCIN) enable ((*inhigh*)EN_carrycascin);
   method carryin(CARRYIN) enable ((*inhigh*)EN_carryin);
   method multsignin(MULTSIGNIN) enable ((*inhigh*)EN_multsignin);
   method pcin(PCIN) enable ((*inhigh*)EN_pcin);

   method cea1(CEA1) enable ((*inhigh*)EN_cea1);
   method cea2(CEA2) enable ((*inhigh*)EN_cea2);
   method cead(CEAD) enable ((*inhigh*)EN_cead);
   method ceb1(CEB1) enable ((*inhigh*)EN_ceb1);
   method ceb2(CEB2) enable ((*inhigh*)EN_ceb2);
   method cealumode(CEALUMODE) enable ((*inhigh*)EN_cealumode);
   method cec(CEC) enable ((*inhigh*)EN_cec);
   method cecarryin(CECARRYIN) enable ((*inhigh*)EN_cecarryin);
   method cectrl(CECTRL) enable ((*inhigh*)EN_cectrl);
   method ced(CED) enable ((*inhigh*)EN_ced);
   method ceinmode(CEINMODE) enable ((*inhigh*)EN_ceinmode);
   method cem(CEM) enable ((*inhigh*)EN_cem);
   method cep(CEP) enable ((*inhigh*)EN_cep);
   schedule (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p)
      CF (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p);
endmodule

(* synthesize *)
module mkDsp48E1(Dsp48E1);
   let dsp <- vmkDSP48E1();
   let defaultReset <- exposeCurrentReset;
   let optionalReset = defaultReset; // noReset
   Wire#(Bit#(4)) alumodeWire <- mkDWire(0);
   Reg#(Bit#(4)) alumodeReg <- mkReg(0);
   Wire#(Bit#(3)) carryinselWire <- mkDWire(0);
   Wire#(Bit#(5)) inmodeWire <- mkDWire(0);
   Wire#(Bit#(7)) opmodeWire <- mkDWire(7'h35);
   Reg#(Bit#(7)) opmodeReg <- mkReg(7'h35);

   Wire#(Bit#(30)) aWire <- mkDWire(0);
   Wire#(Bit#(18)) bWire <- mkDWire(0);
   Wire#(Bit#(48)) cWire <- mkDWire(0);
   Wire#(Bit#(25)) dWire <- mkDWire(0);
   Reg#(Bit#(48))  c1Reg <- mkReg(0);
   Reg#(Bit#(48))  c2Reg <- mkReg(0);
   Reg#(Bit#(48))  c3Reg <- mkReg(0);

   Wire#(Bit#(1)) ce1Wire <- mkDWire(0);
   Reg#(Bit#(1)) ce2Reg <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1)) cepReg <- mkReg(0, reset_by optionalReset);
   Wire#(Bit#(1)) last1Wire <- mkDWire(0);
   Reg#(Bit#(1))  last2Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last3Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last4Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last5Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last6Reg  <- mkReg(0, reset_by optionalReset);

   rule clock_enable_and_reset;
      ce2Reg <= ce1Wire;
      cepReg <= ce2Reg;

      last2Reg <= last1Wire;
      last3Reg <= last2Reg;
      last4Reg <= last3Reg;
      last5Reg <= last4Reg;
      last6Reg <= last5Reg;

      dsp.cea1(1); // (ce1Wire);
      dsp.cea2(1); // (ce2Reg);
      dsp.cead(1);
      dsp.ceb1(1); // (ce1Wire);
      dsp.ceb2(1); // (ce2Reg);
      dsp.cealumode(1); // (ce1Wire);
      dsp.cec(1);
      dsp.cecarryin(1);
      dsp.cectrl(1);
      dsp.ced(1);
      dsp.ceinmode(1);
      dsp.cem(1);
      dsp.cep(1); // (cepReg);

   endrule

   rule driveInputs;
      opmodeReg <= opmodeWire;
      alumodeReg <= alumodeWire;

      c1Reg <= cWire;
      c2Reg <= c1Reg;
      c3Reg <= c2Reg;

      dsp.alumode(alumodeReg);
      dsp.carryinsel(carryinselWire);
      dsp.inmode(inmodeWire);
      dsp.opmode(opmodeReg);
      //dsp.a(aWire);
      //dsp.b(bWire);
      dsp.c(c3Reg);
      //dsp.d(dWire);

      dsp.acin(0);
      dsp.bcin(0);
      dsp.carrycascin(0);
      dsp.carryin(0);
      dsp.pcin(0);
   endrule

   method Action alumode(Bit#(4) v);
      alumodeWire <= v;
   endmethod
   method Action carryinsel(Bit#(3) v);
      carryinselWire <= v;
   endmethod
   method Action inmode(Bit#(5) v);
      inmodeWire <= v;
   endmethod
   method Action opmode(Bit#(7) v);
      opmodeWire <= v;
   endmethod
   method Action a(Bit#(30) v);
      ce1Wire <= 1;
      dsp.a(v);
   endmethod
   method Action b(Bit#(18) v);
      dsp.b(v);
   endmethod
   method Action c(Bit#(48) v);
      cWire <= v;
   endmethod
   method Action d(Bit#(25) v);
      dsp.d(v);
   endmethod
   method Bit#(48) p() if (last6Reg == 1);
      return dsp.p();
   endmethod
   method Action last(Bit#(1) v);
      last1Wire <= v;
   endmethod
endmodule

import Clocks::*;

interface Dsp48E1;
   method Bit#(48) p();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action last(Bit#(1) v);
endinterface

(* always_ready, always_enabled *)
interface PRIM_DSP48E1;
   method Bit#(48) p();
// Control: 4-bit (each) input: Control Inputs/Status Bits
   method Action alumode(Bit#(4) v);		// 4-bit input: ALU control input
   method Action carryinsel(Bit#(3) v);		// 3-bit input: Carry select input
   method Action inmode(Bit#(5) v);		// 5-bit input: INMODE control input
   method Action opmode(Bit#(7) v);		// 7-bit input: Operation mode input
   method Action a(Bit#(30) v);
   method Action b(Bit#(18) v);
   method Action c(Bit#(48) v);
   method Action d(Bit#(25) v);
   method Action acin(Bit#(30) v);
   method Action bcin(Bit#(18) v);
   method Action carrycascin(Bit#(1) v);
   method Action carryin(Bit#(1) v);
   method Action multsignin(Bit#(1) v);
   method Action pcin(Bit#(48) v);

   method Action cea1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage AREG
   method Action cea2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage AREG
   method Action cead(Bit#(1) en);		// 1-bit input: Clock enable input for ADREG
   method Action ceb1(Bit#(1) en);		// 1-bit input: Clock enable input for 1st stage BREG
   method Action ceb2(Bit#(1) en);		// 1-bit input: Clock enable input for 2nd stage BREG
   method Action cealumode(Bit#(1) en);		// 1-bit input: Clock enable input for ALUMODE
   method Action cec(Bit#(1) en);		// 1-bit input: Clock enable input for CREG
   method Action cecarryin(Bit#(1) en);		// 1-bit input: Clock enable input for CARRYINREG
   method Action cectrl(Bit#(1) en);		// 1-bit input: Clock enable input for OPMODEREG and CARRYINSELREG
   method Action ced(Bit#(1) en);		// 1-bit input: Clock enable input for DREG
   method Action ceinmode(Bit#(1) en);		// 1-bit input: Clock enable input for INMODEREG
   method Action cem(Bit#(1) en);		// 1-bit input: Clock enable input for MREG
   method Action cep(Bit#(1) en);		// 1-bit input: Clock enable input for PREG
endinterface

import "BVI" DSP48E1 =
module vmkDSP48E1(PRIM_DSP48E1);
   let currentReset <- exposeCurrentReset;
   let invertedReset <- mkResetInverter(currentReset);
   default_clock clk(CLK);

   default_reset rsta(RSTA) = invertedReset;
   input_reset rstb(RSTB) = invertedReset;
   input_reset rstc(RSTC) = invertedReset;
   input_reset rstd(RSTD) = invertedReset;
   input_reset rstallcarryin(RSTALLCARRYIN) = invertedReset;
   input_reset rstalumode(RSTALUMODE) = invertedReset;
   input_reset rstctrl(RSTCTRL) = invertedReset;
   input_reset rstinmode(RSTINMODE) = invertedReset;
   input_reset rstm(RSTM) = invertedReset;
   input_reset rstp(RSTP) = invertedReset;

   method P p();
   method alumode(ALUMODE) enable ((*inhigh*)EN_alumode);
   method carryinsel(CARRYINSEL) enable ((*inhigh*)EN_carryinsel);
   method inmode(INMODE) enable ((*inhigh*)EN_inmode);
   method opmode(OPMODE) enable ((*inhigh*)EN_opmode);
   method a(A) enable ((*inhigh*)EN_a);
   method b(B) enable ((*inhigh*)EN_b);
   method c(C) enable ((*inhigh*)EN_c);
   method d(D) enable ((*inhigh*)EN_d);
   method acin(ACIN) enable ((*inhigh*)EN_acin);
   method bcin(BCIN) enable ((*inhigh*)EN_bcin);
   method carrycascin(CARRYCASCIN) enable ((*inhigh*)EN_carrycascin);
   method carryin(CARRYIN) enable ((*inhigh*)EN_carryin);
   method multsignin(MULTSIGNIN) enable ((*inhigh*)EN_multsignin);
   method pcin(PCIN) enable ((*inhigh*)EN_pcin);

   method cea1(CEA1) enable ((*inhigh*)EN_cea1);
   method cea2(CEA2) enable ((*inhigh*)EN_cea2);
   method cead(CEAD) enable ((*inhigh*)EN_cead);
   method ceb1(CEB1) enable ((*inhigh*)EN_ceb1);
   method ceb2(CEB2) enable ((*inhigh*)EN_ceb2);
   method cealumode(CEALUMODE) enable ((*inhigh*)EN_cealumode);
   method cec(CEC) enable ((*inhigh*)EN_cec);
   method cecarryin(CECARRYIN) enable ((*inhigh*)EN_cecarryin);
   method cectrl(CECTRL) enable ((*inhigh*)EN_cectrl);
   method ced(CED) enable ((*inhigh*)EN_ced);
   method ceinmode(CEINMODE) enable ((*inhigh*)EN_ceinmode);
   method cem(CEM) enable ((*inhigh*)EN_cem);
   method cep(CEP) enable ((*inhigh*)EN_cep);
   schedule (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p)
      CF (alumode,carryinsel,inmode,opmode,a,b,c,d,acin,bcin,carrycascin,carryin,multsignin,pcin,cea1,cea2,cead,ceb1,ceb2,cealumode,cec,cecarryin,cectrl,ced,ceinmode,cem,cep,p);
endmodule

(* synthesize *)
module mkDsp48E1(Dsp48E1);
   let dsp <- vmkDSP48E1();
   let defaultReset <- exposeCurrentReset;
   let optionalReset = defaultReset; // noReset
   Wire#(Bit#(4)) alumodeWire <- mkDWire(0);
   Reg#(Bit#(4)) alumodeReg <- mkReg(0);
   Wire#(Bit#(3)) carryinselWire <- mkDWire(0);
   Wire#(Bit#(5)) inmodeWire <- mkDWire(0);
   Wire#(Bit#(7)) opmodeWire <- mkDWire(7'h35);
   Reg#(Bit#(7)) opmodeReg <- mkReg(7'h35);

   Wire#(Bit#(30)) aWire <- mkDWire(0);
   Wire#(Bit#(18)) bWire <- mkDWire(0);
   Wire#(Bit#(48)) cWire <- mkDWire(0);
   Wire#(Bit#(25)) dWire <- mkDWire(0);

   Wire#(Bit#(1)) ce1Wire <- mkDWire(0);
   Reg#(Bit#(1)) ce2Reg <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1)) cepReg <- mkReg(0, reset_by optionalReset);
   Wire#(Bit#(1)) last1Wire <- mkDWire(0);
   Reg#(Bit#(1))  last2Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last3Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last4Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last5Reg  <- mkReg(0, reset_by optionalReset);
   Reg#(Bit#(1))  last6Reg  <- mkReg(0, reset_by optionalReset);

   rule clock_enable_and_reset;
      ce2Reg <= ce1Wire;
      cepReg <= ce2Reg;

      last2Reg <= last1Wire;
      last3Reg <= last2Reg;
      last4Reg <= last3Reg;
      last5Reg <= last4Reg;
      last6Reg <= last5Reg;

      dsp.cea1(1); // (ce1Wire);
      dsp.cea2(1); // (ce2Reg);
      dsp.cead(1);
      dsp.ceb1(1); // (ce1Wire);
      dsp.ceb2(1); // (ce2Reg);
      dsp.cealumode(1); // (ce1Wire);
      dsp.cec(1);
      dsp.cecarryin(1);
      dsp.cectrl(1);
      dsp.ced(1);
      dsp.ceinmode(1);
      dsp.cem(1);
      dsp.cep(1); // (cepReg);

   endrule

   rule driveInputs;
      opmodeReg <= opmodeWire;
      alumodeReg <= alumodeWire;

      dsp.alumode(alumodeReg);
      dsp.carryinsel(carryinselWire);
      dsp.inmode(inmodeWire);
      dsp.opmode(opmodeReg);
      //dsp.a(aWire);
      //dsp.b(bWire);
      //dsp.c(cWire);
      //dsp.d(dWire);

      dsp.acin(0);
      dsp.bcin(0);
      dsp.carrycascin(0);
      dsp.carryin(0);
      dsp.pcin(0);
   endrule

   method Action alumode(Bit#(4) v);
      alumodeWire <= v;
   endmethod
   method Action carryinsel(Bit#(3) v);
      carryinselWire <= v;
   endmethod
   method Action inmode(Bit#(5) v);
      inmodeWire <= v;
   endmethod
   method Action opmode(Bit#(7) v);
      opmodeWire <= v;
   endmethod
   method Action a(Bit#(30) v);
      ce1Wire <= 1;
      dsp.a(v);
   endmethod
   method Action b(Bit#(18) v);
      dsp.b(v);
   endmethod
   method Action c(Bit#(48) v);
      dsp.c(v);
   endmethod
   method Action d(Bit#(25) v);
      dsp.d(v);
   endmethod
   method Bit#(48) p() if (last6Reg == 1);
      return dsp.p();
   endmethod
   method Action last(Bit#(1) v);
      last1Wire <= v;
   endmethod
endmodule


moved shift into deq() method of mkAdapterToBus

// Copyright (c) 2012 MIT
// Copyright (c) 2012 Nokia, 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 GetPut         ::*;
import FIFOF          ::*;
import SpecialFIFOs   ::*;
import StmtFSM        ::*;
import Assert         ::*;
import Pipe           ::*;

function Bit#(a) rtruncate(Bit#(b) x) provisos(Add#(k,a,b));
   match {.v,.*} = split(x);
   return v;
endfunction

interface AdapterToBus#(numeric type n, type a);
   interface PipeIn#(a) in;
   interface PipeOut#(Bit#(n)) out;
endinterface

interface AdapterFromBus#(numeric type n, type a);
   interface PipeIn#(Bit#(n)) in;
   interface PipeOut#(a) out;
endinterface

module mkAdapterToBus(AdapterToBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1, z, asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(TLog#(nwords)) max  = fromInteger(valueOf(nwords) - 1);
   Bit#(paddingsz) padding = 0;

   Reg#(Bool) notEmptyReg <- mkReg(False);
   Reg#(Bit#(aszn)) bits <- mkReg(0);
   Reg#(Bit#(TLog#(nwords)))   count <- mkReg(0);
   Reg#(Bit#(TAdd#(TLog#(asz),1)))   shift <- mkReg(0);

   interface PipeIn in;
      method Action enq(a val) if (!notEmptyReg);
         bits <= {padding,pack(val)};
	 notEmptyReg <= True;
      endmethod
      method notFull = !notEmptyReg;
   endinterface
   interface PipeOut out;
      method Bit#(n) first() if (notEmptyReg);
         return rtruncate(bits);
      endmethod
      method Action deq() if (notEmptyReg);
         if (count == max)
            begin
               count <= 0;
	       notEmptyReg <= False;
            end
         else
            begin
               count <= count + 1;
	       shift <= shift + fromInteger(valueOf(n));
	       bits <= (bits << valueOf(n));
            end
      endmethod
      method notEmpty = notEmptyReg;
   endinterface
endmodule

module mkAdapterFromBus(AdapterFromBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1,z,asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(TLog#(nwords)) max    = fromInteger(valueOf(nwords)-1);

   Reg#(Bit#(aszn)) fbnbuff <- mkReg(0);
   Reg#(Bit#(TLog#(nwords)))    count <- mkReg(0);
   FIFOF#(Bit#(asz)) fifo <- mkFIFOF1;

   interface PipeIn in;
      method Action enq(Bit#(n) x) if (count < max || fifo.notFull);
         Bit#(aszn) newbuff = truncate({fbnbuff,x});
         fbnbuff <= newbuff;
         if (count == max)
            begin
               count <= 0;
               fifo.enq(truncate(newbuff));
            end
         else
            begin
               count <= count+1;
            end
      endmethod
      method notFull = fifo.notFull;
   endinterface
   interface PipeOut out;
      method first = unpack(fifo.first);
      method deq = fifo.deq;
      method notEmpty = fifo.notEmpty;
   endinterface
endmodule

interface AdapterIndication;
   method Action done();
endinterface

interface AdapterTb;
   method Action start();
endinterface

module mkAdapterTb#(AdapterIndication indication)(AdapterTb);
   AdapterToBus#(32,Bit#(72)) tb32_72 <- mkAdapterToBus();
   AdapterToBus#(32,Bit#(17)) tb32_17 <- mkAdapterToBus();
   AdapterFromBus#(32,Bit#(72)) fb32_72 <- mkAdapterFromBus();
   AdapterFromBus#(32,Bit#(17)) fb32_17 <- mkAdapterFromBus();

   Reg#(Bit#(10)) timer <- mkReg(0);
   rule timeout;
       timer <= timer+1;
       dynamicAssert(timer < 128, "Timeout");
   endrule

   let fsm <- mkFSM(
      seq
       // test to bit-32
       tb32_72.in.enq(72'h090807060504030201);
       dynamicAssert(tb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!tb32_72.in.notFull, "Adapter full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       $display("tb32_72 word 0 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h00000009, "expecting 00000009");
       tb32_72.out.deq;
       $display("tb32_72 word 1 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h08070605, "expecting 08070605");
       tb32_72.out.deq;
       $display("tb32_72 word 2 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h04030201, "expecting 04030201");
       tb32_72.out.deq;
       dynamicAssert(!tb32_72.out.notEmpty && tb32_72.in.notFull, "Adapter empty and not full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");
       tb32_17.in.enq(17'h10203);
       dynamicAssert(tb32_17.out.notEmpty, "tb32_17 not empty");
       dynamicAssert(!tb32_17.in.notFull, "tb32_17 full");
       $display("tb32_17.out.first %h", tb32_17.out.first);
       dynamicAssert(tb32_17.out.first == (32'h00010203), "Expected 00010203");
       tb32_17.out.deq;
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");

       //test from bit-32
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       fb32_72.in.enq(32'h00000009);
       fb32_72.in.enq(32'h08070605);
       fb32_72.in.enq(32'h04030201);
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;
       fb32_72.in.enq(32'h09080706);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_72.in.enq(32'h05040302);
       fb32_72.in.enq(32'h01000000);
       dynamicAssert(fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_72.in.notFull, "Adapter full");
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h060504030201000000, "Expected 060504030201000000");
       fb32_72.out.deq;
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_17.in.enq(32'h10203);
       dynamicAssert(fb32_17.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_17.in.notFull, "Adapter full");
       $display("fb32_17.out.first %h", fb32_17.out.first);
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;
       dynamicAssert(!fb32_17.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_17.in.notFull, "Adapter not full");

       // they should be duals
       tb32_72.in.enq(72'h090807060504030201);
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;

       tb32_17.in.enq(17'h10203);
       fb32_17.in.enq(tb32_17.out.first);
       tb32_17.out.deq;
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;

       indication.done();
   endseq
   );

   method Action start();
       fsm.start();
   endmethod
endmodule

// Copyright (c) 2012 MIT
// Copyright (c) 2012 Nokia, 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 GetPut         ::*;
import FIFOF          ::*;
import SpecialFIFOs   ::*;
import StmtFSM        ::*;
import Assert         ::*;
import Pipe           ::*;

function Bit#(a) rtruncate(Bit#(b) x) provisos(Add#(k,a,b));
   match {.v,.*} = split(x);
   return v;
endfunction

interface AdapterToBus#(numeric type n, type a);
   interface PipeIn#(a) in;
   interface PipeOut#(Bit#(n)) out;
endinterface

interface AdapterFromBus#(numeric type n, type a);
   interface PipeIn#(Bit#(n)) in;
   interface PipeOut#(a) out;
endinterface

module mkAdapterToBus(AdapterToBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1, z, asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(TLog#(nwords)) max  = fromInteger(valueOf(nwords) - 1);
   Bit#(paddingsz) padding = 0;

   FIFOF#(Bit#(aszn)) fifo <- mkFIFOF1();
   Reg#(Bit#(TLog#(nwords)))   count <- mkReg(0);
   Reg#(Bit#(TAdd#(TLog#(asz),1)))   shift <- mkReg(0);

   interface PipeIn in;
      method Action enq(a val);
         fifo.enq({padding,pack(val)});
      endmethod
      method notFull = fifo.notFull;
   endinterface
   interface PipeOut out;
      method Bit#(n) first() if (fifo.notEmpty);
         return rtruncate(fifo.first << shift);
      endmethod
      method Action deq() if (fifo.notEmpty);
         if (count == max)
            begin
               count <= 0;
	       shift <= 0;
               fifo.deq;
            end
         else
            begin
               count <= count + 1;
	       shift <= shift + fromInteger(valueOf(n));
            end
      endmethod
      method notEmpty = fifo.notEmpty;
   endinterface
endmodule

module mkAdapterFromBus(AdapterFromBus#(n,a))
   provisos(Bits#(a,asz),
            Add#(1,z,asz),
            Div#(asz,n,nwords),
            Mul#(n,nwords,aszn),
            Add#(n,a__,aszn),
            Add#(asz,paddingsz,aszn));

   Bit#(TLog#(nwords)) max    = fromInteger(valueOf(nwords)-1);

   Reg#(Bit#(aszn)) fbnbuff <- mkReg(0);
   Reg#(Bit#(TLog#(nwords)))    count <- mkReg(0);
   FIFOF#(Bit#(asz)) fifo <- mkFIFOF1;

   interface PipeIn in;
      method Action enq(Bit#(n) x) if (count < max || fifo.notFull);
         Bit#(aszn) newbuff = truncate({fbnbuff,x});
         fbnbuff <= newbuff;
         if (count == max)
            begin
               count <= 0;
               fifo.enq(truncate(newbuff));
            end
         else
            begin
               count <= count+1;
            end
      endmethod
      method notFull = fifo.notFull;
   endinterface
   interface PipeOut out;
      method first = unpack(fifo.first);
      method deq = fifo.deq;
      method notEmpty = fifo.notEmpty;
   endinterface
endmodule

interface AdapterIndication;
   method Action done();
endinterface

interface AdapterTb;
   method Action start();
endinterface

module mkAdapterTb#(AdapterIndication indication)(AdapterTb);
   AdapterToBus#(32,Bit#(72)) tb32_72 <- mkAdapterToBus();
   AdapterToBus#(32,Bit#(17)) tb32_17 <- mkAdapterToBus();
   AdapterFromBus#(32,Bit#(72)) fb32_72 <- mkAdapterFromBus();
   AdapterFromBus#(32,Bit#(17)) fb32_17 <- mkAdapterFromBus();

   Reg#(Bit#(10)) timer <- mkReg(0);
   rule timeout;
       timer <= timer+1;
       dynamicAssert(timer < 128, "Timeout");
   endrule

   let fsm <- mkFSM(
      seq
       // test to bit-32
       tb32_72.in.enq(72'h090807060504030201);
       dynamicAssert(tb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!tb32_72.in.notFull, "Adapter full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       $display("tb32_72 word 0 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h00000009, "expecting 00000009");
       tb32_72.out.deq;
       $display("tb32_72 word 1 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h08070605, "expecting 08070605");
       tb32_72.out.deq;
       $display("tb32_72 word 2 %h", tb32_72.out.first());
       dynamicAssert(tb32_72.out.first == 32'h04030201, "expecting 04030201");
       tb32_72.out.deq;
       dynamicAssert(!tb32_72.out.notEmpty && tb32_72.in.notFull, "Adapter empty and not full");
       $display("tb32_72 notEmpty %d notFull %d", tb32_72.out.notEmpty, tb32_72.in.notFull);
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");
       tb32_17.in.enq(17'h10203);
       dynamicAssert(tb32_17.out.notEmpty, "tb32_17 not empty");
       dynamicAssert(!tb32_17.in.notFull, "tb32_17 full");
       $display("tb32_17.out.first %h", tb32_17.out.first);
       dynamicAssert(tb32_17.out.first == (32'h00010203), "Expected 00010203");
       tb32_17.out.deq;
       dynamicAssert(!tb32_17.out.notEmpty, "tb32_17 empty");
       dynamicAssert(tb32_17.in.notFull, "tb32_17 !full");

       //test from bit-32
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       fb32_72.in.enq(32'h00000009);
       fb32_72.in.enq(32'h08070605);
       fb32_72.in.enq(32'h04030201);
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;
       fb32_72.in.enq(32'h09080706);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_72.in.enq(32'h05040302);
       fb32_72.in.enq(32'h01000000);
       dynamicAssert(fb32_72.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_72.in.notFull, "Adapter full");
       $display("fb32_72.out.first %h", fb32_72.out.first);
       dynamicAssert(fb32_72.out.first == 72'h060504030201000000, "Expected 060504030201000000");
       fb32_72.out.deq;
       $display("fb32_72 notEmpty %d notFull %d", fb32_72.out.notEmpty, fb32_72.in.notFull);
       dynamicAssert(!fb32_72.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_72.in.notFull, "Adapter not full");
       fb32_17.in.enq(32'h10203);
       dynamicAssert(fb32_17.out.notEmpty, "Adapter not empty");
       dynamicAssert(!fb32_17.in.notFull, "Adapter full");
       $display("fb32_17.out.first %h", fb32_17.out.first);
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;
       dynamicAssert(!fb32_17.out.notEmpty, "Adapter empty");
       dynamicAssert(fb32_17.in.notFull, "Adapter not full");

       // they should be duals
       tb32_72.in.enq(72'h090807060504030201);
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       fb32_72.in.enq(tb32_72.out.first);
       tb32_72.out.deq;
       dynamicAssert(fb32_72.out.first == 72'h090807060504030201, "Expected 090807060504030201");
       fb32_72.out.deq;

       tb32_17.in.enq(17'h10203);
       fb32_17.in.enq(tb32_17.out.first);
       tb32_17.out.deq;
       dynamicAssert(fb32_17.out.first == 17'h10203, "Expected 10203");
       fb32_17.out.deq;

       indication.done();
   endseq
   );

   method Action start();
       fsm.start();
   endmethod
endmodule